> ## Documentation Index
> Fetch the complete documentation index at: https://primer.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# createVaultManager

```ts TS theme={"dark"}
createVaultManager(): HeadlessVaultManager
```

Get an instance of `HeadlessVaultManager`, which can be used to:

* [fetch a list](/sdk/web/v2.x.x/primer-headless-checkout/methods/createVaultManager#param-fetch-vaulted-payment-methods) of vaulted payment methods for the `customerId` attached to the [client session](/api-reference/v2.4/api-reference/client-session-api/create-a-client-session#body-customer-id)
* [delete](#param-delete-vaulted-payment-method) a vaulted payment method for the `customerId` attached to the [client session](/api-reference/v2.4/api-reference/client-session-api/create-a-client-session#body-customer-id)
* [perform a payment](#param-start-payment-flow) using a vaulted payment method
* [create an input to collect the CVV](#param-create-cvv-input) for a vaulted payment method

Example:

```ts TS theme={"dark"}
// Headless Checkout initialisation
const headless = await Primer.createHeadless(clientToken, {
  onAvailablePaymentMethodsLoad: () => {
    // create your UI for displaying payment methods
  },
  container: "#checkout-container",
});
await headless.start();

// Headless Vault Manager initialisation
const vaultManager = headless.createVaultManager();
```

## Returns

An instance of `HeadlessVaultManager`.

<Expandable title="HeadlessVaultManager" defaultOpen>
  <ResponseField name="fetchVaultedPaymentMethods" type="() => Promise<VaultedPaymentMethod[]>">
    Get a list of `VaultedPaymentMethod` for the `customerId` attached to the [client session](/api-reference/v2.4/api-reference/client-session-api/create-a-client-session#body-customer-id).
    Build your own UI to display, manage and perform payments with them.

    <Warning>
      The list of vaulted payment methods is not affected by the checkout builder's conditions.
      For example, if you configured the checkout builder to not show `Paypal` with the current client session,
      but `Paypal` was vaulted previously, `fetchVaultedPaymentMethods` will still return it.

      This issue will be addressed and resolved in an upcoming release.
    </Warning>

    ```ts TS theme={"dark"}
    // Initialise Headless Checkout ...

    const vaultManager = headless.createVaultManager();
    const vaultedPaymentMethods = await vaultManager.fetchVaultedPaymentMethods();
    ```

    Throws an error if the call to retrieve the vaulted payment methods fails.

    <Expandable title="VaultedPaymentMethod">
      <ResponseField name="id" type="string">
        A *temporary* identifier for the vaulted payment method. You should use this id with [deleteVaultedPaymentMethod](#param-delete-vaulted-payment-method), and [startPaymentFlow](#param-start-payment-flow).

        ℹ️ This id changes with each call to [fetchVaultedPaymentMethods](#param-fetch-vaulted-payment-methods).
      </ResponseField>

      <ResponseField name="analyticsId" type="string">
        An identifier for the vaulted payment method that doesn't change across calls to [fetchVaultedPaymentMethods](#param-fetch-vaulted-payment-methods).
      </ResponseField>

      <ResponseField name="paymentInstrumentData" type="object">
        Data associated to the payment instrument. You can use this information to display the vaulted payment method in your UI.

        As an example, for a vaulted card, you will receive:

        ```ts TS theme={"dark"}
        {
            "first6Digits": "411111",
            "last4Digits": "1111",
            "expirationMonth": "05",
            "expirationYear": "2030",
            "cardholderName": "Primer Test",
            "network": "VISA",
            "binData": {
                "network": "VISA",
                "issuerCountryCode": "US",
                "issuerName": "TEST BANK, N.A.",
                "regionalRestriction": "UNKNOWN",
                "accountNumberType": "UNKNOWN",
                "accountFundingType": "UNKNOWN",
                "prepaidReloadableIndicator": "NOT_APPLICABLE",
                "productUsageType": "UNKNOWN",
                "productCode": "UNKNOWN",
                "productName": "UNKNOWN"
            },
            "isNetworkTokenized": false
        }
        ```
      </ResponseField>

      <ResponseField name="paymentInstrumentType" type="string">
        The type of the payment instrument associated to the vaulted payment method.

        Examples of possible values (new values could be added as we add new payment methods):

        * `APPLE_PAY`
        * `CARD_OFF_SESSION_PAYMENT`
        * `GOOGLE_PAY`
        * `KLARNA_CUSTOMER_TOKEN`
        * `OFF_SESSION_PAYMENT`
        * `PAYMENT_CARD`
        * `PAYPAL_BILLING_AGREEMENT`
        * `PAYPAL_ORDER`
      </ResponseField>

      <ResponseField name="threeDSecureAuthentication" type="Nullable<ThreeDSAuthenticationData>">
        The 3DS authentication data for the vaulted payment method.
      </ResponseField>

      <ResponseField name="userDescription" type="Optional<string>">
        User-provided description for the vaulted payment method.
      </ResponseField>
    </Expandable>
  </ResponseField>

  <ResponseField name="deleteVaultedPaymentMethod" type="(vaultedPaymentMethodId: string) => Promise<void>">
    Delete a vaulted payment method by id for the `customerId` attached to the [client session](/api-reference/v2.4/api-reference/client-session-api/create-a-client-session#body-customer-id).

    You can get the id from any instance of [VaultedPaymentMethod](#param-fetch-vaulted-payment-methods) returned by [fetchVaultedPaymentMethods](#param-fetch-vaulted-payment-methods).

    ```ts TS theme={"dark"}
    // Initialise Headless Checkout ...

    const vaultManager = headless.createVaultManager();
    const vaultedPaymentMethods = await vaultManager.fetchVaultedPaymentMethods();
    // Delete the first vaulted payment method
    try {
      await vaultManager.deleteVaultedPaymentMethod(vaultedPaymentMethods[0]?.id);
    } catch (error) {
      // handle errors
    }
    ```

    Throws an error if the id passed does not match any payment method previously retrieved by [fetchVaultedPaymentMethods](#param-fetch-vaulted-payment-methods).

    Throws an error if the call to delete the vaulted payment method fails.

    <Expandable title="VaultedPaymentMethod">
      <ResponseField name="id" type="string">
        A *temporary* identifier for the vaulted payment method. You should use this id with [deleteVaultedPaymentMethod](#param-delete-vaulted-payment-method), and [startPaymentFlow](#param-start-payment-flow).

        ℹ️ This id changes with each call to [fetchVaultedPaymentMethods](#param-fetch-vaulted-payment-methods).
      </ResponseField>

      <ResponseField name="analyticsId" type="string">
        An identifier for the vaulted payment method that doesn't change across calls to [fetchVaultedPaymentMethods](#param-fetch-vaulted-payment-methods).
      </ResponseField>

      <ResponseField name="paymentInstrumentData" type="object">
        Data associated to the payment instrument. You can use this information to display the vaulted payment method in your UI.

        As an example, for a vaulted card, you will receive:

        ```ts TS theme={"dark"}
        {
            "first6Digits": "411111",
            "last4Digits": "1111",
            "expirationMonth": "05",
            "expirationYear": "2030",
            "cardholderName": "Primer Test",
            "network": "VISA",
            "binData": {
                "network": "VISA",
                "issuerCountryCode": "US",
                "issuerName": "TEST BANK, N.A.",
                "regionalRestriction": "UNKNOWN",
                "accountNumberType": "UNKNOWN",
                "accountFundingType": "UNKNOWN",
                "prepaidReloadableIndicator": "NOT_APPLICABLE",
                "productUsageType": "UNKNOWN",
                "productCode": "UNKNOWN",
                "productName": "UNKNOWN"
            },
            "isNetworkTokenized": false
        }
        ```
      </ResponseField>

      <ResponseField name="paymentInstrumentType" type="string">
        The type of the payment instrument associated to the vaulted payment method.

        Examples of possible values (new values could be added as we add new payment methods):

        * `APPLE_PAY`
        * `CARD_OFF_SESSION_PAYMENT`
        * `GOOGLE_PAY`
        * `KLARNA_CUSTOMER_TOKEN`
        * `OFF_SESSION_PAYMENT`
        * `PAYMENT_CARD`
        * `PAYPAL_BILLING_AGREEMENT`
        * `PAYPAL_ORDER`
      </ResponseField>

      <ResponseField name="threeDSecureAuthentication" type="Nullable<ThreeDSAuthenticationData>">
        The 3DS authentication data for the vaulted payment method.
      </ResponseField>

      <ResponseField name="userDescription" type="Optional<string>">
        User-provided description for the vaulted payment method.
      </ResponseField>
    </Expandable>
  </ResponseField>

  <ResponseField name="startPaymentFlow" type="(vaultedPaymentMethodId: string) => Promise<void>">
    Starts the payment flow. You should pass as a parameter the `id` of a [VaultedPaymentMethod](#param-fetch-vaulted-payment-methods) previously retrieved with [fetchVaultedPaymentMethods](#param-fetch-vaulted-payment-methods).

    Upon a successful invocation of this function, the SDK will automatically trigger the standard payment [callbacks](/checkout/headless#configure-headless-universal-checkout).

    ```ts TS theme={"dark"}
    // Initialise Headless Checkout ...

    const vaultManager = headless.createVaultManager();

    const vaultedPaymentMethods = await vaultManager.fetchVaultedPaymentMethods();
    // Start the payment flow using the first vaulted payment method
    try {
      await vaultManager.startPaymentFlow(vaultedPaymentMethods[0]?.id);
    } catch (error) {
      // handle errors
    }
    ```

    Throws an error if the id passed does not match any payment method previously retrieved by [fetchVaultedPaymentMethods](#headlessvaultmanager.deleteVaultedPaymentMethod).

    Throws an error if the `paymentInstrumentType` in the vaulted payment method passed in is not recognised.

    <Expandable title="VaultedPaymentMethod">
      <ResponseField name="id" type="string">
        A *temporary* identifier for the vaulted payment method. You should use this id with [deleteVaultedPaymentMethod](#param-delete-vaulted-payment-method), and [startPaymentFlow](#param-start-payment-flow).

        ℹ️ This id changes with each call to [fetchVaultedPaymentMethods](#param-fetch-vaulted-payment-methods).
      </ResponseField>

      <ResponseField name="analyticsId" type="string">
        An identifier for the vaulted payment method that doesn't change across calls to [fetchVaultedPaymentMethods](#param-fetch-vaulted-payment-methods).
      </ResponseField>

      <ResponseField name="paymentInstrumentData" type="object">
        Data associated to the payment instrument. You can use this information to display the vaulted payment method in your UI.

        As an example, for a vaulted card, you will receive:

        ```ts TS theme={"dark"}
        {
            "first6Digits": "411111",
            "last4Digits": "1111",
            "expirationMonth": "05",
            "expirationYear": "2030",
            "cardholderName": "Primer Test",
            "network": "VISA",
            "binData": {
                "network": "VISA",
                "issuerCountryCode": "US",
                "issuerName": "TEST BANK, N.A.",
                "regionalRestriction": "UNKNOWN",
                "accountNumberType": "UNKNOWN",
                "accountFundingType": "UNKNOWN",
                "prepaidReloadableIndicator": "NOT_APPLICABLE",
                "productUsageType": "UNKNOWN",
                "productCode": "UNKNOWN",
                "productName": "UNKNOWN"
            },
            "isNetworkTokenized": false
        }
        ```
      </ResponseField>

      <ResponseField name="paymentInstrumentType" type="string">
        The type of the payment instrument associated to the vaulted payment method.

        Examples of possible values (new values could be added as we add new payment methods):

        * `APPLE_PAY`
        * `CARD_OFF_SESSION_PAYMENT`
        * `GOOGLE_PAY`
        * `KLARNA_CUSTOMER_TOKEN`
        * `OFF_SESSION_PAYMENT`
        * `PAYMENT_CARD`
        * `PAYPAL_BILLING_AGREEMENT`
        * `PAYPAL_ORDER`
      </ResponseField>

      <ResponseField name="threeDSecureAuthentication" type="Nullable<ThreeDSAuthenticationData>">
        The 3DS authentication data for the vaulted payment method.
      </ResponseField>

      <ResponseField name="userDescription" type="Optional<string>">
        User-provided description for the vaulted payment method.
      </ResponseField>
    </Expandable>
  </ResponseField>

  <ResponseField name="createCvvInput" type="(options: CardSecurityCodeInputOptions) => Promise<CvvInput | null>">
    Create a `CvvInput` that can be used to safely pass the secure code associated to a vaulted card to Primer's backend.

    For security reasons, the input is rendered in an iframe on Primer's domain and you won't be able to access programmatically the value stored in the input.

    ```ts TS theme={"dark"}
    const vaultManager = headless.createVaultManager();

    // ... retrieve payment methods with fetchVaultedPaymentMethods

    const cvvInput = await vaultManager.createCvvInput({
      cardNetwork: vaultedPaymentMethod.paymentInstrumentData.network,
      container: "#foo",
      name: "cvv",
      style,
      placeholder: "123",
    });

    // Somewhere else in your code, create a `submitButton` to start the payment
    // and a `cvvError` container to show validation errors

    submitButton.onclick = () => {
      // use metadata to show error messages
      cvvError.innerText = cvvInput.metadata.error ?? "";
      // don't start the payment flow if the `CVVInput` is in an invalid state
      if (cvvInput.metadata.error) return;
      try {
        vaultManager.startPaymentFlow(vaultedPaymentMethod.id, {
          cvv: cvvInput.valueToken,
        });
      } catch (error) {
        // handle errors
      }
    };
    ```

    ##### Parameters:

    <Expandable title="CardSecurityCodeInputOptions">
      <ResponseField name="container" type="string">
        A CSS selector that identifies the container where the `CvvInput` will be appended. If the `container` is not found and the `CVVInput` cannot be mounted, the Promise returned by `createCVVInput` is resolved with `null` and an error message is logged to the developer's console.
      </ResponseField>

      <ResponseField name="ariaLabel" type="Optional<string>">
        The `aria-label` attribute for the input element wrapped by `CvvInput`.
      </ResponseField>

      <ResponseField name="id" type="Optional<string>">
        The `id` attribute that will be assigned to the `HTMLIFrameElement` used by `CvvInput`.
      </ResponseField>

      <ResponseField name="name" type="Optional<string>">
        An optional `name` attribute for the input element wrapped by `CvvInput`.

        The name you provide will always be prefixed with `cvv-`, so if for example you pass `name: 'custom'` the `CVVInput` will wrap an `HTMLInputElement` that looks like this:

        ```ts TS theme={"dark"}
        <input name="cvv-custom" /* Other attributes */ />
        ```
      </ResponseField>

      <ResponseField name="placeholder" type="Optional<string>">
        The `placeholder` attribute for the input element wrapped by `CvvInput`.
      </ResponseField>

      <ResponseField name="placement" type="Optional<'append' | 'prepend'>">
        Whether to `append` or `prepend` the `CvvInput` to its container.
      </ResponseField>

      <ResponseField name="properties" type="Optional<Object>">
        Additional attributes that can be applied to the `HTMLInputElement` wrapped by `CvvInput`.

        Any attribute that would be valid on an `<input>` can be used here, however:

        * `name` is taken directly from the `CardSecurityCodeInputOptions` options
        * `maxLength` and `minLength` will be inferred from the `cardNetwork`
        * type is always set to `tel` to provide a good UX when typing on a virtual keyboard
        * for security reasons event handlers such as `onkeydown`, `onkeyup` won't be serialized and passed down to the input

        You can pass other attributes such as `data-*`, `aria-*`...
      </ResponseField>

      <ResponseField name="style" type="Optional<CheckoutStyle>">
        A [CheckoutStyle](/sdk/web/v2.x.x/checkout-style/Overview) object that will be applied to the input element.
      </ResponseField>

      <ResponseField name="cardNetwork" type="Optional<string>">
        The card network to determine the length of the field for CVV validation.

        You should pass the `paymentInstrumentData.network` attribute on any of the [VaultedPaymentMethod](#param-fetch-vaulted-payment-methods)s returned by [fetchVaultedPaymentMethods](#param-fetch-vaulted-payment-methods).

        If you don't pass a `cardNetwork` or the SDK cannot recognize the card network passed in, it will raise a warning and will default the validation of the CVV to a minimum length of 3 and a maximum length of 4.
      </ResponseField>
    </Expandable>

    ##### Returns:

    <Expandable title="CvvInput">
      <ResponseField name="valueToken" type="string">
        The `valueToken` representing the actual CVV value not accessible for security reasons.

        You can forward the token to `HeadlessVaultManager.startPaymentFlow` as the `cvv` parameter and under the hood it will be replaced with the value entered by the user.

        You can also access the `valueToken` and be informed of when it changes using `addListener('change', listener)`.

        ```ts TS theme={"dark"}
        // use `metadata` to check for validation errors
        if (cvvInput.metadata.error) {
          // display errors, don't start the payment flow
          return;
        }
        try {
          vaultManager.startPaymentFlow(vaultedPaymentMethod.id, {
            cvv: cvvInput.valueToken,
          });
        } catch (error) {
          // Handle startPaymentFlow errors
        }
        ```
      </ResponseField>

      <ResponseField name="addListener" type="(event: 'change' | 'focus' | 'blur', listener: Function) => Function">
        Add a listener for one of the supported events (`change`, `focus` and `blur`) and return a function that can be called without arguments to remove the listener.

        `focus` and `blur` listeners do not receive any arguments.

        `change` listeners receive the following arguments:

        * `valueToken`: a string representing the actual CVV value not accessible for security reasons
        * `metadata`: additional details on the state of the input field wrapped by the CvvInput.

        Both `valueToken` and `metadata` can be also accessed directly on an instance of `CvvInput` (`cvvInput.valueToken`, `cvvInput.metadata`)
      </ResponseField>

      <ResponseField name="addEventListener" type="(event: 'change' | 'focus' | 'blur', listener: Function) => Function">
        Alias of
        [addListener](#param-add-listener)
      </ResponseField>

      <ResponseField name="removeListener" type="(event: 'change' | 'focus' | 'blur', listener: Function) => void">
        Removes a listener previously added with `addListener`. You should pass as parameters the exact same parameters passed to `addListener`.

        Alternatively, you can just use the function returned by `addListener`.

        Note: if you try to add a listener for an event that can't be handled, `addListener` will not add it and it will return `undefined` instead of a function to remove it.
      </ResponseField>

      <ResponseField name="focus" type="() => void">
        Give focus to the `HTMLInputElement` wrapped by `CvvInput`.
      </ResponseField>

      <ResponseField name="blur" type="() => void">
        Remove focus from the `HTMLInputElement` wrapped by `CvvInput`.
      </ResponseField>

      <ResponseField name="remove" type="() => void">
        Removes the `CvvInput` field from the DOM and detaches all event listeners previously added with `addListener`.
      </ResponseField>

      {" "}

      <ResponseField name="frame" type="HTMLIFrameElement">
        A reference to the `HTMLIFrameElement` wrapping the input.
      </ResponseField>

      <ResponseField name="metadata" type="object">
        Additional details on the state of the input field wrapped by the `CvvInput`.

        <Expandable title="InputMetadata">
          <ResponseField name="error" type="&#x22;cvvRequired&#x22; | &#x22;cvvIncomplete&#x22; | null">
            A label describing validation errors, `null` if the input value has no validation errors.
          </ResponseField>

          <ResponseField name="valid" type="boolean">
            True if the input value has no validation errors.
          </ResponseField>

          <ResponseField name="active" type="boolean">
            True if the input is focused.
          </ResponseField>

          <ResponseField name="dirty" type="boolean">
            True if the input value is different from the initial.
          </ResponseField>

          <ResponseField name="touched" type="boolean">
            True if the input has been touched once.
          </ResponseField>
        </Expandable>
      </ResponseField>

      <ResponseField name="name" type="string">
        The `name` attribute of the underlying `HTMLInputElement` field.
      </ResponseField>
    </Expandable>

    ##### Errors:

    If the `container` passed in the parameters is not found and the `CVVInput` cannot be mounted, the promise is resolved with `null` and an error message is logged to the developer's console.

    ##### Example:

    Wrap a `CvvInput` in a React component using `addListener('change', listener)`:

    ```ts TS theme={"dark"}
    const CvvInput = ({ onChange }) => {
      useEffect(() => {
        const cvvInput = headless.createCvvInput({
          cardNetwork: vaultedPaymentMethod.paymentInstrumentData.network,
          container: "#foo",
          name: "cvv",
          style,
          placeholder: "123",
        });
        cvvInput.addListener("change", onChange);
      }, []);

      return <div id="foo" />;
    };
    ```

    ```ts TS theme={"dark"}
    const CardForm = () => {
      const vaultManager = useVaultManager();
      const selectedVaultedPaymentMethod = useSelectedVaultedPaymentMethod();

      const [cvv, setCvv] = useState("");

      return (
        <div>
          <CvvInput onChange={(value) => setCvv(value)} />
          <SubmitButton
            onClick={() =>
              vaultManager.startPaymentFlow(vaultedPaymentMethod.id, { cvv })
            }
          />
        </div>
      );
    };
    ```
  </ResponseField>
</Expandable>

## Throws

* Throws an error if a `customer.customerId` is not provided in the [client session](/api-reference/v2.4/api-reference/client-session-api/create-a-client-session#body-customer-id)
* Throws an error if the Headless Instance was not [started](/sdk/web/v2.x.x/primer-headless-checkout/methods/start)
