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

# useBuyModal

> Hook for managing the buy modal interface for collectible purchases

## Import

```typescript theme={null}
import { useBuyModal } from "@0xsequence/marketplace-sdk/react";
```

## Usage

<Note>
  Make sure you have followed the [Getting
  Started](https://docs.sequence.xyz/sdk/web/marketplace-sdk/getting-started) guide
  to get the collection address and chainId.
</Note>

### Examples

<Tabs>
  <Tab title="Market Purchase">
    Example of implementing a market purchase (secondary sales) using the `useBuyModal` hook:

    <Note>
      This example uses the [`useLowestListing`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useLowestListing) hook from marketplace-sdk. If there is no lowestListing with the given parameters, it means there is no orderId available, and therefore the item cannot be bought.
    </Note>

    <Steps>
      <Step title="Setup handler component with marketplace config validation">
        First, create a main component that handles marketplace configuration loading and validation:

        ```typescript theme={null}
        import {
          useBuyModal,
          useLowestListing,
          useMarketplaceConfig,
        } from '@0xsequence/marketplace-sdk/react';
        import type { Address } from 'viem';

        function MarketPurchaseExample() {
          const { data: marketplaceConfig, isLoading: isMarketplaceConfigLoading } =
            useMarketplaceConfig();

          // Handle loading states
          if (isMarketplaceConfigLoading) {
            return <div style={{ padding: '20px' }}>Loading marketplace config...</div>;
          }

          if (!marketplaceConfig) {
            return (
              <div style={{ padding: '20px' }}>No marketplace config available</div>
            );
          }

          const collection = marketplaceConfig.market.collections[0];

          if (!collection) {
            return <div style={{ padding: '20px' }}>No collections available</div>;
          }

          const chainId = collection.chainId;
          const collectionAddress = collection.itemsAddress as Address;

          return (
            <MarketPurchase
              chainId={chainId}
              collectionAddress={collectionAddress}
              collectibleId="0"
            />
          );
        }
        ```
      </Step>

      <Step title="Create market purchase component">
        Next, create the actual market purchase component that uses properly validated data:

        ```typescript theme={null}
        interface MarketPurchaseProps {
          chainId: number;
          collectionAddress: Address;
          collectibleId: string;
        }

        function MarketPurchase({
          chainId,
          collectionAddress,
          collectibleId,
        }: MarketPurchaseProps) {
          const {
            data: lowestListing,
            isLoading: isLoadingLowestListing,
            isError: isErrorLowestListing,
          } = useLowestListing({
            collectionAddress,
            chainId,
            tokenId: collectibleId,
          });

          const { show: showMarketModal } = useBuyModal({
            onSuccess: ({ hash, orderId }) => {
              console.log('Market purchase successful', { hash, orderId });
            },
            onError: (error) => {
              console.error('Market purchase failed:', error.message);
            },
          });

          const handleMarketBuy = () => {
            if (!lowestListing || isLoadingLowestListing) return;

            showMarketModal({
              chainId,
              collectionAddress,
              collectibleId,
              orderId: lowestListing.orderId,
              marketplace: lowestListing.marketplace,
            });
          };

          if (isLoadingLowestListing) {
            return <div style={{ padding: '20px' }}>Loading listing...</div>;
          }

          if (isErrorLowestListing || !lowestListing) {
            return (
              <div style={{ padding: '20px' }}>
                Error loading listing or no listing found
              </div>
            );
          }

          return (
            <div style={{ padding: '20px' }}>
              <h3>Market Purchase</h3>

              <p>Price: ${lowestListing.priceUSDFormatted}</p>

              <button
                type="button"
                onClick={handleMarketBuy}
                disabled={isLoadingLowestListing || isErrorLowestListing}
              >
                Buy from Market
              </button>
            </div>
          );
        }
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Shop Purchase">
    Example of implementing a shop purchase (primary sales) using the `useBuyModal` hook:

    <Note>
      This example uses the [`useListPrimarySaleItems`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useListPrimarySaleItems) hook from marketplace-sdk. The hook fetches primary sale items from a specific contract. If there is no primarySaleItem with the given parameters or if the supply is 0, the item cannot be bought.
    </Note>

    <Steps>
      <Step title="Setup handler component with marketplace config validation">
        First, create a main component that handles marketplace configuration loading and validation:

        ```typescript theme={null}
        import {
          useBuyModal,
          useListPrimarySaleItems,
          useMarketplaceConfig,
        } from '@0xsequence/marketplace-sdk/react';
        import type { Address } from 'viem';

        function ShopPurchaseExample() {
          const { data: marketplaceConfig, isLoading: isMarketplaceConfigLoading } =
            useMarketplaceConfig();

          // Handle loading states
          if (isMarketplaceConfigLoading) {
            return <div style={{ padding: '20px' }}>Loading marketplace config...</div>;
          }

          if (!marketplaceConfig) {
            return (
              <div style={{ padding: '20px' }}>No marketplace config available</div>
            );
          }

          const collection = marketplaceConfig.shop.collections[0];

          if (!collection) {
            return <div style={{ padding: '20px' }}>No shop collections available</div>;
          }

          const chainId = collection.chainId;
          const collectionAddress = collection.itemsAddress as Address;
          const saleContractAddress = collection.saleAddress as Address;

          return (
            <ShopPurchase
              chainId={chainId}
              collectionAddress={collectionAddress}
              saleContractAddress={saleContractAddress}
              collectibleId="0"
            />
          );
        }
        ```
      </Step>

      <Step title="Create shop purchase component">
        Next, create the actual shop purchase component that uses properly validated data:

        ```typescript theme={null}
        interface ShopPurchaseProps {
          chainId: number;
          collectionAddress: Address;
          saleContractAddress: Address;
          collectibleId: string;
        }

        function ShopPurchase({
          chainId,
          collectionAddress,
          saleContractAddress,
          collectibleId,
        }: ShopPurchaseProps) {
          const { show: showBuyModal } = useBuyModal({
            onSuccess: ({ hash }) => {
              console.log('Shop purchase successful', { hash });
            },
            onError: (error) => {
              console.error('Shop purchase failed:', error.message);
            },
          });

          // Fetch primary sale items
          const { data: primarySaleItems, isLoading: isLoadingPrimarySale } = useListPrimarySaleItems({
            chainId,
            primarySaleContractAddress: saleContractAddress,
            filter: {
              includeEmpty: true,
            },
          });

          const primarySaleItem =
            primarySaleItems?.pages[0]?.primarySaleItems[0]?.primarySaleItem;

          const handleShopBuy = () => {
            if (!primarySaleItem) return;

            showBuyModal({
              chainId,
              collectionAddress,
              salesContractAddress: saleContractAddress,
              cardType: 'shop',
              quantityDecimals: 0,
              quantityRemaining: Number(primarySaleItem.supply),
              items: [
                {
                  tokenId: collectibleId,
                  quantity: '1',
                },
              ],
              salePrice: {
                amount: primarySaleItem.priceAmount ?? '0',
                currencyAddress: (primarySaleItem.currencyAddress as Address) ?? '0x',
              },
            });
          };

          if (isLoadingPrimarySale) {
            return <div style={{ padding: '20px' }}>Loading primary sale items...</div>;
          }

          if (!primarySaleItem) {
            return (
              <div style={{ padding: '20px' }}>No primary sale items available</div>
            );
          }

          return (
            <div style={{ padding: '20px' }}>
              <h3>Shop Purchase</h3>

              <p>Available: {primarySaleItem.supply ?? 0}</p>

              <button
                type="button"
                onClick={handleShopBuy}
                disabled={!primarySaleItem || Number(primarySaleItem.supply) === 0}
              >
                Buy from Shop
              </button>
            </div>
          );
        }
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

## Parameters

The hook accepts an optional `callbacks` object with the following properties:

```typescript theme={null}
interface ModalCallbacks {
  onSuccess?: ({ hash, orderId }: { hash?: Hash; orderId?: string }) => void;
  onError?: (error: Error) => void;
  successActionButtons?: Array<{ label: string; action: () => void }>;
}
```

| Parameter                        | Type                                                             | Description                                                                |
| -------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `callbacks.onSuccess`            | `({ hash, orderId }: { hash?: Hash; orderId?: string }) => void` | Optional callback function called when the purchase is successful          |
| `callbacks.onError`              | `(error: Error) => void`                                         | Optional callback function called when an error occurs during the purchase |
| `callbacks.successActionButtons` | `Array<{ label: string; action: () => void }>`                   | Optional array of action buttons to show on success                        |

## Return Type

The hook returns an object with the following methods:

```typescript theme={null}
{
  show: (args: BuyModalProps) => void
  close: () => void
}
```

### Methods

#### show

`(args: BuyModalProps) => void`

Opens the buy modal with the specified parameters. The `BuyModalProps` can be either `ShopBuyModalProps` or `MarketplaceBuyModalProps` depending on the purchase type.

For market purchases (Secondary sales):

```typescript theme={null}
interface MarketplaceBuyModalProps extends BuyModalBaseProps {
  marketplaceType?: "market";
  collectibleId: string;
  marketplace: MarketplaceKind;
  orderId: string;
}
```

For shop purchases (Primary sales):

```typescript theme={null}
interface ShopBuyModalProps extends BuyModalBaseProps {
  marketplaceType: "shop";
  salesContractAddress: Address;
  items: Array<Partial<CheckoutOptionsItem> & { tokenId?: string }>;
  quantityDecimals: number;
  quantityRemaining: number;
  salePrice: {
    amount: string;
    currencyAddress: Address;
  };
  unlimitedSupply?: boolean;
}
```

Both types extend from `BuyModalBaseProps`:

```typescript theme={null}
interface BuyModalBaseProps {
  chainId: number;
  collectionAddress: Address;
  skipNativeBalanceCheck?: boolean;
  nativeTokenAddress?: Address;
  marketplaceType?: MarketplaceType;
  customCreditCardProviderCallback?: (buyStep: Step) => void;
  successActionButtons?: Array<{ label: string; action: () => void }>;
}
```

#### close

`() => void`

Closes the buy modal.

## Notes

The `useBuyModal` hook provides a convenient way to manage the buy modal interface for collectible purchases. It handles:

* Opening and closing the modal
* Managing the purchase flow state
* Error handling and success callbacks
* Support for both primary and secondary sales
