Klarna Direct

Payment Tokenization for Server-side integration

Save a customer's Klarna payment method from the backend using the canonical Payment Request, Klarna Purchase Journey, token issuance flow. Step-by-step server-side implementation for Partners, with sample requests and responses for tokenization only and tokenization combined with an initial payment.

Overview

Use this guide to save a customer's Klarna payment method from the backend without embedding the Klarna Web SDK in the checkout. Partners create a Payment Request that asks Klarna to issue a customer_token, redirect the customer to the Klarna Purchase Journey to collect consent, then either store the issued token (tokenization only) or finalize an initial Payment Transaction (tokenization combined with authorization).
This page is the tokenization counterpart of Authorize a customer-initiated payment (server-side). It uses the same createPaymentRequest, redirect, webhook, authorizePayment pattern, with one extra parameter (request_customer_token) that tells Klarna to issue a token alongside (or instead of) a Payment Transaction.
For conceptual background on tokenization, scopes, and the customer-not-present authorization path, see the Payment Tokenization overview and the Customer Token resource.
What this guide covers
  • A backend that creates a Payment Request with request_customer_token and stores the resulting payment_request_id.
  • A redirect step from the checkout to the Klarna Purchase Journey.
  • A webhook handler that processes payment.request.state-change.completed and extracts either the customer_token (tokenization only) or the klarna_network_session_token (tokenization combined with authorization).
  • For combined flows, a backend step that finalizes the Payment Transaction with authorizePaymentAPI.
  • Secure storage of the issued customer_token, ready to be reused on subsequent authorizations.
When Klarna is embedded in the checkout via the Klarna Web SDK, follow Tokenization for hosted checkout pages and embedded elements instead. The SDK orchestrates the same underlying API calls, but launches the Klarna Purchase Journey in a popup or modal rather than via a full-page redirect.

Prerequisites

Before starting tokenization, ensure the following are in place:
  • A valid Klarna Partner account with API credentials.
  • 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 where Klarna can redirect the customer after the Klarna Purchase Journey.
  • A checkout, account-setup, or subscription-signup flow where the customer is present and able to provide consent for saving the payment method.
  • A clear customer-facing consent mechanism that explains the token's intended use (subscription billing, on-demand re-authorization, wallet linking).

End-to-end flow

The flow is the canonical Partner Payment Request flow, with two branches that diverge after the customer completes the Klarna Purchase Journey:
  • The Partner's backend calls createPaymentRequestAPI with request_customer_token (and, for the combined flow, an amount) plus customer_interaction_config.method = HANDOVER.
  • Klarna responds with a payment_request_id and a payment_request_url.
  • Redirect the customer's browser to the payment_request_url.
  • The customer authenticates with Klarna and approves the tokenization (and the initial payment, when one was requested) in the Klarna Purchase Journey.
  • Klarna sends a payment.request.state-change.completed webhook.
  • Branch on the scenario:
    • Tokenization only: The webhook payload (and the Payment Request's state_context.klarna_customer.customer_token) carry the issued customer_token. Tokenization is complete: store the token securely and confirm the outcome to the customer. No further API call is needed.
    • Tokenization combined with authorization: The webhook payload carries a klarna_network_session_token. Call authorizePaymentAPI with the Klarna Network Session Token in the Klarna-Network-Session-Token header to create the initial Payment Transaction. The response includes both customer_token_response (the issued token) and payment_transaction_response (the payment outcome).
sequenceDiagram autonumber participant C as Customer participant P as Partner participant K as Klarna C->>P: Initiate tokenization (subscription signup, save card, free trial) P->>K: createPaymentRequest (request_customer_token, customer_interaction_config=HANDOVER) K->>P: payment_request_id, payment_request_url, state=SUBMITTED P->>C: Redirect to payment_request_url C->>K: Authenticate and approve tokenization in the Purchase Journey K->>C: Redirect to return_url K-->>P: Webhook payment.request.state-change.completed (state=COMPLETED) alt Tokenization only Note over K,P: Payload carries customer_token in klarna_customer P->>P: Store customer_token securely P->>C: Confirm tokenization success else Tokenization combined with authorization Note over K,P: Payload carries klarna_network_session_token P->>K: authorizePayment with Klarna-Network-Session-Token header alt APPROVED K->>P: customer_token_response + payment_transaction_response (APPROVED) P->>P: Store customer_token and payment_transaction_id P->>C: Show success page else DECLINED K->>P: customer_token_response + payment_transaction_response (DECLINED) Note over P: Token may still be issued, inspect customer_token_response P->>C: Show alternative payment page end end

Step 1: Create the Payment Request

From the Partner's backend, call createPaymentRequestAPI with the tokenization context and a customer_interaction_config describing how Klarna should hand the customer over to the Klarna Purchase Journey. For server-rendered checkouts, set method = HANDOVER and provide a return_url (and optionally an app_return_url for native apps).
The request structure depends on whether the payment method is being saved alone, or saved together with an initial payment.
Use this shape to save a payment method without an immediate charge (for example, a free trial, wallet linking, or "save card for later"). Include request_customer_token and omit request_payment_transaction and amount.
Include at minimum:
ParameterRequiredDescription
currencyYesCurrency in ISO 4217 format. The token's currency context for future transactions.
request_customer_token.scopesYesToken scope. Use payment:customer_not_present for subscription / scheduled billing, payment:customer_present for on-demand / one-click. See token scopes.
request_customer_token.customer_token_referenceRecommendedThe Partner's own reference for the token, used for reconciliation and to link the token to a customer record.
customer_interaction_config.methodYesSet to HANDOVER for the redirect-based server-side flow. The customer must always provide consent for tokenization, so HANDOVER is mandatory here.
customer_interaction_config.return_urlYesURL on the Partner's domain where Klarna redirects the customer after the Klarna Purchase Journey.
customer_interaction_config.app_return_urlRecommended (mobile)App scheme or universal link that returns the customer to the Partner's native app after a mid-flow handover to a third-party app (such as 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 context describing the tokenization use case. Significantly improves underwriting and powers customer communication. See supplementary purchase data.
supplementary_purchase_data.subscriptionsConditionalRequired when the token will be used for subscription authorizations (scope payment:customer_not_present). Include subscription reference, billing plans, and free-trial status.
supplementary_purchase_data.ondemand_serviceConditionalRequired when the token will be used for on-demand authorizations (scope payment:customer_present). Describes the service the token will be used for.
supplementary_purchase_data.customerRecommendedCustomer context (name, email, address). Used by Klarna to simplify sign-up and for fraud assessment.
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. See Payment Request resource.

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", "payment_request_reference": "partner-tokenization-reference-1234", "request_customer_token": { "scopes": ["payment:customer_not_present"], "customer_token_reference": "subscription-user-12345" },

Sample response

A successful call returns the created Payment Request in SUBMITTED state with the payment_request_url to redirect the customer to in Step 2:
JSON
1 2 3 4 5 6 7 8 9 10
{ "payment_request_id": "krn:payment:us1:request:bcb5ca7d-9ad4-4cf1-9e34-7311f0d3ab02", "payment_request_reference": "partner-tokenization-reference-1234", "currency": "USD", "state": "SUBMITTED", "state_context": { "customer_interaction": { "method": "HANDOVER", "payment_request_id": "krn:payment:us1:request:bcb5ca7d-9ad4-4cf1-9e34-7311f0d3ab02", "payment_request_url": "https://pay.test.klarna.com/na/requests/2cb914b0-[...]/start"
Optionally set customer_interaction_config.interaction_expiry to override the default 3-hour Payment Request lifetime. See Custom Payment Request expiry.
Token scope selection is critical
The token scope must match the intended re-authorization pattern:
  • payment:customer_present is for on-demand re-authorizations where the customer is present.
  • payment:customer_not_present is for unattended scheduled authorizations.
Klarna issues exactly one scope per token, and it cannot be changed later. See the token scopes guidance for help choosing.

Step 2: Redirect the customer to the Klarna Purchase Journey

Redirect the customer to the payment_request_url returned in Step 1. The Klarna Purchase Journey lets the customer authenticate with Klarna (login, one-time passcode, biometrics), confirm tokenization consent, and (for combined flows) approve the initial payment.
On completion, Klarna redirects the customer back to the return_url (or app_return_url on mobile) provided in customer_interaction_config. For tokenization-only flows, the issued customer_token is delivered via the webhook (Step 3). For combined flows, Klarna also issues a klarna_network_session_token used to finalize the Payment Transaction in Step 4.
Phone collection in the Klarna Purchase Journey

Return URLs

The return_url and app_return_url set inside customer_interaction_config tell Klarna where to send the customer after they complete or stop the Klarna Purchase Journey.

return_url

When the Klarna Purchase Journey is launched in a web environment, Klarna redirects the customer to the return_url after they finish, whether they complete or stop the flow.

app_return_url

On mobile, the customer may be redirected to a third-party app (such as a bank app) or the Klarna app during the Klarna Purchase Journey. The app_return_url brings the customer back to the Partner's mobile app when this happens.
Register a URL scheme (for example, yourapp://klarna) or a universal link that resumes the tokenization flow. Klarna invokes this URL after the customer completes a native app-based step, such as biometric authentication or Klarna app login. Resume the mobile app in its last state without applying state changes or deep link navigations.

Interaction scenarios

The return_url and app_return_url are not mutually exclusive. Depending on the device and environment, either or both may be triggered:
ScenarioDescription
Pure web flowThe customer starts the Klarna Purchase Journey in a desktop browser. After completing the flow, Klarna redirects them to return_url.
App-to-app flowThe Partner's native app opens the Klarna Purchase Journey using a universal link. When the Klarna app is installed, the customer goes directly into it. After completion, Klarna redirects them to app_return_url.
WebView flow with app handoverThe Partner's native app starts the Klarna Purchase Journey in a System WebView. When the customer must authenticate via an external banking app, app_return_url returns them to the Partner's app mid-flow. They then resume in the WebView and, on completion, are redirected to return_url.

Step 3: Receive the tokenization outcome

Once the customer approves tokenization in the Klarna Purchase Journey, Klarna transitions the Payment Request to COMPLETED and notifies the Partner via webhook. The payload differs by scenario.
Klarna provides two methods to retrieve the tokenization outcome. Subscribing to the webhook event is required and may be combined with reading the Payment Request as a fallback for resilience.

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 tokenization. Subscribe via the Webhooks registration guide.
The webhook payload carries the issued customer_token directly under klarna_customer. Tokenization is complete at this point. No further API call is needed. Store the token securely and confirm the outcome to the customer.
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": "2026-04-01T16:55:17Z", "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-[...]",
The klarna_network_session_token is valid for only 1 hour and must be used within this time frame to finalize the Payment Transaction.

Method: Read the Payment Request (optional fallback)

As a fallback (for example, when the webhook is delayed or the handler missed it), call readPaymentRequestAPI. Once the Payment Request reaches the COMPLETED state, both the customer_token and (for combined flows) the klarna_network_session_token are available in state_context.
Sample response
JSON
1 2 3 4 5 6 7 8 9 10
{ "payment_request_id": "krn:payment:us1:request:bcb5ca7d-9ad4-4cf1-9e34-7311f0d3ab02", "payment_request_reference": "partner-tokenization-reference-1234", "state": "COMPLETED", "previous_state": "IN_PROGRESS", "state_context": { "klarna_customer": { "customer_token": "krn:partner:us1:test:identity:customer-token:Rt4iBjqKBM[...]", "customer_token_reference": "subscription-user-12345" }
Tokenization-only flow: complete. When only a token was requested (no amount), tokenization is complete now. Skip Step 4 and go straight to Step 5: Store the customer token.

Step 4: Finalize the Payment Transaction (combined flow only)

This step applies only to the Tokenization combined with authorization flow. Tokenization itself is already complete at the end of Step 3. What remains is to create the initial Payment Transaction using the Klarna Network Session Token.
Call authorizePaymentAPI with the klarna_network_session_token in the Klarna-Network-Session-Token request header. Klarna creates the Payment Transaction and confirms the issued customer_token in the same response.
The customer's selected payment method is carried by the Klarna Network Session Token, so payment_option_id is not required. Use the same currency, amount, and supplementary_purchase_data sent on the Payment Request. Significant differences may cause Klarna to require re-confirmation.
Because the customer just completed the Klarna Purchase Journey, Klarna may still ask for a step-up at authorization. Include step_up_config to make recovery possible; without it, borderline cases return DECLINED instead of STEP_UP_REQUIRED.
Include at minimum:
ParameterRequiredDescription
Klarna-Network-Session-Token (header)YesThe Klarna Network Session Token received in Step 3.
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.
request_customer_token.scopesYesSame scope requested on the Payment Request. Required so Klarna confirms the token under the same scope.
request_customer_token.customer_token_referenceRecommendedSame reference used on the Payment Request.
supplementary_purchase_dataRecommendedSame supplementary data sent on the Payment Request.
step_up_configRecommendedOpts in to the STEP_UP_REQUIRED outcome so the customer can complete a step-up Klarna Purchase Journey when Klarna's risk signals require additional interaction. Set customer_interaction_config.method = HANDOVER and provide a return_url (and optionally app_return_url for native apps). Without it, borderline cases return DECLINED.
acquiring_configConditionalRoutes the Payment Transaction to a specific Payment Account or Payment Acquiring Account, and optionally requests the settlement currency. Use the same routing fields set on the Payment Request.

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:eyJhbGciOiJFU...' \ -d '{ "currency": "USD", "request_payment_transaction": { "amount": 1999, "payment_transaction_reference": "subscription-first-payment-001" },
When the klarna_network_session_token has expired (1-hour validity) or the payment context differs significantly from the original Payment Request, the call returns DECLINED. The customer_token may still be issued, so always inspect customer_token_response independently of the payment result.

Handle the authorization result

Klarna returns response objects matching what was requested: a customer_token_response for the token, and a payment_transaction_response for the initial payment. The two are independent. A DECLINED payment does not automatically mean the token was not issued.
Result (payment_transaction_response.result)DescriptionNext steps
APPROVEDThe initial Payment Authorization succeeded and a payment_transaction was created. The customer_token is returned in customer_token_response and is ready for future use.Store the customer_token securely (Step 5), persist the payment_transaction_id, and confirm the outcome to the customer.
STEP_UP_REQUIREDReturned only when step_up_config was included on the request. Klarna's risk signals require additional customer interaction before approval. The response includes a new Payment Request with customer_interaction details.Launch the Klarna Purchase Journey using the new Payment Request, wait for the next payment.request.state-change.completed webhook to deliver a new Klarna Network Session Token, then call authorizePaymentAPI again with that token to finalize. The same Customer Token context is preserved across the retry.
DECLINEDThe initial Payment Authorization failed. No payment_transaction is created. The customer_token may still be returned in customer_token_response and remain valid for future use. Inspect customer_token_response.result to be sure.Show the customer a decline / alternative payment page. When the token was issued, decide whether to retain it (typical for subscription onboarding where the next billing attempt can succeed) or discard it based on business logic.
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:5cb3e0e5-a6f0-[...]", "payment_transaction_reference": "subscription-first-payment-001", "amount": 1999, "currency": "USD", "payment_pricing": {...}, "payment_funding": {

Step 5: Store the customer token

Once a customer_token is available (whether from the Step 3 webhook for tokenization only, or the Step 4 response for the combined flow), persist it securely. The customer_token is a sensitive credential that allows authorizations on behalf of the customer until it expires or is revoked.
PracticeDescription
Store securelyPersist customer_token values in encrypted storage. Restrict access to the systems that issue authorizations.
Associate with the customerLink each token to the relevant customer record, including the issuing scope and the issuance timestamp. Use customer_token_reference to keep the Partner's reference and the Klarna-issued token in sync.
Track scope and intentRecord the token's scope (payment:customer_present or payment:customer_not_present) and the business intent (subscription, wallet, on-demand) so the right token is picked at authorization time.
Honor lifecycle eventsWhen a customer cancels their subscription or removes their saved payment method, stop using the token and delete it or mark it as inactive.
Do not expose tokensNever return raw customer_token values to a frontend, mobile clients, or third parties. Reference them by an internal identifier instead.
For the conceptual model and lifecycle of the resource, see the Customer Token resource.

Charging with the customer token

Once stored, the customer_token is what Partners reuse on subsequent authorizations. Both authorization patterns start with authorizePaymentAPI and bypass the upfront Payment Request, because the stored token already represents the customer's consent. The difference is whether step_up_config is included to opt in to step-up:
  • Customer-present authorizations (on-demand, one-click): use scope payment:customer_present. Call authorizePaymentAPI directly with the Klarna-Customer-Token header, currency, request_payment_transaction.amount, supplementary_purchase_data, and step_up_config with customer_interaction_config.method = HANDOVER and a return_url. When Klarna's risk signals require additional customer interaction, the response is STEP_UP_REQUIRED with a new Payment Request. Launch the Klarna Purchase Journey using it, then call authorizePaymentAPI again with the new Klarna Network Session Token. Without step_up_config, Klarna returns DECLINED on borderline cases instead of allowing recovery.
  • Customer-not-present authorizations (subscriptions, scheduled billing): use scope payment:customer_not_present. Call authorizePaymentAPI directly with the Klarna-Customer-Token header, currency, request_payment_transaction.amount, and supplementary_purchase_data. Do not include step_up_config. There is no customer available to complete a step-up Klarna Purchase Journey. Klarna returns APPROVED or DECLINED only.
For the full token-authorization guidance and request shapes, see the Customer Token resource and the Payment Tokenization overview.
Related articles
Build Payment Presentation with the Klarna Web SDK
Authorize a customer-initiated payment (server-side)
Payment Tokenization Overview
Customer Token
Payment Tokenization for Hosted Checkout integration