Klarna Direct

Authorize a customer-initiated payment (Web SDK)

Authorize a customer-initiated payment when the Klarna Web SDK is embedded in the checkout. The SDK orchestrates the Klarna Purchase Journey through the Klarna payment button; the Partner's backend creates the Payment Request and finalizes the authorization.

Overview

Use this guide when the Klarna Web SDK is embedded in the checkout and the Partner wants to launch the Klarna Purchase Journey from the Klarna payment button — keeping the customer on the page in a popup or modal instead of redirecting them away.
The underlying API calls are the same as in the server-side flow: createPaymentRequest, retrieve the klarna_network_session_token, then authorizePayment. What differs is the orchestration: the SDK handles the customer-facing Klarna Purchase Journey through the initiate callback on the Klarna payment button, while the Partner's backend remains responsible for creating the Payment Request and authorizing the payment.
When the checkout is server-rendered and the Web SDK is not embedded, follow Authorize a customer-initiated payment (server-side) instead. That guide covers the same underlying API calls using a full-page redirect to the Klarna Purchase Journey and a webhook to deliver the Klarna Network Session Token.
This guide focuses on the orchestration that follows: creating the Payment Request, retrieving the Klarna Network Session Token, and authorizing the payment. For displaying Klarna in the payment selector and configuring the Klarna payment button, see Build Payment Presentation with the Klarna Web SDK.

Prerequisites

Before starting, ensure the following are in place:
  • A valid Klarna Partner account with API credentials.
  • The Klarna Web SDK initialized in the checkout, with Klarna rendered in the payment selector and the Klarna payment button mounted. See Build Payment Presentation with the Klarna Web SDK.
  • Backend capability to receive and process Klarna webhooks. See Webhooks registration.
  • A subscription to the payment.request.state-change.completed webhook event.
  • A return_url on the Partner's domain that Klarna can redirect the customer to when the Klarna Purchase Journey ends in a REDIRECT or DEVICE_BEST flow.

End-to-end flow

When the customer selects Klarna in the checkout and clicks the Klarna payment button:
  • The Web SDK invokes the initiate callback configured on the payment button.
  • Inside initiate, the SDK supplies the klarna_network_session_token and paymentOptionId to the callback as arguments. The Partner's frontend posts both to its own backend.
  • The Partner's backend calls createPaymentRequestAPI with the payment context and customer_interaction_config, and returns the resulting payment_request_url to the frontend.
  • The frontend resolves the initiate callback with { paymentRequestUrl }. The SDK launches the Klarna Purchase Journey in a popup, modal, or redirect depending on the configured initiationModeDEVICE_BEST is the recommended default. See Step 3: Configure how the Klarna Purchase Journey is launched.
  • The customer completes the Klarna Purchase Journey (authentication, payment method selection, confirmation).
  • The Payment Request transitions to COMPLETED and Klarna sends a payment.request.state-change.completed webhook carrying the klarna_network_session_token.
  • The Partner's backend calls authorizePaymentAPI with the Klarna-Network-Session-Token header to create the Payment Transaction. Optionally include step_up_config so Klarna can return STEP_UP_REQUIRED (and a new Payment Request) instead of DECLINED when additional customer interaction is needed.
  • When Klarna returns STEP_UP_REQUIRED, the SDK can launch the Klarna Purchase Journey for the new Payment Request. After the customer completes it, a new Klarna Network Session Token arrives via webhook and the backend calls authorizePaymentAPI again.
sequenceDiagram autonumber participant C as Customer participant FE as Partner frontend (Web SDK) participant BE as Partner backend participant K as Klarna C->>FE: Clicks Klarna payment button FE->>FE: SDK invokes initiate(klarna_network_session_token, paymentOptionId) FE->>BE: POST /api/payment-request (klarna_network_session_token, paymentOptionId) BE->>K: createPaymentRequest (HANDOVER, return_url, supplementary_purchase_data) K->>BE: payment_request_url BE->>FE: { paymentRequestUrl } FE->>K: SDK launches Klarna Purchase Journey (modal/popup/redirect) C->>K: Customer completes the Klarna Purchase Journey K-->>BE: Webhook payment.request.state-change.completed Note over K,BE: klarna_network_session_token BE->>K: authorizePayment with Klarna-Network-Session-Token header (optional step_up_config) alt APPROVED K->>BE: APPROVED, payment_transaction BE->>FE: Confirmation FE->>C: Show success page else DECLINED K->>BE: DECLINED BE->>FE: Decline FE->>C: Show failure / alternative payment page else STEP_UP_REQUIRED (only if step_up_config was sent) K->>BE: STEP_UP_REQUIRED, new Payment Request BE->>FE: New paymentRequestUrl FE->>K: SDK launches step-up Purchase Journey C->>K: Customer completes step-up Purchase Journey K-->>BE: Webhook with new klarna_network_session_token BE->>K: authorizePayment again with new Klarna Network Session Token K->>BE: APPROVED / DECLINED BE->>FE: Result FE->>C: Show success / failure page end

Step 1: Implement the initiate callback (frontend)

The initiate callback is configured on the Klarna payment button when it is mounted. The SDK invokes it the moment the customer clicks the button and supplies the klarna_network_session_token and paymentOptionId as arguments. Use the callback to forward both to the backend, create the Payment Request, and resolve the callback with the resulting paymentRequestUrl.
JAVASCRIPT
1 2 3 4 5 6 7 8 9 10
async function initiateKlarnaPayment(klarnaNetworkSessionToken, paymentOptionId) { try { // Forward the token and paymentOptionId to the backend so it can create the Payment Request const response = await fetch('/api/payment-request', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ klarnaNetworkSessionToken, paymentOptionId }) }); if (!response.ok) throw new Error('Network or server error');
For details on configuring the paymentButton.component({ initiate, initiationMode, ... }) parameters, see Build Payment Presentation with the Klarna Web SDK — Step 7: Configure the Klarna payment button.

Step 2: Create the Payment Request (backend)

From the backend endpoint called by the initiate callback, call createPaymentRequestAPI with the payment context and a customer_interaction_config. For Web SDK integrations, set method = HANDOVER and provide a return_url (and optionally an app_return_url for native apps). The same fields apply as in the server-side flow — see Payment Request for the full resource model and Supplementary purchase data for the recommended data points.
Include at minimum:
ParameterRequiredDescription
currencyYesCurrency in ISO 4217 format.
amountYesTotal amount of the Payment Request, including tax and discounts.
customer_interaction_config.methodYesSet to HANDOVER. The SDK orchestrates how the Klarna Purchase Journey is launched (modal, popup, or redirect) based on initiationMode.
customer_interaction_config.return_urlYesURL on the Partner's domain where Klarna redirects the customer when the SDK falls back to a redirect — used by the recommended DEVICE_BEST mode on mobile and by REDIRECT mode.
customer_interaction_config.app_return_urlOptionalApp scheme or universal link that returns the customer to the Partner's native app after a mid-flow handover to a third-party app (for example, a bank app or the Klarna app). Not a substitute for return_url.
payment_request_referenceRecommendedThe Partner's own reference for the Payment Request, used for reconciliation.
supplementary_purchase_dataRecommendedAdditional purchase context (line items, customer, shipping, purchase reference). Improves underwriting and fraud detection and powers customer communication. See Supplementary purchase data.
acquiring_configConditionalRoutes the Payment Request to a specific Payment Account or Payment Acquiring Account. Required when the Partner's Klarna setup includes more than one account. Provide either payment_account_id (account-only routing) or payment_acquiring_account_id together with payment_account_reference (acquiring-account routing). When omitted, Klarna uses the default account configured for the Partner.

Sample request

SHELL
1 2 3 4 5 6 7 8 9 10
curl https://api-global.test.klarna.com/v2/payment/requests \ -H 'Authorization: Basic <API key>' \ -H 'Content-Type: application/json' \ -d '{ "currency": "USD", "amount": 11800, "payment_request_reference": "partner-request-reference-1234", "customer_interaction_config": { "method": "HANDOVER", "return_url": "https://partner.example/klarna-redirect?id={klarna.payment_request.id}",

Sample response

A successful call returns the created Payment Request in SUBMITTED state. For the full list of states a Payment Request can transition through, see Payment Request — States. The backend returns the payment_request_id to the frontend so the initiate callback can resolve and the SDK can launch the Klarna Purchase Journey.
JSON
1 2 3 4 5 6 7 8 9 10
{ "payment_request_id": "krn:payment:us1:request:552603c0-fe8b-4ab1-aacb-41d55fafbdb4", "payment_request_reference": "partner-request-reference-1234", "currency": "USD", "amount": 11800, "state": "SUBMITTED", "state_context": { "customer_interaction": { "method": "HANDOVER", "payment_request_id": "krn:payment:us1:request:552603c0-fe8b-4ab1-aacb-41d55fafbdb4",

Step 3: Configure how the Klarna Purchase Journey is launched

The Web SDK launches the Klarna Purchase Journey using the initiationMode parameter set on the Klarna payment button. It controls whether the journey opens in a popup, an in-page iframe, or as a full-page redirect.
initiationModeDescription
DEVICE_BESTDefault and recommended. Selects the best launch method per device — popup on desktop (with redirect fallback), redirect on mobile, redirect in native WebViews. Requires return_url in customer_interaction_config.
ON_PAGELaunches the Klarna Purchase Journey on the same page in a popup (or full-screen iframe as fallback). The customer never leaves the page.
REDIRECTRedirects the customer to the Klarna Purchase Journey. Requires return_url in customer_interaction_config.
For details on the rest of the paymentButton.component() configuration parameters and a sample integration, see Build Payment Presentation with the Klarna Web SDK — Step 7: Configure the Klarna payment button.

Track the Klarna Purchase Journey with Web SDK events

Register event handlers on the KlarnaPayment SDK interface to track the lifecycle of the Klarna Purchase Journey on the client side:
Event handlerPurpose
on("complete", callback)Triggered when the customer completes the purchase. During a redirect flow, fires once the success page loads.
on("abort", callback)Triggered when the customer aborts the Klarna Purchase Journey.
on("error", callback)Triggered when an error occurs during the Payment Request lifecycle. When defined, all errors are emitted to this handler instead of being thrown.
JAVASCRIPT
1 2 3 4 5 6
klarna.Payment.on("complete", (paymentRequest) => { console.log("Payment request completed"); // By default, Klarna will redirect to the submitted return_url upon completion. // Return false if you want to prevent the redirection to the success page. return true; });
Use Web SDK events to enhance the customer experience — for example, displaying clear error messages when a purchase is aborted, or disabling page interactions while payment authorization is in progress.
Never use SDK events to trigger Payment Authorization. Always rely on Klarna webhooks to receive the klarna_network_session_token and finalize the payment after the customer completes the purchase.

Step 4: Receive the klarna_network_session_token

Once the customer completes the purchase, Klarna issues a klarna_network_session_token and the Payment Request transitions to COMPLETED. This token is used in Step 5 to finalize the authorization.
Klarna provides multiple methods to retrieve the token. Subscribing to the webhook event is required and may be combined with reading the Payment Request as a fallback for resilience.
The klarna_network_session_token is valid for only 1 hour and must be used within this time frame to finalize the authorization. See Klarna Network Session Token — Expiration for the expiration model and where to read the expiration timestamp.

Method: Subscribe to the payment.request.state-change.completed webhook (required)

Klarna sends this event when the Payment Request reaches the COMPLETED state, indicating that the customer has approved the purchase and the authorization can be finalized. Subscribe via the Webhooks registration guide.
Sample payload
JSON
1 2 3 4 5 6 7 8 9 10
{ "metadata": { "event_type": "payment.request.state-change.completed", "event_id": "d9f9b1a0-5b1a-4b0e-9b0a-9e9b1a0d5b1a", "event_version": "v2", "occurred_at": "2024-01-01T12:00:00Z", "correlation_id": "2d1557e8-17c3-466c-924a-bbc3e91c2a02", "subject_account_id": "krn:partner:global:account:test:HGBY07TR", "recipient_account_id": "krn:partner:global:account:test:LWT2XJSE", "product_instance_id": "krn:partner:product:payment:ad71bc48-8a07-4919-[...]",

Method: Read the Payment Request (optional fallback)

As a fallback (for example, when the webhook is delayed or the handler missed it) retrieve the token by calling readPaymentRequestAPI. Once the Payment Request reaches the COMPLETED state, the token is available in state_context.klarna_network_session_token.
Sample response
JSON
1 2 3 4 5 6 7 8 9 10
{ "payment_request_id": "krn:payment:us1:request:552603c0-fe8b-4ab1-[...]", "payment_request_reference": "partner-request-reference-1234", "state": "COMPLETED", "previous_state": "IN_PROGRESS", "state_context": { "klarna_network_session_token": "krn:network:us1:test:session-token:eyJhbGciOiJIU..." }, "currency": "USD", "amount": 11800,

Step 5: Authorize the payment

Finalize the payment by calling authorizePaymentAPI with the klarna_network_session_token in the Klarna-Network-Session-Token request header. Klarna creates the Payment Transaction and returns the result.
The customer's selected payment method is carried by the Klarna Network Session Token. There is no need to send payment_option_id.
Include at minimum:
ParameterRequiredDescription
Klarna-Network-Session-Token (header)YesThe Klarna Network Session Token received in Step 4.
currencyYesSame currency used in the Payment Request.
request_payment_transaction.amountYesSame amount used in the Payment Request.
request_payment_transaction.payment_transaction_referenceRecommendedThe Partner's own reference for the Payment Transaction, used for reconciliation.
supplementary_purchase_dataRecommendedSame supplementary data sent in the Payment Request. Significant differences may cause Klarna to require re-confirmation.
acquiring_configConditionalRoutes the Payment Transaction to a specific Payment Account or Payment Acquiring Account, and optionally requests the currency Klarna uses to settle the transaction. Use the same routing fields set on the Payment Request, and add settlement_currency (ISO 4217) when a settlement currency that differs from the Payment Transaction currency is required. See Request settlement currency.
step_up_configRecommendedOpts the Partner in to the STEP_UP_REQUIRED outcome. When included, Klarna can request additional customer interaction (returning a new Payment Request) instead of declining cases where it needs more risk signals. Without it, those cases are returned as DECLINED. Set customer_interaction_config.method = HANDOVER and provide a return_url (and optionally app_return_url) so Klarna knows where to send the customer back after the step-up Klarna Purchase Journey. See Payment Authorization.

Sample request

SHELL
1 2 3 4 5 6 7 8 9 10
curl https://api-global.test.klarna.com/v2/payment/authorize \ -H 'Authorization: Basic <API key>' \ -H 'Content-Type: application/json' \ -H 'Klarna-Network-Session-Token: krn:network:us1:test:session-token:eyJhbGciOiJIU...' \ -d '{ "currency": "USD", "request_payment_transaction": { "amount": 11800, "payment_transaction_reference": "partner-transaction-reference-1234" },

Handle the authorization result

Klarna returns a payment_transaction_response object. The result field indicates the outcome and determines the next action:
ResultDescriptionNext steps
APPROVEDThe authorization succeeded and a payment_transaction was created.Store the payment_transaction_id and proceed with post-purchase operations (capture, refund, etc.). Show the customer a confirmation page.
DECLINEDThe authorization was not approved. No transaction is created. Common causes include an expired Klarna Network Session Token, significant discrepancies between the Payment Request and the authorize call, or risk evaluation requiring additional customer interaction when step_up_config was not included in the request.Show the customer a decline or alternative payment page.
STEP_UP_REQUIREDKlarna requires additional customer interaction before approving. Only returned when step_up_config was included in the authorize request. The response includes a new Payment Request with state_context.customer_interaction.payment_request_url.Pass the new paymentRequestUrl back to the Web SDK so it can launch the step-up Klarna Purchase Journey. When the customer completes it, a new Klarna Network Session Token arrives via webhook. Call authorizePaymentAPI again with the new token.
Without step_up_config in the authorize request, Klarna cannot return STEP_UP_REQUIRED. It returns DECLINED instead in cases where additional customer interaction would have been needed. Klarna recommends including step_up_config by default to recover those cases.
The response schema is as follows:
JSON
1 2 3 4 5 6 7 8 9 10
{ "payment_transaction_response": { "result": "APPROVED", "payment_transaction": { "payment_transaction_id": "krn:payment:us1:transaction:6debe89e-98c0-[...]", "payment_transaction_reference": "partner-transaction-reference-1234", "amount": 11800, "currency": "USD", "payment_pricing": {...}, "payment_funding": {

Step 6: Handle STEP_UP_REQUIRED

When authorizePayment returns STEP_UP_REQUIRED, Klarna creates a new Payment Request that drives the customer through an additional Klarna Purchase Journey to gather the missing risk signals. The integration loops once more through Step 3, Step 4, and Step 5 — using the new Payment Request — and ends with a second authorizePayment call that returns APPROVED or DECLINED.

Pass the new Payment Request to the frontend

Extract payment_request.payment_request_id from the STEP_UP_REQUIRED response and return it to the frontend. Apply the same pattern used in Step 1 — return a JSON response that the initiate callback can use:
JAVASCRIPT
1 2 3 4 5
// Backend res.json({ paymentRequestUrl: response.payment_request.state_context.customer_interaction.payment_request_url });

Launch the step-up Klarna Purchase Journey

The frontend resolves the initiate callback with the new paymentRequestUrl. The Web SDK launches the step-up Klarna Purchase Journey using the same initiationMode configured on the Klarna payment button — no additional SDK calls are needed:
JAVASCRIPT
1
return { paymentRequestUrl: stepUpPaymentRequestUrl };
The customer completes the additional verification in the Klarna Purchase Journey, and the new Payment Request transitions to COMPLETED.

Receive the new Klarna Network Session Token

A second payment.request.state-change.completed webhook is delivered, carrying a fresh klarna_network_session_token for the new Payment Request. Handle it with the same webhook handler used in Step 4.

Retry authorizePayment with the new token

Call authorizePaymentAPI again, using the new klarna_network_session_token in the Klarna-Network-Session-Token header. Send the same currency, request_payment_transaction.amount, acquiring_config, and supplementary_purchase_data used in the original authorize call. Klarna returns APPROVED or DECLINEDSTEP_UP_REQUIRED is not returned a second time once the customer has gone through the step-up Klarna Purchase Journey.
Treat the step-up loop as a single recoverable detour, not a full restart. Reuse the Payment Transaction reference, supplementary data, and routing from the first authorize call — only the Klarna Network Session Token changes between the two requests.
Related articles
Authorize a customer-initiated payment (server-side)
Build Payment Presentation with the Klarna Web SDK
Set up your webhooks
Payment Authorization
Payment Request