Klarna Web SDK v2
    Preparing search index...

    Interface KlarnaPayment

    The Klarna Payment interface provides access to the payment request API.

    Accepting a payment using the Klarna Payment button:

    label="Example"

    const klarna = ...;

    // Handle payment request completion
    klarna.Payment.on("complete", async (paymentRequest) => {
    await fetch("https://example.com/my-backend", {
    method: 'POST',
    body: JSON.stringify({
    klarnaNetworkSessionToken: paymentRequest.stateContext.klarnaNetworkSessionToken
    }),
    });
    });

    // Implement the initiate function to create a payment request.
    klarna.Payment.button({
    initiate: () => {
    return {
    currency: "USD",
    amount: 1000
    },
    }
    }).mount("#button-container");
    <!-- Make sure to provide a container element for the button -->
    <div id="button-container"></div>
    interface KlarnaPayment {
        button(config: KlarnaPaymentButtonConfig): KlarnaPaymentButton;
        cancel(paymentRequestId: string): Promise<PaymentRequest>;
        fetch(paymentRequestUrl: string): Promise<PaymentRequest>;
        initiate(
            data: InitiateLegacyCallback | InitiateCallback,
            options?: PaymentRequestOptions,
        ): Promise<PaymentRequest | undefined>;
        off(event: string, callback: Function): void;
        on(event: "complete", callback: OnCompleteCallback): void;
        on(event: "error", callback: OnErrorCallback): void;
        on(event: "abort", callback: OnAbortCallback): void;
        on(event: "redirect", callback: OnRedirectCallback): void;
        on(event: "overlayopen", callback: OnOverlayOpenCallback): void;
        on(event: "overlayclose", callback: OnOverlayCloseCallback): void;
        on(
            event: "shippingaddresschange",
            callback: ShippingAddressChangeCallback,
        ): void;
        on(
            event: "shippingoptionselect",
            callback: ShippingOptionSelectCallback,
        ): void;
        presentation(data: PaymentPresentationData): Promise<PaymentPresentation>;
    }
    Index
    • Parameters

      Returns KlarnaPaymentButton

      "Creates a Klarna payment button that handles the customer flow. You provide an initiate callback that returns either a paymentRequestUrl (created server-side) or PaymentRequestData (created client-side), and Klarna takes care of launching the purchase flow.

      Register event handlers (complete, error, abort) before mounting the button so that all events are captured from the first interaction."

      label="Example"

      // 1. Register event handlers first
      klarna.Payment.on("complete", async (paymentRequest) => {
      console.log("Payment completed:", paymentRequest.state);
      });

      klarna.Payment.on("error", async (error) => {
      console.error("Payment error:", error);
      });

      // 2. Create and mount the button
      klarna.Payment.button({
      initiate: async ({ klarnaNetworkSessionToken }) => {
      // Create the payment request on your server
      const response = await fetch("/api/create-payment-request", {
      method: "POST",
      body: JSON.stringify({ klarnaNetworkSessionToken }),
      });
      const { paymentRequestUrl } = await response.json();

      return { paymentRequestUrl };
      },
      }).mount("#klarna-button-container");

      Payment

      Payment.button

      Payment

      general-availability

      Payment.button

      true

      true

    • Parameters

      • paymentRequestId: string

      Returns Promise<PaymentRequest>

      "Cancels the payment request with the given ID. It's only possible to cancel payment requests created by the same client/credentials.

      Pass the payment request URL received from the payment request creation response.

      Use this when the customer clears their cart, starts a new checkout session, or you otherwise need to invalidate an in-progress payment request."

      label="Example"

      // Cancel an existing payment request when the customer empties their cart
      const cancelledRequest = await klarna.Payment.cancel("kr_payment_req_123");
      console.log("Payment request cancelled, state:", cancelledRequest.state);

      Sub-Partners should not cancel payment requests owned by the Acquiring Partner. This method will be removed in a future release.

      Payment

      Payment.cancel

      Payment

      deprecated

      Payment.cancel

      true

      true

    • Parameters

      • paymentRequestUrl: string

      Returns Promise<PaymentRequest>

      "Fetches the current state of a payment request. It's only possible to fetch payment requests created by the same client/credentials.

      Pass the payment request URL received from the payment request creation response.

      This is useful in redirect flows where the customer returns to your site and you need to check the payment request state to determine the outcome."

      label="Example"

      // Fetch by payment request Url
      const paymentRequest = await klarna.Payment.fetch("https://pay.klarna.com/l/...");

      if (paymentRequest.state === "COMPLETED") {
      const token = paymentRequest.stateContext?.klarnaNetworkSessionToken;
      // Send the token to your backend for authorization
      await authorizePayment(token);
      } else if (paymentRequest.state === "DECLINED") {
      console.error("Payment declined:", paymentRequest.stateReason);
      }

      Payment

      Payment.fetch

      Payment

      general-availability

      Payment.fetch

      true

      true

    • Returns Promise<PaymentRequest | undefined>

      "Initiates a payment with Klarna. Use this method only if you absolutely need to own your button. Otherwise, use the {@docs-portal-link Payment.button} method. If you use this method along with initiationMode of DEVICE_BEST or ON_PAGE, it has to be called right after the button is clicked. If there are long running operations such as network requests, you can do that within the callback."

      label="Example"

      // Prefer Payment.button() — it handles click timing and popup blockers automatically.
      // Use initiate() only if you need full control over your own button.
      // Call initiate immediately after a click event.
      // Move network requests inside the callback to avoid browser popup blockers.
      let isInitiating = false;

      // Suppose "payWithKlarnaButton" is your checkout button
      payWithKlarnaButton.addEventListener('click', async () => {
      if (isInitiating) {
      return;
      }

      try {
      isInitiating = true;
      payWithKlarnaButton.disabled = true;

      await klarna.Payment.initiate(async ({ klarnaNetworkSessionToken }) => {
      // Do network requests inside the callback.
      // The klarnaNetworkSessionToken can optionally be sent to your backend
      // for server-side payment request creation.
      const paymentData = await createPaymentSession(klarnaNetworkSessionToken);

      return {
      currency: "USD",
      amount: paymentData.amount,
      customerInteractionConfig: {
      returnUrl: "https://example.com/success",
      },
      };
      }, {
      initiationMode: "DEVICE_BEST",
      });
      } catch (error) {
      console.error('Payment initiation failed:', error);
      } finally {
      isInitiating = false;
      payWithKlarnaButton.disabled = false;
      }
      });

      Payment

      Payment.initiate

      Payment

      general-availability

      Payment.initiate

      true

      true

    • Parameters

      • event: string
      • callback: Function

      Returns void

      "Unregister an event handler for the given event. Pass the same function reference that was used when registering with on(). This is useful for cleanup when your component unmounts or when you need to swap handlers."

      label="Example"

      // Keep a reference to the handler so it can be removed later
      const onComplete = async (paymentRequest) => {
      await handleCompletion(paymentRequest);
      return true;
      };

      // Register
      klarna.Payment.on("complete", onComplete);

      // Later, unregister (e.g. on component unmount)
      klarna.Payment.off("complete", onComplete);

      Payment

      Payment.off

      Payment

      general-availability

      Payment.off

      true

      true

    • Parameters

      Returns void

      "Register an event handler for the complete event. A payment request is completed when the customer has approved the purchase.

      During a redirection flow the complete handler will trigger once your page has loaded on the success page. Pending updates are triggered even if the event handler is registered after the page has loaded to avoid the need for polling.

      Return false from the callback to prevent automatic redirection to the returnUrl (e.g. if you want to show a custom confirmation screen). Return true and Klarna navigates to the returnUrl, emitting the redirect event first if you registered a handler for it. The complete handler always runs before that redirect."

      label="Example"

      klarna.Payment.on("complete", async (paymentRequest) => {
      const token = paymentRequest.stateContext?.klarnaNetworkSessionToken;

      // Send the token to your backend for authorization
      await fetch("https://example.com/api/authorize", {
      method: "POST",
      body: JSON.stringify({ klarnaNetworkSessionToken: token }),
      });

      // Return false to prevent automatic redirection to returnUrl
      return false;
      });

      Payment

      Payment.onComplete

      Payment

      general-availability

      Payment.onComplete

      true

      true

    • Parameters

      Returns void

      "Register an event handler for the error event. The handler is called when initiate() (including a click on the payment button), fetch() or cancel() fails. The same error is still thrown, or the returned promise rejected, after the handler has been called, so try/catch around your own calls keeps working. A failed click on the payment button has no caller to catch the error, so this handler is the only place to handle it.

      The handler is not called when the customer closes the payment window before finishing, which is a cancellation rather than an error, or for presentation(), which falls back to a default presentation when the backend call fails and rejects when required input such as currency is missing.

      The error parameter may be a PaymentError (with structured errorCode and errorMessage fields) or a generic Error."

      label="Example"

      klarna.Payment.on("error", async (error, paymentRequest) => {
      if ("errorCode" in error) {
      // Structured PaymentError
      console.error(`Payment error [${error.errorCode}]: ${error.errorMessage}`);
      } else {
      // Generic Error
      console.error("Unexpected error:", error.message);
      }

      if (paymentRequest) {
      console.log("Payment request state:", paymentRequest.state);
      }
      });

      Payment

      Payment.onError

      Payment

      general-availability

      Payment.onError

      true

      true

    • Parameters

      Returns void

      "Register an event handler for the abort event. This fires when the customer cancels the payment request by closing the popup or otherwise stopping the process. This is distinct from {@docs-portal-link Payment.cancel}, which is initiated programmatically by the integrator."

      label="Example"

      klarna.Payment.on("abort", async (paymentRequest) => {
      console.log("Payment aborted, reason:", paymentRequest?.stateReason);
      // Re-enable the checkout button so the customer can try again
      enableCheckoutButton();
      });

      Payment

      Payment.onAbort

      Payment

      general-availability

      Payment.onAbort

      true

      true

    • Parameters

      Returns void

      "Register an event handler for the redirect event. Klarna emits it before it navigates the browsing context that loaded the SDK: to launch the purchase journey as a redirect (phones, tablets and in-app browsers), when your initiate callback resolves with a returnUrl, and after a journey that ran in a pop-up or inside the page completes and Klarna navigates to the return URL. The handler receives the redirectUrl the customer has to be sent to.

      Resolve true to let Klarna navigate the browsing context that loaded the SDK. Resolve false to take the navigation over yourself, for example when the SDK runs inside an iframe and the top-level page has to navigate. If no handler is registered, Klarna navigates the browsing context that loaded the SDK.

      After a completed purchase, the complete handler always runs first, so you can read the payment request, including its token, before any navigation. If the complete handler resolves false, Klarna doesn't navigate to the return URL and doesn't emit redirect. If it resolves true, Klarna emits redirect with the return URL before navigating.

      Register the handler before mounting the {@docs-portal-link Payment.button} or calling {@docs-portal-link Payment.initiate}."

      label="Example"

      // Inside a framed checkout page: hand the navigation to the parent page.
      // At the top level, register no handler, so Klarna navigates the page itself.
      if (window.parent !== window) {
      klarna.Payment.on("redirect", async ({ redirectUrl }) => {
      window.parent.postMessage(
      { type: "klarna:flow-redirect", redirectUrl },
      "https://partner.example.com"
      );

      // Return false so Klarna doesn't navigate the iframe
      return false;
      });
      }

      Payment

      Payment.onRedirect

      Payment

      gated

      Payment.onRedirect

      true

      true

    • Parameters

      Returns void

      "Register a handler for the overlayopen event. Klarna emits it on the Payment namespace right before flow interaction mode draws anything over the page for a payment-initiated flow: the backdrop behind the Klarna pop-up, the backdrop shown when the browser blocks the pop-up, or the in-page fallback iframe. This includes the payment button and links rendered through {@docs-portal-link Payment.presentation} such as Check your purchase power.

      Register the handler before mounting {@docs-portal-link Payment.button} or calling {@docs-portal-link Payment.presentation}. If you also mount {@docs-portal-link Messaging.placement} in the same framed page, register the same handler on {@docs-portal-link Messaging.onOverlayOpen} for placement-driven overlays, and count the overlays that are open: a Messaging overlay can open while a Payment overlay is still fading out."

      label="Example"

      // Inside a framed checkout page. One count covers the overlays of both namespaces.
      let openOverlays = 0;

      const onOverlayOpen = () => {
      openOverlays += 1;
      if (openOverlays > 1) return;
      pinKlarnaContainer();
      window.parent.postMessage({ type: "klarna:flow-open" }, "https://partner.example.com");
      };

      if (window.parent !== window) {
      klarna.Payment.on("overlayopen", onOverlayOpen);
      // If the page also mounts Messaging.placement (MESSAGING in products):
      // klarna.Messaging.on("overlayopen", onOverlayOpen);
      }

      Payment

      Payment.onOverlayOpen

      Payment

      gated

      Payment.onOverlayOpen

      true

      true

    • Parameters

      Returns void

      "Register a handler for the overlayclose event. Klarna emits it on the Payment namespace after flow interaction mode removes the backdrop or in-page fallback iframe for a payment-initiated flow. The event may fire before a redirect navigation completes while the document is still alive, and may not fire if the browsing context is torn down first.

      It has no fixed order relative to complete and abort. With initiationMode ON_PAGE and the journey in the Klarna pop-up, the backdrop stays after the pop-up closes until Klarna has confirmed the outcome, so overlayclose fires after them. With POPUP, or when the journey runs in the in-page fallback iframe, Klarna starts removing the overlay when the journey ends and confirms the outcome at the same time, so either can come first. Restore a resized iframe on overlayclose, not on complete.

      Register the handler before mounting {@docs-portal-link Payment.button} or calling {@docs-portal-link Payment.presentation}. If you also mount {@docs-portal-link Messaging.placement} in the same framed page, register the same handler on {@docs-portal-link Messaging.onOverlayClose} for placement-driven overlays, and restore a resized iframe only once every open overlay has closed."

      label="Example"

      // Inside a framed checkout page. openOverlays is the count from the overlayopen example
      // (let openOverlays = 0), which adds one for each overlay that opens.
      const onOverlayClose = () => {
      if (openOverlays === 0) return;
      openOverlays -= 1;
      if (openOverlays > 0) return;
      unpinKlarnaContainer();
      window.parent.postMessage({ type: "klarna:flow-close" }, "https://partner.example.com");
      };

      if (window.parent !== window) {
      klarna.Payment.on("overlayclose", onOverlayClose);
      // If the page also mounts Messaging.placement (MESSAGING in products):
      // klarna.Messaging.on("overlayclose", onOverlayClose);
      }

      Payment

      Payment.onOverlayClose

      Payment

      gated

      Payment.onOverlayClose

      true

      true

    • Parameters

      Returns void

      "The shipping address changed event handler is triggered when the customer changes their shipping address during the payment flow. If the shipping address is present in the customer account, the event will be triggered immediately after the customer has logged in. Here, you are given the opportunity to accept or reject the shipping address.

      If you did not return anything during the 10 seconds after receiving this event, the customer will see the error screen and payment request will be aborted."

      label="Example"

      klarna.Payment.on("shippingaddresschange", (paymentRequest, shippingAddress) => {
      // 1. Accept — return a list of shipping options.
      // The customer will be prompted to select one.
      if (canShipTo(shippingAddress)) {
      return {
      shippingOptions: [
      {
      shippingOptionReference: "standard",
      amount: 500,
      displayName: "Standard Shipping",
      description: "3-5 business days",
      },
      {
      shippingOptionReference: "express",
      amount: 1500,
      displayName: "Express Shipping",
      description: "1-2 business days",
      shippingType: "EXPRESS",
      },
      ],
      // 2. Accept with preselection — return selectedShippingOptionReference along
      // with updated amount and lineItems to skip the selection screen.
      amount: totalWithShipping,
      lineItems: [
      ...lineItems,
      { name: "Standard Shipping", quantity: 1, totalAmount: 500 },
      ],
      selectedShippingOptionReference: "standard",
      };
      }

      // 3. Reject — return a rejectionReason to prompt the customer for a new address.
      // Available reasons: POSTAL_CODE_NOT_SUPPORTED, CITY_NOT_SUPPORTED,
      // REGION_NOT_SUPPORTED, COUNTRY_NOT_SUPPORTED, ADDRESS_NOT_SUPPORTED.
      return {
      rejectionReason: "COUNTRY_NOT_SUPPORTED",
      };
      });

      Payment

      Payment.onShippingAddressChange

      Payment

      general-availability

      Payment.onShippingAddressChange

      true

      true

    • Parameters

      Returns void

      "The shipping option selected event handler is triggered when the customer selects a shipping option during the payment flow. Here, you are given the opportunity to accept or reject the shipping option.

      If you did not return anything during the 10 seconds after receiving this event, the customer will see the error screen and payment request will be aborted."

      label="Example"

      klarna.Payment.on("shippingoptionselect", async (paymentRequest, shippingOption) => {
      // 1. Accept — return the updated order payload with the selected shipping
      // cost added to amount and lineItems.
      if (isValidOption(shippingOption)) {
      const { amount } = await fetch("/cart", {
      method: "POST",
      body: JSON.stringify({ shipping_option: shippingOption }),
      });

      return {
      amount,
      lineItems: [
      ...lineItems,
      { name: "Shipping", quantity: 1, totalAmount: 500 },
      ],
      };
      }

      // 2. Reject — return a rejectionReason to prompt the customer to select
      // a different option. Available reasons: INVALID_OPTION.
      return {
      rejectionReason: "INVALID_OPTION",
      };
      });

      Payment

      Payment.onShippingOptionSelect

      Payment

      general-availability

      Payment.onShippingOptionSelect

      true

      true

    • Parameters

      Returns Promise<PaymentPresentation>

      "Returns instructions on how Klarna should be presented in the payment selector and UI components to render. Use the instruction field to determine whether Klarna should be shown, preselected, shown exclusively, or hidden. Then mount the returned UI components (icon, header, subheader, message, and paymentButton) into your checkout page. The paymentButton is the component the customer clicks to start the Klarna purchase flow."

      label="Example"

      // Fetch the presentation, handle the instruction, and mount Klarna UI components.
      const paymentPresentation = await klarna.Payment.presentation({
      amount: 11800,
      currency: "USD",
      locale: "en-US",
      intent: "PAY",
      });

      if (paymentPresentation) {
      switch (paymentPresentation.instruction) {
      case "SHOW_KLARNA":
      renderKlarnaOption(paymentPresentation);
      break;
      case "PRESELECT_KLARNA":
      renderKlarnaOption(paymentPresentation);
      break;
      case "SHOW_ONLY_KLARNA":
      document.getElementById("other-payment-methods")?.remove();
      renderKlarnaOption(paymentPresentation);
      break;
      case "HIDE_KLARNA":
      document.getElementById("klarna-option")?.remove();
      break;
      default:
      renderKlarnaOption(paymentPresentation);
      break;
      }
      }

      function renderKlarnaOption(paymentPresentation) {
      const klarnaContainer = document.getElementById("klarna-option");

      if (!klarnaContainer) {
      return;
      }

      const { paymentOption } = paymentPresentation;
      if (!paymentOption) {
      return;
      }

      klarnaContainer.innerHTML = `
      <div id="klarna-icon-container"></div>
      <div id="klarna-header-container"></div>
      <div id="klarna-subheader-container"></div>
      <div id="klarna-message-container"></div>
      <div id="klarna-button-container"></div>
      `;

      // Mount Klarna UI components
      paymentOption.icon
      .component({ shape: "badge" })
      .mount("#klarna-icon-container");

      paymentOption.header
      .component()
      .mount("#klarna-header-container");

      paymentOption.subheader
      .component()
      .mount("#klarna-subheader-container");

      if (paymentOption.message) {
      paymentOption.message
      .component()
      .mount("#klarna-message-container");
      }

      // Mount the payment button — the customer clicks this to start the Klarna flow
      paymentOption.paymentButton
      .component({
      initiate: async ({ klarnaNetworkSessionToken, paymentOptionId }) => {
      const response = await fetch("/api/create-payment-request", {
      method: "POST",
      body: JSON.stringify({ klarnaNetworkSessionToken, paymentOptionId }),
      });
      const { paymentRequestUrl } = await response.json();
      return { paymentRequestUrl };
      },
      })
      .mount("#klarna-button-container");
      }

      Payment

      Payment.presentation

      Payment

      general-availability

      Payment.presentation

      true

      true