Charge customer-initiated on-demand purchases with the customer token using Klarna's Hosted Payment Page, 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 Hosted Payment Page (HPP) 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; you create an HPP session and redirect the customer to a Klarna-hosted page to complete step-up before returning to your success URL.
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
sequenceDiagram
autonumber
participant Customer
participant FE as Merchant Frontend
participant BE as Merchant Backend
participant HPP as Klarna HPP
participant Klarna as Klarna Payments API
Customer->>FE: Trigger on-demand purchase
FE->>BE: Submit confirmed cart
BE->>Klarna: createOrder on customer token (step_up: SUPPORTED)
alt No step-up required
Klarna->>BE: 200 + order_id
BE->>FE: Order confirmed
FE->>Customer: Confirmation
else Step-up required
Klarna->>BE: Response with step_up_id
BE->>Klarna: createCreditSession (step_up_id, customer_token, same cart)
Klarna->>BE: session_id
BE->>HPP: createHppSession (payment_session_url, merchant_urls, place_order_mode)
HPP->>BE: redirect_url
BE->>FE: redirect_url
FE->>Customer: Redirect to Klarna HPP
Customer->>HPP: Completes Klarna Purchase Journey (step-up)
alt place_order_mode = PLACE_ORDER / CAPTURE_ORDER
HPP->>Klarna: HPP places the order on behalf of merchant
HPP->>Customer: Redirect to merchant_urls.success with order_id
else place_order_mode = NONE
par Authoritative path (mandatory)
Klarna-->>BE: POST authorization_token to merchant_urls.authorization
and Complementary path
HPP->>Customer: Redirect to merchant_urls.success?token=… in URL
Customer->>FE: Lands on success URL (UX signal)
end
BE->>Klarna: createOrder (authorization_token from server-side callback)
Klarna->>BE: 200 + order_id
end
Note over Klarna: Customer token updated with confirmed funding source
BE->>FE: Order confirmed
FE->>Customer: Confirmation
end
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.
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.
Klarna needs additional customer interaction. Continue with Steps 4–7 to create a step-up session, redirect the customer to HPP, and complete the charge.
Other 4xx
error_code, error_messages, correlation_id
Return the customer to the checkout surface and surface a clear failure message. See validations in Klarna Payments for code-by-code handling.
5xx
Transient error
Retry with the same Klarna-Idempotency-Key. Do not generate a new key on retry.
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).
Call create HPP session with payment_session_url pointing to the Klarna Payments session created in Step 4, your merchant_urls, and the place_order_mode that matches your integration.
place_order_mode
What HPP does after the customer completes step-up
PLACE_ORDER
HPP places the order on your behalf and redirects the customer to merchant_urls.success with order_id in the query string. No further API call from you.
CAPTURE_ORDER
Same as PLACE_ORDER, plus HPP triggers capture immediately. Use when you do not need a separate capture step.
NONE
HPP redirects the customer to merchant_urls.success with authorization_token in the query string. You then call createOrder with the authorization_token in Step 7.
Pick PLACE_ORDER (or CAPTURE_ORDER) when you want HPP to finalize the order and you do not need to run additional checks between authorization and order creation. Pick NONE when you need to validate the customer or cart server-side before placing the order.
Send the customer to the HPP redirect_url. The customer authenticates on Klarna's hosted page, completes the step-up, and is redirected back to your merchant_urls.success URL when they are done. If they stop the flow, they go to merchant_urls.cancel instead.
The Klarna Purchase Journey is the surface where the customer completes step-up — sign-in, OTP entry, or picking an alternative Klarna payment method. With HPP, this happens on a Klarna-hosted page that the customer reaches via your redirect_url.
Track the HPP session status using HPP webhooks on your status_update URL or by polling, so you do not depend solely on the customer landing on your success URL.
If the customer is declined inside the Purchase Journey, HPP redirects them to merchant_urls.failure. Return them to the checkout surface to pick another payment method — do not retry the same charge silently.
Klarna Purchase Journey — Confirm and pay (step-up)
What you do here depends on the place_order_mode you set in Step 5.
place_order_mode
What to do
PLACE_ORDER or CAPTURE_ORDER
The order is already created. The customer lands at merchant_urls.success with order_id in the query string. Fulfill the order. No further API call from you.
NONE
Drive order creation from the merchant_urls.authorization server-side callback — Klarna POSTs authorization_token to that URL once step-up completes. From the callback handler, call create order on /payments/v1/authorizations/{authorizationToken}/order with the same cart. The ?token=… parameter on the customer's success redirect is a complementary UX signal; do not rely on it as your only path.
The merchant_urls.authorization callback is mandatory and authoritative in place_order_mode = NONE. Klarna POSTs the authorization_token to your registered server-side callback URL once step-up completes — and that is the source you must use to drive createOrder. The token included in the merchant_urls.success redirect is a low-latency UX signal you can use to update the page state, but customers may close the tab, drop network on the redirect hop, or be blocked by browser sandboxing. The server-side callback is delivered regardless.
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 HPP success redirect). 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.
On success, the 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.
Configure merchant_urls.authorization on the Klarna Payments session (Step 4) and drive createOrder from that server-side callback in place_order_mode = NONE.
Read authorization_token from the merchant_urls.success query string and drive createOrder from the browser — closed tabs and dropped redirects will produce missed orders.
Configure HPP merchant_urls (back, cancel, error, failure, success, status_update) and subscribe to HPP webhooks on status_update.
Rely solely on the customer landing on merchant_urls.success — also use webhooks.
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.
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.
Pick place_order_mode based on whether you need server-side validation before order creation.
Mix place_order_mode = PLACE_ORDER with a custom createOrder call — HPP already placed the order.
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.