Payment Tokenization for Hosted Checkout integration
Save a customer's Klarna payment method from a hosted checkout using the Klarna Web SDK. Create a Payment Request with a tokenization intent, launch the Klarna Purchase Journey, and store the resulting customer token for future on-demand and recurring authorizations.
This guide shows how Partners issue a Klarna customer_token from a hosted checkout that uses the Klarna Web SDK. The Web SDK presents Klarna in the payment selector, the Partner's backend creates a Payment Request that asks Klarna to issue a token, and the SDK launches the Klarna Purchase Journey so the customer can grant consent. Klarna then issues the customer_token that the Partner stores and reuses for subsequent authorizations.
Tokenization always requires a customer-present consent step in the Klarna Purchase Journey. Klarna will never issue a customer_token without it.
This page focuses only on what is specific to tokenization:
Choosing the right Web SDK intent for the tokenization use case.
Calling createPaymentRequest with request_customer_token from the SDK's initiate callback.
Handling the Payment Request completion to retrieve the customer_token.
(Optional) Finalizing an initial Payment Transaction in the tokenization combined with authorization flow.
For everything else (loading the SDK, registering domains, presenting Klarna in the checkout, mounting payment buttons, configuring initiationMode, and listening to SDK events), see the canonical Klarna Web SDK guide. This page does not repeat that material.
Before integrating tokenization with the Web SDK, ensure that the following are in place:
A working Klarna Web SDK integration that already presents Klarna and completes a one-time payment. Tokenization extends this integration, it is not a parallel one.
Webhook subscriptions for payment.request.state-change.completed events, registered as described in Webhooks registration.
A checkout or account-management flow where the customer is present and able to complete the Klarna Purchase Journey to give consent.
Customer-facing copy that clearly discloses tokenization terms (free-trial billing date, subscription frequency, on-demand re-use), as required by the chosen token scope.
Tokenization with the Web SDK reuses the standard Web SDK flow. The only differences are the intent passed on payment presentation, the request_customer_token field added to the Payment Request body, and how the completion webhook is handled.
sequenceDiagram
autonumber
participant C as Customer
participant FE as Partner frontend (Web SDK)
participant BE as Partner backend
participant K as Klarna
FE->>K: Initialize Klarna Web SDK (clientId, products)
FE->>K: klarna.Payment.presentation({ currency, intent: "SUBSCRIBE" })
K-->>FE: Payment presentation (Klarna option + payment button)
C->>FE: Selects Klarna and clicks the payment button
FE->>FE: SDK invokes the initiate callback
FE->>BE: POST /api/start-tokenization (paymentOptionId, klarnaNetworkSessionToken?)
BE->>K: createPaymentRequest (request_customer_token, currency, customer_interaction_config)
K-->>BE: payment_request_id, payment_request_url (state SUBMITTED)
BE-->>FE: { paymentRequestUrl }
FE->>K: Web SDK launches the Klarna Purchase Journey (paymentRequestUrl)
C->>K: Authenticates and approves tokenization
K-->>BE: Webhook payment.request.state-change.completed
alt Tokenization only
Note over K,BE: state COMPLETED, customer_token in state_context.klarna_customer
BE->>BE: Persist customer_token
else Tokenization combined with authorization
Note over K,BE: state COMPLETED, klarna_network_session_token
BE->>K: authorizePayment with Klarna-Network-Session-Token header
K-->>BE: customer_token_response + payment_transaction_response
end
K-->>FE: SDK on("complete") callback fires
FE->>C: Confirm tokenization (and payment, when combined)
Tokenization with the Web SDK supports two scenarios. The choice drives the createPaymentRequest body and how the completion webhook is handled.
Scenario
Description
Web SDK intent
Tokenization only
Save a payment method without an immediate charge (for example, free trials, wallet linking, or account setup). The Payment Request completion delivers the customer_token directly. No second API call is needed.
SUBSCRIBE or ADD_TO_WALLET
Tokenization combined with authorization
Save a payment method and charge the customer in the same flow (for example, a subscription that starts with a first payment). The Payment Request completion delivers a Klarna Network Session Token, and Partners call authorizePayment to create the initial Payment Transaction.
PAY (or the tokenization intent the use case requires)
Pick the token scope that matches the re-authorization model:
payment:customer_present: on-demand and one-click authorizations (the customer triggers each authorization).
When calling klarna.Payment.presentation(), set intent to the value that matches the tokenization use case. The intent personalizes the Klarna Purchase Journey copy, payment options, and consent screens for the customer.
Intent
Use case
SUBSCRIBE
Recurring authorizations at regular intervals (subscriptions). The customer saves a payment method for future automatic authorizations.
ADD_TO_WALLET
Wallet linking. Save a payment method to a customer account for later customer-initiated purchases.
PAY
One-time payments. Use this intent when tokenization is combined with an initial Payment Transaction (for example, a subscription that charges its first month immediately).
Pass the intent on payment presentation:
JAVASCRIPT
1
2
3
4
5
6
7
const paymentPresentation = await klarna.Payment.presentation({
currency: "USD",
// amount is required when intent is PAY or SUBSCRIBE
amount: 999,
locale: "en-US",
intent: "SUBSCRIBE"
});
For the full presentation surface (initialization, rendering, payment-option selection, and button mounting), see Build checkout form with Klarna WebSDK.
Omit amount when the intent is ADD_TO_WALLET. The PAY and SUBSCRIBE intents both require amount.
The Klarna payment button calls the initiate callback when the customer clicks it. In a one-time payment flow this callback creates a Payment Request for a charge. For tokenization, it instead asks the Partner's backend to create a Payment Request with request_customer_token and return the resulting paymentRequestUrl to the SDK.
The callback signature is the same as for one-time payments, initiate(klarnaNetworkSessionToken, paymentOptionId), and it must resolve to { paymentRequestUrl }.
JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
asyncfunctioninitiateKlarnaTokenization(klarnaNetworkSessionToken, paymentOptionId) {
try {
const response = awaitfetch('/api/start-tokenization', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ klarnaNetworkSessionToken, paymentOptionId })
});
if (!response.ok) thrownewError('Network or server error');
For button mounting, theming, initiationMode choices, and Web SDK event handlers (on("complete"), on("abort"), on("error")), refer to the Web SDK guide. They apply to tokenization unchanged.
The klarnaNetworkSessionToken provided to the callback carries Klarna context from a Boost feature (Express checkout, Sign in with Klarna, on-site messaging). It is optional on the tokenization Payment Request. Klarna will create the Klarna Purchase Journey from scratch when it is absent. Forward it to the backend whenever the SDK provides one so Klarna can personalize the journey.
The backend handler calls createPaymentRequest with request_customer_token. The body shape depends on whether the customer is also charged.
To save the payment method only:
Include request_customer_token with the scopes that matches the re-authorization model and an optional customer_token_reference to link the token to an internal user.
Provide currency (no amount, no request_payment_transaction).
Provide customer_interaction_config with method: "HANDOVER" and a return_url. This enables the SDK to launch the Klarna Purchase Journey.
Provide supplementary_purchase_data describing the intended use case. Use subscriptions[] for recurring re-authorizations or ondemand_service for on-demand re-authorizations.
Token scope is critical. It must match how the customer will be re-authorized. See Token scopes for guidance on choosing between payment:customer_present and payment:customer_not_present.
The return_url (web) and app_return_url (mobile) parameters in customer_interaction_config define where Klarna brings the customer back after the Klarna Purchase Journey completes or is stopped. Configure them following the same rules used for one-time payments. See Configure customer-interaction parameters for the details. Tokenization adds no extra requirements.
When the initiate callback resolves with { paymentRequestUrl }, the Klarna Web SDK launches the Klarna Purchase Journey using the configured initiationMode on the payment button. The customer authenticates with Klarna, reviews the consent terms (subscription frequency, free-trial dates, on-demand re-use), and approves tokenization.
For DEVICE_BEST, the SDK automatically selects either an on-page or redirect experience based on the device. When the experience is on-page the customer stays on the page; when it is a redirect, Klarna brings the customer back to the configured return_url on completion or stop.
For REDIRECT, the customer is redirected to the Klarna Purchase Journey and Klarna brings them back to the configured return_url on completion or stop.
For ON_PAGE, the Klarna Purchase Journey is rendered in a popup or in-page modal. The customer never leaves the page.
Use the standard Web SDK event handlers (on("complete"), on("abort"), on("error")) to update the UI, but never finalize tokenization or take a Payment Transaction from a frontend event. Always rely on Klarna webhooks (Step 6) to drive backend state changes.
When the customer completes the Klarna Purchase Journey, Klarna sends a payment.request.state-change.completed webhook to the Partner's backend. The webhook payload differs by scenario.
The webhook payload contains the issued customer_token directly. No further API call is required. Persist the token, mark the tokenization as successful in local records, and confirm to the customer.
The same customer_token can also be retrieved from state_context.klarna_customer.customer_token by calling readPaymentRequest as a fallback.
Subscribe to webhook events through the Webhooks registration guide. Use readPaymentRequest as an optional fallback when the webhook handler missed the event. The same customer_token and klarna_network_session_token are available in state_context.
Webhook delivery is the source of truth. The Web SDK on("complete") callback can update the UI optimistically, but it must not be used to confirm tokenization or take a payment.
This step applies only to the tokenization combined with authorization scenario. Tokenization itself is already complete after the webhook in Step 6. This step finalizes the initial Payment Transaction using the Klarna Network Session Token issued by Klarna.
The Klarna Network Session Token is valid for 1 hour. When it expires, or when the payment context (amount, currency, supplementary_purchase_data) does not match the original Payment Request, Klarna returns DECLINED.
The response carries both customer_token_response and payment_transaction_response. Inspect each independently. Even when the Payment Transaction is declined, the customer's tokenization consent may still result in an issued customer_token.
Klarna created the Payment Transaction and the customer_token is ready for re-use.
Persist payment_transaction.payment_transaction_id and customer_token. Continue with capture/refund through the Payment Transaction operations.
DECLINED
The Payment Transaction failed. Inspect customer_token_response separately. The customer_token may still be valid.
Show the customer an error and offer an alternative payment method. Decide based on customer_token_response.result whether to keep or discard the token.
After Step 6 (tokenization-only) or Step 7 (combined), persist the customer_token securely. Treat it as a sensitive credential. It allows authorizations on behalf of the customer until it expires or is revoked.
Practice
Description
Store securely
Persist customer_token values in encrypted storage; restrict access to the systems that issue authorizations.
Associate with the customer
Link each token to the relevant customer record together with the issued scope and the issuance timestamp.
Track scope and intent
Record the token's scopes and the business intent (subscription, wallet, on-demand) so the correct token is used at authorization time.
Honor lifecycle events
When the customer cancels their subscription or removes a saved payment method, stop using the token and mark it inactive.
Do not expose tokens
Never return raw customer_token values to a frontend, mobile clients, or third parties. Reference them by an internal identifier instead.
Update the frontend through the SDK's on("complete") callback (or a success page) to confirm to the customer that the payment method is saved.
For the resource-level lifecycle and revocation operations, see Customer Token.