Charge customer-initiated on-demand purchases with the customer token using the Klarna Payments JavaScript SDK, including support for step-up when customer interaction is required to authorize the purchase.
Charge a customer-initiated on-demand purchase with an existing Klarna customer token, using the Klarna Payments JavaScript SDK to authorize the charge. Klarna aims to authorize immediately so the customer can continue without friction. Your integration must handle two outcomes:
1.
Klarna authorizes immediately — you fulfil the order.
2.
Klarna requires a step-up — to protect the customer or satisfy risk / compliance requirements, Klarna returns a step_up_id; the SDK hands off to the Klarna Purchase Journey to collect the customer's authorization (login, OTP, alternative funding source).
1. Partner checkout — customer confirms cart and selects Klarna
2. Klarna Purchase Journey — shown only if Klarna requires step-up
3. Partner confirmation — order placed; customer token updated
Before charging, your frontend shows the customer the standard purchase-confirmation surface they expect — a one-tap checkout sheet, a wallet drawer, a "Buy now" page, or whatever your flow uses. The cart, total, currency, and the saved Klarna payment method must be visible so the customer can confirm before you call Klarna.
The Klarna Payments JavaScript SDKmust already be loaded on this surface. Do not lazy-load it after the charge response — by the time Klarna returns step_up_id, the SDK must be ready to mount the Klarna Purchase Journey.
Include the SDK script tag with the rest of your initial page assets:
The SDK exposes window.Klarna.Payments once loaded. Defer the createOrder call (Step 2) until the script is on the page on initial render — or, if you really must inject it dynamically, until you've awaited its onload.
When the customer confirms the purchase, your backend calls createOrder on the customer token with step_up: SUPPORTED. This signals to Klarna that you are ready to handle a step-up if Klarna decides to run one.
Send a unique Klarna-Idempotency-Key per charge attempt. Reuse the same key when retrying the same logical charge after a network failure — never reuse it across distinct charge attempts.
You must set step_up: SUPPORTED on every on-demand charge — i.e. every time the customer is present at the moment of charge. Without it, Klarna cannot trigger step-up even when it would otherwise approve the charge with one, and you will see avoidable declines. Klarna still decides whether step-up actually runs based on the current request — your job is to be ready to handle either outcome on the same flow.
The step-up response carries fraud_status: REJECTED and an error_code — this is the API contract for step-up signaling, not a final decline. The presence of step_up_id is the only signal that matters: when it is present, continue to Step 4. When it is absent on a non-200 response, treat the response as a final failure.
When the response contains step_up_id, your backend creates a fresh Klarna Payments session referencing that step_up_id and the customer token. Call create session with the same cart that you used in Step 2 and the same intent you used when the token was created (typically buy_and_tokenize).
On the same frontend surface where the customer was already confirming the purchase, initialize the SDK with the client_token and call Klarna.Payments.authorize. The SDK takes over: it presents the Klarna Purchase Journey and lets the customer authenticate or pick an alternative Klarna payment method.
The Klarna Purchase Journey is the surface where the customer completes step-up — sign-in, OTP entry, or picking an alternative Klarna payment method. The Klarna Payments SDK launches it inline (or as a redirect on devices where inline is not possible).
If the customer is declined inside the Purchase Journey, the SDK callback returns approved: false. Return the customer to the checkout surface so they can choose another payment method — do not retry the same charge silently.
Klarna Purchase Journey — Confirm and pay (step-up)
The merchant_urls.authorization callback is mandatory and authoritative. When the customer completes step-up, Klarna POSTs the authorization_token to your registered server-side callback URL — and that is the source you must use to drive createOrder. The SDK callback (res.authorization_token) is a complementary low-latency signal you can use to update UI immediately, but it is not reliable on its own: closed tabs, network interruptions, ad blockers, and browser sandboxing can all drop it.
Callback request from Klarna
HTTP
1
2
3
4
5
6
7
POST https://example.com/authorization_callbacks
Content-Type: application/json
{
"authorization_token": "1eddf502-f3a0-45bf-b1fd-f2e3a2758200",
"session_id": "e4b81ca2-0aae-4c16-bcb2-29a0a088a35b"
}
Callback contract you must implement
Aspect
Requirement
Transport
HTTPS endpoint registered on merchant_urls.authorization.
Timeout
2 s connection + 2 s read — return a 2xx response within this window.
Acknowledgement
Any 2xx response (e.g. 204 No Content) means "received".
Retries on non-2xx
Klarna retries up to 3 times with exponential backoff starting at 1 s.
Delivery semantics
At-least-once. The same authorization_token may arrive multiple times (retries, or in parallel with the SDK callback). Your handler must be idempotent — drive createOrder exactly once per token.
Token lifetime
authorization_token is valid for 60 minutes — call createOrder from the handler promptly.
Authentication
Do not require auth on the URL. To verify origin, embed a one-time secret in the URL query string (e.g. ?secretToken=…) generated per session.
Multiple authorizations
If the first createOrder attempt does not succeed and the customer re-authorizes, Klarna may send a new callback with a different authorization_token. Always use the latest token.
Your merchant_urls.authorization endpoint receives a POST from Klarna with the authorization_token once the customer completes step-up. From that handler, call create order on /payments/v1/authorizations/{authorizationToken}/order with the same cart you used in Step 2. Klarna creates the order, and the existing customer token is updated with the funding source the customer just confirmed in step-up — future on-demand charges on this token use the updated funding source.
Store order_id, fulfill the order, and surface confirmation to the customer. The customer token is updated with the funding source confirmed during step-up — future on-demand charges use this funding source.
Set step_up: SUPPORTED on every on-demand charge — Klarna decides whether to run step-up.
Treat the step-up response as a final failure — step_up_id means continue, not stop.
Load the Klarna Payments SDK wherever step-up may run, before you call createOrder.
Lazy-load the SDK after the charge response — it must be ready when step_up_id arrives.
Pass step_up_id, customer_token, and the same cart and intent into createCreditSession.
Change the cart between Step 2 and Step 4 — the customer confirmed Step 2's cart.
Drive createOrder from the merchant_urls.authorization server-side callback — that is the authoritative source of authorization_token.
Rely on the SDK callback (res.authorization_token) as your only path — closed tabs, network drops, and ad blockers can kill it.
Use the SDK callback as a complementary signal to update UI immediately (e.g. show a spinner).
Place the order from the frontend by forwarding res.authorization_token from the SDK to the backend — race conditions and dropped callbacks will produce missed orders.
Generate a unique Klarna-Idempotency-Key per charge attempt and reuse it only on retry of the same attempt.
Reuse an idempotency key across distinct charge attempts.
Return the customer to the checkout surface when step-up is declined so they can pick another payment method.
Silently retry the same charge after a step-up decline.