alt
Unzer

Checkout flow documentation

Learn about different checkout flow options, submit handling, and form validation behavior when integrating UI components v2.

To simplify the integration, you can use the <unzer-checkout> custom web component. This tag encapsulates core functionality needed to manage the checkout process efficiently.

icon

At a minimum, <unzer-checkout> should be used with a checkout button as its immediate child.

If you’re using a custom button, it’s important that the button supports the disabled property. This allows <unzer-checkout> to dynamically control the button’s state based on the current status of the checkout form. For example:

myButton.disabled = true; // should disable the button
myButton.disabled = false; // should enable the button

If the disabled property is not present or supported, <unzer-checkout> will not be able to control the button’s interactivity.

<unzer-checkout id='unzer-checkout'>
    <button type="submit">Pay</button>
</unzer-checkout>

Manual control

If you prefer to implement your own logic for enabling or disabling the checkout button, you can pass the manualCheckoutButtonControl attribute to the tag. In this mode, <unzer-checkout> will dispatch events to indicate when the button should be enabled or disabled, allowing you to implement your own logic and criteria for managing the button state.

<unzer-payment
        id="unzer-payment"
        publicKey="s-pub-xyz"
        locale="de-DE">
    <unzer-card></unzer-card>
</unzer-payment>
<unzer-checkout id='unzer-checkout' manualCheckoutButtonControl>
    <button type="submit">Pay</button>
</unzer-checkout>
Promise.all([
  customElements.whenDefined("unzer-payment"),
  customElements.whenDefined("unzer-checkout"),
  customElements.whenDefined("unzer-card"),
])
  .then(() => {
    const unzerCheckout = document.getElementById("unzer-checkout");
    const unzerPayment = document.getElementById("unzer-payment");
    unzerPayment.addEventListener("stateChanged", (event) => {
        const enableCheckout = event.detail.enableCheckout;
        // Add custom logic here and apply the button state
    });
  })
  .catch((error) => {
    /* Handle loading and initialization error */
  })

If you prefer not to use <unzer-checkout> at all, events will be dispatched in a similar manner

<unzer-payment
        id="unzer-payment"
        publicKey="s-pub-xyz"
        locale="de-DE">
    <unzer-card></unzer-card>
</unzer-payment>
<div>
    <button type="submit">Pay</button>
</div>
Promise.all([
  customElements.whenDefined("unzer-payment"),
  customElements.whenDefined("unzer-card"),
])
  .then(() => {
    const unzerCheckout = document.getElementById("unzer-checkout");
    const unzerPayment = document.getElementById("unzer-payment");
    unzerPayment.addEventListener("stateChanged", (event) => {
        const enableCheckout = event.detail.enableCheckout;
        // Add custom logic here and apply the button state
  })
  .catch((error) => {
    /* Handle loading and initialization error */
  })

Custom checkout flow

For more information on checkout flow customization please see Integrate UI without the unzer-checkout component

Integrate UI without the unzer-checkout component

Learn how to integrate UI components v2 without using the <unzer-checkout> component for maximum control over the payment flow.

Overview

While the <unzer-checkout> component provides a simplified integration experience, you can also integrate UI components v2 without it for more control over the payment flow, custom validation, and event handling.

Basic integration structure

<unzer-payment
  id="unzer-payment"
  publicKey="s-pub-xyz"
  locale="de-DE">
    <!-- ... Here you will need to add the Unzer payment type tag, so the form UI elements will be inserted -->
    <!--    e.g <unzer-paylater-invoice></unzer-paylater-invoice> -->
    <p>Shipping Information</p>
    <unzer-shipping-address></unzer-shipping-address>

    <p>Billing Information</p>
    <unzer-billing-address></unzer-billing-address>

    <button type="submit" id="yourPaymentButtonId">Pay</button>
</unzer-payment>
Promise.all([
  customElements.whenDefined("unzer-payment"),
  customElements.whenDefined("unzer-klarna"),
])
  .then(() => {
    const unzerPayment = document.getElementById("unzer-payment");
    const submitButton = document.getElementById("yourPaymentButtonId");

    // Event listeners for payment component
    unzerPayment.addEventListener("typeCreated", (event) => {
      const typeId = event.detail.id;
      const typeData = event.detail.data;
      console.log("Payment type created:", typeId);
      console.log("Payment type data:", typeData);
      
      // Send typeId to your server for payment processing
    });

    // Handle submit button click
    submitButton.addEventListener("click", async (event) => {
      event.preventDefault();
      
      try {
        const response = await unzerPayment.submit();
        console.log("Submit response:", response);
        
        if (response.submitResponse && response.submitResponse.success) {
          const typeId = response.submitResponse.data.id;
          console.log("Payment type ID:", typeId);
          
          // Process payment on server
        } else {
          console.error("Submit failed:", response);
          console.error("Payment submission failed");
        }
      } catch (error) {
        console.error("Submit error:", error);
        console.error("An error occurred during payment submission");
      }
    });
  })
  .catch((error) => {
    console.error("Initialization error:", error);
    console.error("Failed to initialize payment components");
  });

Key differences from checkout component

  1. Manual submit handling: You call unzerPayment.submit() directly instead of relying on the checkout component
  2. Event-driven architecture: You listen to events emitted by the payment component
  3. Custom validation handling: You manage form validation state manually
  4. Flexible UI control: You have full control over the submit button and user interface
  5. Direct response handling: You handle the submit response directly without the checkout component’s abstraction

Benefits of non-checkout integration

  • Full control: Complete control over the payment flow and user interface
  • Custom validation: Implement your own validation logic and error handling
  • Flexible styling: No constraints from the checkout component’s styling
  • Event-driven: React to specific events as they occur
  • Integration flexibility: Easier to integrate with existing forms and workflows
  • Shop system compatibility: Better integration with shop systems where submit button handling is not under your control

Submit payment without checkout component

When not using the <unzer-checkout> component, you need to manually handle the submit process and event handling.

Manual submit handling

Instead of using <unzer-checkout>, you can call the submit() method directly on the <unzer-payment> element:

const unzerPayment = document.getElementById("unzer-payment");
const submitButton = document.getElementById("yourPaymentButtonId");

submitButton.addEventListener("click", async (event) => {
  const response = await unzerPayment.submit();
  console.log("response: ", response);
  if (response.submitResponse) {
    console.log("submit response: ", response.submitResponse);
  }
});

Getting payment type ID

After successful submission, you can access the payment type ID from the response:

const response = await unzerPayment.submit();
if (response.submitResponse && response.submitResponse.success) {
  const typeId = response.submitResponse.data.id;
  // Use typeId for server-side payment processing
  console.log("Payment type ID:", typeId);
}

Form validation behavior

Important: Unzer form validation is automatically triggered only when you call the submit() method. It is not possible to manually trigger Unzer’s built-in validation outside of the submit process.

However, you can implement your own additional validation logic before calling submit():

const unzerPayment = document.getElementById("unzer-payment");
const submitButton = document.getElementById("yourPaymentButtonId");

submitButton.addEventListener("click", async (event) => {
  // Your custom validation logic
  if (validateCustomFields()) {
    // Only call submit() if your validation passes
    const response = await unzerPayment.submit();
    // Handle response...
  } else {
    // Handle validation errors
    console.log("Custom validation failed");
  }
});

function validateCustomFields() {
  // Implement your custom validation logic here
  // Return true if validation passes, false otherwise
  return true;
}

This approach allows you to:

  • Perform custom validation before Unzer validation
  • Control when the submit process starts
  • Handle validation errors according to your application’s needs
  • Integrate with existing form validation frameworks