Tokenization has failed - An unknown error has occurred

I’m trying to include a basic card payment option in my Vue JS app and keep running into the issue of failed tokenization with an unknown error. I did my best to “translate” the web-payments-quickstart project from GitHub to fit into my Vue JS project but I must’ve made a mistake I cannot find.

Here is my code:

<script>
export default {
  name: 'payment',
  data() {
    return {
      appId: 'sandbox-sq0idb-bub0FOKgPJgECKJ5OSrZPg',
      locationId: 'LE56BBNQJRGDY',
      payments: null,
      card: null
    }
  },
  async mounted() {
    if (!window.Square) {
          throw new Error('Square.js failed to load properly');
        }
    
    // Initialize Payment
    try {
      this.payments = window.Square.payments(this.appId, this.locationId);
      // console.log(this.payments)
    } catch {
      const statusContainer = document.getElementById(
        'payment-status-container'
      );
      statusContainer.className = 'missing-credentials';
      statusContainer.style.visibility = 'visible';
      return;
    }

    // Initialize Card
    try {
          this.card = await this.initializeCard(this.payments);
        } catch (e) {
          console.error('Initializing Card failed', e);
          return;
        }

    // const cardButton = document.getElementById('card-button');
    // cardButton.addEventListener('click', async function (event) {
    //   await this.handlePaymentMethodSubmission(event, this.card);
    // });
  },
  methods: {
    async initializeCard(payments) {
        const card = await payments.card();
        await card.attach('#card-container');

        return card;
      },

      async createPayment(token) {
        let locationId = this.locationId
        const body = JSON.stringify({
          locationId,
          sourceId: token,
        });

        let url = CONST.URLS.ReservationUrls.CreatePayment(token,this.reservationCode);
          const paymentResponse = await fetch(url, {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
            },
            body,
          });

        if (paymentResponse.ok) {
          return paymentResponse.json();
        }

        const errorBody = await paymentResponse.text();
        throw new Error(errorBody);
      },

      async tokenize(paymentMethod) {
        console.log(this.card)
        const tokenResult = await paymentMethod.tokenize();
        if (tokenResult.status === 'OK') {
          return tokenResult.token;
        } else {
          let errorMessage = `Tokenization failed with status: ${tokenResult.status}`;
          if (tokenResult.errors) {
            errorMessage += ` and errors: ${JSON.stringify(
              tokenResult.errors
            )}`;
          }
          throw new Error(tokenResult);
        }
      },

      displayPaymentResults(status) {
        const statusContainer = document.getElementById(
          'payment-status-container'
        );
        if (status === 'SUCCESS') {
          statusContainer.classList.remove('is-failure');
          statusContainer.classList.add('is-success');
        } else {
          statusContainer.classList.remove('is-success');
          statusContainer.classList.add('is-failure');
        }

        statusContainer.style.visibility = 'visible';
      },

      async handlePaymentMethodSubmission(paymentMethod) {
          // event.preventDefault();
          // console.log(paymentMethod)
          const cardButton = document.getElementById('card-button');
          try {
            // disable the submit button as we await tokenization and make a payment request.
            cardButton.disabled = true;
            const token = await this.tokenize(paymentMethod);
            const paymentResults = await createPayment(token);
            this.displayPaymentResults('SUCCESS');

            console.debug('Payment Success', paymentResults);
          } catch (e) {
            cardButton.disabled = false;
            this.displayPaymentResults('FAILURE');
            console.error(e.message);
          }
        }
  }
}
</script>

And this is the corresponding HTML:

<template>
  <div>
    <form id="payment-form" @submit.prevent="this.handlePaymentMethodSubmission(this.card)">
        <div id="card-container"></div>
        <button id="card-button" type="submit">Pay $1.00</button>
      </form>
      <div id="payment-status-container"></div>
  </div>
</template>

Whenever there is a problem with tokenizing a card, the reason for the tokenization failure will be added to the X-pciBooking-Tokenization-Errors header. If the message contains more than 1 credit card detail to be tokenized, the X-pciBooking-Tokenization-Errors header will be formatted as double semi-colon separated value list where the location of the error message in the list will match the location of the card in the message.
The cards that were tokenized will be listed as a comma separated value list in the predefined header. The order of the tokens in this list will be in the order that the cards were located in the message.

For example, if there are three credit cards in the message, and the first and third one are correct but the second one is incorrect, the X-pciBooking-Tokenization-Errors header will look like this:
;;Luhn (Mod10) error;;

Regards,
Rachel Gomez