This guide shows you how to build the payment form for Klarna's Hosted Checkout integration. You'll learn to display Klarna payment methods dynamically, handle customer interactions, and implement the payment button with proper callbacks for seamless customer-initiated Payment Authorization.
Display one or multiple Klarna payment methods in your checkout and let customers select one to complete their purchase. This guide shows you how to integrate Klarna payment methods using the Klarna web SDK.
What you'll build:
Before building the payment form, ensure you have:
The integration process consists of the following key steps:
Update the Partner-facing API to collect the following data points from the Partner for customer-initiated payment scenarios:
| Parameter | Required (Acquiring Partner) | Required (Partner) | Description |
|---|---|---|---|
amount | Yes | Yes | Total amount of the authorization, including tax and any available discounts. |
currency | Yes | Yes | Currency in ISO 4217 format. |
supplementary_purchase_data | Yes | Recommended | Additional details about the transaction to help reduce fraud risk and enhance transparency. Include this data to improve underwriting, fraud detection, and customer communication. Klarna processes and uses this data for fraud assessment and customer experience optimization. |
supplementary_purchase_data.purchase_reference | Yes | Recommended | Customer-facing payment number displayed to customers on the Klarna app and other communications. Also included in settlement reports for reconciliation purposes. If you are an Acquiring Partner, this is the reference your Partner generated for their customer payment. |
supplementary_purchase_data.line_items | Yes | Recommended | Detailed line item information of the purchase. |
supplementary_purchase_data.customer | Yes | Recommended | Information about the customer which can be shared by the Partner. These data points may be used by Klarna to simplify sign-up and during fraud assessment, as well as for underwriting purposes to provide an enhanced experience to returning customers. |
supplementary_purchase_data.shipping | Yes | Recommended | Shipping information for the purchase. If the purchase contains multiple shipments with different recipients, provide one shipping object per shipment. |
klarna_network_session_token | Yes | Conditional | Encodes Klarna Network Session Token context (prequalification, sign-in state, or approval). Required for finalization after customer authorization; optional on initial request. |
klarna_network_data | Yes | Recommended | Additional data to enable custom features or data exchange supported by your Integrating Partner. Klarna accepts this passthrough field in a structured JSON format and forwards it to relevant systems for interoperability. Data shared in this field may complement structured datapoints provided in supplementary_purchase_data. Treat this value as an opaque string; do not validate or infer its structure. |
return_url | Yes | Conditional | Payment flow redirection URL. The customer will always be redirected to this URL on successful authorization. For web SDK with REDIRECT mode, the customer will also be redirected to this URL on failed authorization. Recommended for web flows. |
app_return_url | Yes | Conditional | Mobile application return URL (app scheme with no action deeplink). The customer will be redirected to this URL after third-party redirects or redirects to the Klarna Application. It is expected to open the integrating mobile application in its last state (no state changes or deeplink navigations). Recommended for mobile app flows. |
Requirements
klarna_network_session_token and klarna_network_data in the Partner-facing API to ensure Partners can easily identify and use them.supplementary_purchase_data when calling KlarnaMap your existing Partner-facing fields into supplementary_purchase_data when calling Klarna:
Line items: supplementary_purchase_data.line_items
Customer details: supplementary_purchase_data.customer
Shipping information: supplementary_purchase_data.shipping
Payment reference: supplementary_purchase_data.purchase_reference
Add new Partner-facing fields "just for Klarna" if you already have equivalents:
Don't introduce parallel structures like items and klarna_line_items
Don't force Partners to submit the same data twice
The two structures will diverge over time, causing maintenance issues
Supplementary purchase data scenarios
Acquiring Partners may receive supplementary purchase data (including line items, L2/L3 data for Card Network optimization, and payment context) in one or both of the following ways:
klarna_network_data: Forward as received without parsing or mappingsupplementary_purchase_data object when calling authorizePaymentBefore presenting the payment form, if a Klarna Network Session Token (klarna_network_session_token) was shared by the Partner, the Acquiring Partner must check if Klarna Payment Authorization can be fast-tracked. This typically happens when the Partner implements Klarna Conversion features such as Klarna Express Checkout and the customer has authorized the transaction.
Acquiring configuration for multi-payment-account Partners
If you are an Acquiring Partner with multiple Payment Accounts, include the acquiring_config query parameter to specify which Payment Account to use. For Partners with a single Payment Account, omitting acquiring_config is allowed — Klarna automatically uses the only available Payment Account.
Provide one of the following combinations — not both:
acquiring_config[payment_acquiring_account_id] + acquiring_config[payment_account_reference]acquiring_config[payment_account_id]curl -G 'https://api-global.test.klarna.com/v2/accounts/{partner_account_id}/payment/presentation' \
--header 'Authorization: Basic <API key>' \
--data-urlencode 'locale=en-US' \
--header 'Klarna-Network-Session-Token: krn:network:us1:test:session-token:eyJhbGciOiJIU[...]' \
--data-urlencode 'amount=11836' \
--data-urlencode 'currency=USD' \
--data-urlencode 'intent=PAY'The PaymentPresentation interface provides the full Klarna branding package and instructions tailored to the customer's purchase. However, at this step, the only relevant information is payment_status.
| Payment status | Description | Next step |
|---|---|---|
REQUIRES_CUSTOMER_ACTION | Further customer interaction is required, the payment selector should be displayed. | Continue to Step 3 to initialize the Web SDK and build the payment form. |
PENDING_PARTNER_AUTHORIZATION | Klarna recommends Acquiring Partners to authorize the Payment Transaction immediately by calling the Payment Authorize API and redirect the customer to the payment confirmation page. If such fast-track scenario is not technically supported by the Acquiring Partner, the payment selector should instead be displayed. | For detailed implementation guidance, see the Payment Authorization Guidelines. If authorization succeeds, redirect the customer to the confirmation page. If authorization fails, continue to Step 3 to display the payment form and allow the customer to complete the payment. |
{
...
"payment_status": "PENDING_PARTNER_AUTHORIZATION",
...
}When Klarna Payment Authorization was not fast-tracked, forward the Klarna Network Session Token (klarna_network_session_token) to the frontend and initialize the Klarna web SDK to display Klarna payment methods in your checkout.
This step is only applicable if you have a Customer Token (customer_token) acquired through the Payment Tokenization process.
Call [ generateKlarnaNetworkSessionToken] with the Customer Token in the Klarna-Customer-Token header. If the Partner has already provided a Klarna Network Session Token (for example, from an earlier browsing session), include it in the Klarna-Network-Session-Token header as well. When both headers are provided, Klarna attaches the customer token to the existing session instead of creating a new one, enabling a seamless transition from anonymous to authenticated context within the same shopping session.
Pass the returned Klarna Network Session Token to the Web SDK during initialization.
curl -X POST https://api-global.test.klarna.com/v2/accounts/{partner_account_id}/network/session/tokens \
-H 'Authorization: Basic <API key>' \
-H 'Klarna-Customer-Token: krn:partner:us1:test:identity:customer-token:vVQGmYzlfsQ16dko3[...]' \
-H 'Klarna-Network-Session-Token: krn:network:us1:test:session-token:eyJhbGciOiJIU[...]' # optional, include if available{
"klarna_network_session_token": "krn:network:us1:test:session-token:eyJhbGciOiJIU[...]"
}For tokenization scenarios, use the klarna_network_session_token generated via generateKlarnaNetworkSessionToken to initialize the web SDK on the next step instead of the network session token provided by the Partner.
The Klarna web SDK (klarna.mjs) follows the JavaScript module approach and should be included in places where you need to have a reference to the SDK such as while rendering any components or initiating a payment flow.
| Parameter | Description |
|---|---|
clientId | A credential that identifies the Acquiring Partner (obtained via Klarna's Credentials API). It is shared across all integrated Partners. To ensure the credential functions properly, make sure to register all domains where the Web SDK will be used. |
products | An array used to specify which products should be loaded to optimize performance by limiting the amount of data downloaded. If the PAYMENT product is included, only the Klarna.Payment package will be loaded. If the products array is omitted, all available packages will be loaded by default. |
partnerAccountId | A unique identifier for the specific Partner onboarding under the Acquiring Partner. |
klarnaNetworkSessionToken | The Klarna Network Session Token (klarna_network_session_token) that enables restoring the customer's state securely on the client. Pass this token directly when initializing the SDK. |
locale | Optional, language and region code (for example, en-US). If omitted, Klarna may default based on the customer's browser settings. |
For the full API specifications, refer to Klarna web SDK.
<script type="module">
try {
const {
KlarnaSDK
} = await import("https://js.klarna.com/web-sdk/v2/klarna.mjs")
const klarna = await KlarnaSDK({
clientId: "klarna_test_client_***",
products: ["PAYMENT"],
partnerAccountId: "krn:partner:global:account:test:***",
klarnaNetworkSessionToken: "[klarna_network_session_token]", // retrieved from server or received from Partner
locale: "en-US" // optional but recommended
});If the domain is not registered, subsequent method calls will result in an error.
Load the Web SDK from https://js.klarna.com/web-sdk/v2/klarna.mjs to remain compliant.
Keep the SDK in the top level (1st party) browsing context.
Specify products for performance.
Disclose Web SDK tracking in your site's notices. Learn more here.
Don't include the Web SDK in a bundle or host it yourself.
Don't load the Web SDK inside an iframe.
Don't omit products.
Don't use the Web SDK without disclosing tracking technologies.
After initializing the Web SDK, request Klarna's Payment Presentation to retrieve the visual assets, localized text, and display instructions needed to render Klarna as a payment method. The Web SDK dynamically adapts the presentation based on the customer's context, ensuring a consistent experience across different checkout states.
The process involves:
initiate callback to authorize the Payment Transaction when the customer clicks the button![]() | ![]() | ![]() | ![]() |
| One payment method without preselection | One payment method selected | Saved payment method available and selected | Pick Plan option selected |
Klarna Payment Presentation provides all the visual assets, localized texts, and instructions needed to correctly display Klarna in your checkout form.
Use the initialized SDK instance to call the Klarna.Payment.presentation() method.
Basic checkout context parameters must be provided:
| Parameter | Required | Description |
|---|---|---|
amount | Yes | The transaction amount in minor units following ISO 4217 exponents (for example, $118.00 = 11800, 1400 = 1400). This field is required if the intent is set to PAY, SUBSCRIBE, or DONATE; otherwise, it is optional. |
currency | Yes | Three-letter ISO 4217 currency code (for example, USD, EUR). |
locale | No | Locale code to localize texts and formats (for example, en-US, de-DE). If you don't set this, it will automatically use the value chosen when you first set up the Web SDK. If that's not available, it will use your browser's settings instead. |
intent | No | Specify the intent of the checkout flow: PAY, SUBSCRIBE, SIGNUP, SIGNIN, DONATE, ADD_TO_WALLET. If omitted, intent defaults to "PAY". |
For the full API specifications, refer to Klarna web SDK.
Performance optimization It is important to ensure that Klarna is displayed at roughly the same time as other payment methods, with an acceptable delay of less than 100 ms. To achieve this, begin initializing the Klarna web SDK and invoke the Payment Presentation method concurrently while loading the list of all enabled payment methods from your server.
Refresh Payment Presentation when the total amount changes.
The assets returned by klarna.Payment.presentation() (instalment amounts, messaging, and links) are tied to the amount you pass in the call.
If the customer changes the basket or final amount after Klarna is already displayed you must call klarna.Payment.presentation() again with the updated amount and re-render the Klarna payment method with the new response.
Displaying presentation from an older total can show incorrect instalment amounts and mislead customers.
Sample code
const paymentPresentation = await klarna.Payment.presentation({
amount: 11800,
currency: "USD",
locale: "en-US",
intent: "PAY"
});The PaymentPresentation interface provides the full Klarna branding package and instructions tailored to the customer's purchase:
| Parameter | Required | Purpose |
|---|---|---|
instruction | Yes | Specifies how Klarna as a payment option(s) should be displayed (for example, whether to show, preselect, or display as show-only). Adhering to these Payment Presentation instructions ensures customers have the best possible experience and optimizes conversion rates. |
paymentOption | No | Defines the default payment option applicable to all purchase types. This object includes the visual elements required to represent Klarna during checkout. |
savedPaymentOption | No | Defines the customer's saved payment option, available when a Customer Token (customer_token) is used. This object includes the same visual elements as paymentOption for displaying Klarna. When present, prioritize displaying this option to provide the best customer experience. |
paymentOption and savedPaymentOption share a similar object structure:
| Parameter | Required | Description |
|---|---|---|
paymentOptionId | Yes | The identifier of the payment option. The value is required to be sent to the Payment Authorize API or the Payment Request API when initiating the payment. |
icon | Yes | Klarna badge/logo suitable for checkout forms. |
header | Yes | The main descriptor that introduces Klarna in the payment form. The value will be dynamically adjusted based on the locale provided. |
subheader | Yes | The descriptor subheader which must be loaded inline below the main descriptor header. Short and enriched descriptive texts. Provides transparency on available options like installments, pay later, etc. |
message | No | Enriched tailored description with link. |
badge | No | Badge used for saved options or promotions. |
terms | No | Defines terms/disclosures potentially with links. |
paymentButton | Yes | Payment button that starts the Klarna Purchase Journey. |
For the full API specifications, refer to Klarna web SDK.
Apply Klarna's Payment Presentation instructions to control how Klarna appears in your checkout. Following these instructions ensures consistent customer experiences and enables features like Klarna Express Checkout and Sign in with Klarna.
Your implementation must handle both paymentOption (default) and savedPaymentOption (customer-specific). Prioritize savedPaymentOption when both are present.
The instruction attribute indicates how Klarna should be displayed:
| Instruction | Description |
|---|---|
SHOW_KLARNA | Display Klarna alongside other payment methods. |
PRESELECT_KLARNA | Display Klarna pre-selected alongside other payment methods. Returned when the customer has signed in with Klarna or has a saved payment option. |
SHOW_ONLY_KLARNA | Display Klarna as the only payment method. Returned after the customer completes the first step of Klarna Express Checkout. |
HIDE_KLARNA | Hide Klarna from payment methods. Returned when the Partner's access has been revoked. |
For full API specifications, see Klarna web SDK.
The following examples show how to apply each instruction. Your implementation must prioritize savedPaymentOption over paymentOption when both are available:
| Show Klarna | Preselect Klarna | Show only Klarna | Hide Klarna | |
|---|---|---|---|---|
| Without saved payment method | ![]() | ![]() | ![]() | ![]() |
| With saved payment method | ![]() | ![]() | ![]() | ![]() |
The presentation instructions are derived from possible customer Purchase Journeys described in the following article.
Sample code:
function renderKlarna(paymentPresentation) {
if (!paymentPresentation) return;
const root = qs("#klarna-payment-method");
if (!root) {
console.error("Missing #klarna-payment-method container.");
return;
}
// Create containers for both saved and default payment options
root.innerHTML = ` <div id="klarna-option-saved" class="klarna-option saved" style="display:none;">
</div>Once an instance of PaymentPresentation is created, the Klarna payment method(s) must be rendered dynamically in the payment selector according to Klarna's presentation guidelines. The following diagram displays different visual components and how they are rendered in different selection states:

Mount the Klarna payment method components within your designated Klarna payment method to render them dynamically in the payment form. When defining the layout, allocate sufficient space for all components and choose the appropriate variants to match your payment form structure. The message component must always occupy a full row to ensure legibility, positioned directly beneath the header, sub-header, and logo, as illustrated above.
Ensure that all components including those not immediately visible are mounted during initialization, and manage their visibility through your own logic or UI controls.
function renderKlarnaOption(containerId, option) {
const container = qs(`#${containerId}`);
if (!container) {
console.error(`Missing #${containerId} container.`);
return;
}
const ids = {
icon: `${containerId}-icon`,
header: `${containerId}-header`,
subhdr: `${containerId}-subheader`,
badge: `${containerId}-badge`,When a Klarna payment method is selected/deselected, ensure the additional visual components are shown/hidden properly.
/**
- Toggle the Klarna payment method selected state.
- Use for both SDK preselection (PRESELECT_KLARNA) and customer interactions.
*/
function toggleKlarnaPaymentOptionSelection(containerId, isSelected) {
const container = qs(`#${containerId}`);
if (!container) {
console.error(`Missing container #${containerId}.`);
return;
}
const display = isSelected ? "block" : "none";initiate callbackThe Payment Presentation instance allows you to mount the prebuilt button component. The Klarna Payment Button is context-aware and dynamically adapts to your configuration. Choose the theme and shape of the payment button to best fit into your online store in a way that complements your brand and encourages customer engagement. More details on the button styling can be found here.

The paymentButton.component() can be configured with the following set of parameters:
| Parameter | Required | Description |
|---|---|---|
id | No | Sets a custom DOM ID on the rendered button. Useful for testing or styling. |
shape | No | Defines the button's shape. Possible values are:default, pill, rect |
theme | No | Sets the visual theme of the button. Possible values are: default, light, dark, outlined |
locale | No | Sets the language and region (for example, en-US). If you don't set this, it will automatically use the value chosen when you first set up the Web SDK. If that's not available, it will use your browser's settings instead. |
disabled | No | Disables the button when set to true. Useful during form validation or async actions. |
loading | No | Forces the button into a loading state. Useful when awaiting async setup or validation. |
intents | No | Sets the purpose of the payment. Used to personalize the button and flow if not set when creating the PaymentPresentation instance. |
initiate | Yes | Function that returns a Promise resolving to either a PaymentRequestData, a paymentRequestId, or a returnUrl. This will be handled differently depending on the integration path. |
initiationMode | No | Defines how Klarna launches the Purchase Journey. |
For the full API specifications, refer to Klarna web SDK.
Sample code
option.paymentButton
.component({
id: "klarna-payment-button", // optional test hook
shape: "pill", // "default" | "pill" | "rect"
theme: "default", // "default" | "light" | "dark" | "outlined"
intent: "PAY",
initiationMode: "DEVICE_BEST", // "DEVICE_BEST" | "ON_PAGE" | "REDIRECT"
initiate: (klarnaNetworkSessionToken, paymentOptionId) =>
initiateKlarnaPayment(klarnaNetworkSessionToken, paymentOptionId)
})
.mount(`#${containerId}-payment-button`);The button will automatically handle customer interaction and trigger the Klarna Purchase Journey via the initiate function.
initiate callbackWhen using the Payment Authorize API, the Partner frontend implements the initiate callback to send the payment context to the Partner backend. The Partner backend then calls Klarna's authorizePayment action and returns the result.
The initiate callback receives two parameters from the Klarna web SDK:
klarnaNetworkSessionToken — represents payment context, including the customer's authentication and consent state. Forward this to the Partner backend and include it in the Klarna-Network-Session-Token header when calling the Payment Authorize API.paymentOptionId — identifies which payment option the customer selected. Forward this to the Partner backend and include it as the payment_option_id field in the request body when calling the Payment Authorize API.The callback must return a Promise that resolves to a returnUrl when Klarna returns STEP_UP_REQUIRED, or null if the authorization completes immediately (APPROVED or DECLINED).
Sample code
async function initiateKlarnaPayment(klarnaNetworkSessionToken, paymentOptionId) {
// Partner-implemented backend endpoint that calls Klarna's authorizePayment
const response = await fetch("/api/authorize-payment", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
klarnaNetworkSessionToken,
paymentOptionId,
amount: 11800,
currency: "USD"After building the payment form, complete your integration: