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

# SDK API Reference (React)

> Complete API documentation for TagadaPay Plugin SDK v2

# SDK API Reference for React

<CardGroup cols={2}>
  <Card title="Latest Version" icon="tag">
    **v2.7.14** - Complete TypeScript documentation
  </Card>

  <Card title="Framework" icon="react">
    **React SDK** - Hooks-based API for React 18+
  </Card>
</CardGroup>

Complete API documentation for all hooks, components, and utilities in the TagadaPay Plugin SDK v2.

<Note>
  **React is Required**: This API reference covers the React-based TagadaPay Plugin SDK v2
  (`@tagadapay/plugin-sdk/v2`). All hooks and components require React 18+. For V1 docs, see the legacy
  documentation.
</Note>

## Quick Navigation

<CardGroup cols={3}>
  <Card title="Query Hooks" icon="database" href="#query-hooks">
    TanStack Query hooks for data fetching
  </Card>

  <Card title="Mutation Hooks" icon="edit" href="#mutation-hooks">
    Hooks for data updates
  </Card>

  <Card title="Utility Hooks" icon="wrench" href="#utility-hooks">
    Helper hooks for common tasks
  </Card>

  <Card title="Payment Hooks" icon="credit-card" href="#payment-hooks">
    Payment processing and 3DS
  </Card>

  <Card title="Location Hooks" icon="map-marker" href="#location-hooks">
    Address and geolocation
  </Card>

  <Card title="Components" icon="puzzle-piece" href="#components">
    Reusable React components
  </Card>
</CardGroup>

## Installation & Setup

```bash theme={null}
npm install @tagadapay/plugin-sdk
```

### Provider Setup

Wrap your app with `TagadaProvider`:

```tsx theme={null}
import { TagadaProvider } from '@tagadapay/plugin-sdk/v2';

export default function App() {
  return (
    <TagadaProvider>
      <YourPlugin />
    </TagadaProvider>
  );
}
```

## Query Hooks

### useCheckout()

Fetch and manage checkout data with automatic caching.

```tsx theme={null}
import { useCheckout } from '@tagadapay/plugin-sdk/v2';

function CheckoutPage() {
  const { data: checkout, isLoading, error, refetch } = useCheckout();

  if (isLoading) return <div>Loading checkout...</div>;
  if (error) return <div>Error loading checkout</div>;

  return (
    <div>
      <h1>Checkout</h1>
      <p>
        Total: {checkout.total} {checkout.currency}
      </p>
      <button onClick={() => refetch()}>Refresh</button>
    </div>
  );
}
```

**Returns:**

* `data`: Checkout object with all checkout data
* `isLoading`: Boolean loading state
* `error`: Error object if request failed
* `refetch()`: Function to manually refetch data
* `isFetching`: Boolean indicating background refetch

**Checkout Data Structure:**

```typescript theme={null}
interface CheckoutData {
  checkoutSession: {
    id: string;
    token: string;
    status: string;
  };
  items: CartItem[];
  total: number;
  currency: string;
  customer?: CustomerInfo;
  shipping?: ShippingInfo;
  payment?: PaymentInfo;
}
```

### useProducts()

Fetch product catalog with automatic caching.

```tsx theme={null}
import { useProducts } from '@tagadapay/plugin-sdk/v2';

function ProductCatalog() {
  const { data: products, isLoading } = useProducts();

  return (
    <div>
      {products?.map((product) => (
        <ProductCard key={product.id} product={product} />
      ))}
    </div>
  );
}
```

**Returns:**

* `data`: Array of product objects
* `isLoading`: Loading state
* `error`: Error state
* `refetch()`: Manual refetch function

### useOffer() <Tooltip tip="Deprecated — use usePreviewOffer instead">⚠️ Deprecated</Tooltip>

<Warning>
  **Deprecated.** Use [`usePreviewOffer()`](#usepreviewoffer) instead.
  `useOffer` (aliased from `useOfferQuery`) still works but is no longer the
  recommended hook for upsell pages. `usePreviewOffer` skips the upfront
  checkout-session round-trip, recomputes pricing client-side, and applies the
  CRM-configured MIT/CIT payment initiator automatically. `useOffer` will be
  removed in a future major version.
</Warning>

Single-offer hook that initializes a checkout session up front, exposes a
`payOffer()` mutation, and returns offer + line-item state. Kept exported as
`useOffer` (aliasing `useOfferQuery`) for backwards compatibility.

```tsx theme={null}
import { useOffer } from '@tagadapay/plugin-sdk/v2';

function LegacyUpsell({ offerId, mainOrderId }: { offerId: string; mainOrderId: string }) {
  const { offer, summary, payOffer, isPaying } = useOffer({ offerId, mainOrderId });

  return (
    <div>
      <h2>{offer?.name}</h2>
      <p>{summary?.totalAdjustedAmount} {summary?.currency}</p>
      <button onClick={() => payOffer(mainOrderId)} disabled={isPaying}>
        Accept
      </button>
    </div>
  );
}
```

New code should use [`usePreviewOffer()`](#usepreviewoffer) instead — same
single-offer shape, lighter footprint, automatic MIT/CIT pickup.

### usePreviewOffer()

Lightweight offer preview hook for post-checkout upsell pages. Fetches an offer
with a precomputed summary, lets the customer pick variants and quantities, and
recomputes totals client-side without round-tripping to the backend on every
change. Pay once the customer accepts.

```tsx theme={null}
import { usePreviewOffer } from '@tagadapay/plugin-sdk/v2';

function UpsellOffer({ offerId, mainOrderId }: { offerId: string; mainOrderId: string }) {
  const {
    offer,
    isLoading,
    summary,
    selections,
    selectVariant,
    updateQuantity,
    pay,
    isPaying,
  } = usePreviewOffer({ offerId });

  if (isLoading) return <div>Loading…</div>;

  const handleAccept = async () => {
    const { checkoutUrl } = await pay(mainOrderId);
    if (checkoutUrl) window.location.href = checkoutUrl;
  };

  return (
    <div>
      <h2>{offer?.name}</h2>
      <p>Total: {summary?.totalAdjustedAmount} {summary?.currency}</p>
      <button onClick={handleAccept} disabled={isPaying}>
        {isPaying ? 'Processing…' : 'Add to my order'}
      </button>
    </div>
  );
}
```

**Options**

| Name                | Type                                                | Description                                                                               |
| ------------------- | --------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `offerId`           | `string`                                            | The offer to preview. Required.                                                           |
| `currency`          | `string`                                            | Optional override. Defaults to the `?currency=` URL param or the funnel context currency. |
| `initialSelections` | `Record<string, { variantId; quantity; priceId? }>` | Pre-populate variant/quantity selections keyed by line-item id.                           |

**Returns**

| Name                                                                                    | Description                                                            |
| --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| `offer`                                                                                 | The raw offer object (or `null` while loading).                        |
| `summary`                                                                               | Computed pricing summary — items, totals, available variants per line. |
| `selections`                                                                            | Current per-line variant + quantity.                                   |
| `selectVariant(lineItemId, variantId)` / `selectVariantByProduct(productId, variantId)` | Change variant.                                                        |
| `updateQuantity(lineItemId, quantity)` / `updateQuantityByProduct(productId, quantity)` | Change quantity.                                                       |
| `getAvailableVariants(productId)`                                                       | List variants for a product including unit prices.                     |
| `pay(mainOrderId?, options?)`                                                           | Charge the customer's stored card and return `{ checkoutUrl }`.        |
| `toCheckout(mainOrderId?)`                                                              | Create a checkout session without paying.                              |
| `isLoading` / `isFetching` / `isPaying` / `error`                                       | Loading + error state.                                                 |

**MIT vs CIT auto-pickup**

`pay()` looks up `stepConfig.paymentInitiator` from the runtime
`window.__TGD_STEP_CONFIG__` injection and applies it automatically:

* `paymentInitiator: 'merchant'` (default) → **MIT**, sent to Stripe as
  `off_session: true`. No 3DS challenge, higher conversion.
* `paymentInitiator: 'customer'` → **CIT**, sent as
  `setup_future_usage: 'off_session'`. May trigger 3DS — useful when MITs are
  being declined by the issuer.

Merchants flip the toggle from the CRM step config; no plugin code change is
required. To override per call, pass `{ initiatedBy }`:

```tsx theme={null}
await pay(mainOrderId, { initiatedBy: 'customer' });
```

`OffersResource.payOffer()` and `OffersResource.payWithCheckoutSession()` use the
same auto-pickup. All three paths share `getAssignedPaymentInitiator()` under
the hood.

### usePromotions()

Fetch active promotions and campaigns.

```tsx theme={null}
import { usePromotions } from '@tagadapay/plugin-sdk/v2';

function PromotionsBanner() {
  const { data: promotions, isLoading } = usePromotions();

  return (
    <div>
      {promotions?.map((promo) => (
        <PromotionBadge key={promo.id} promotion={promo} />
      ))}
    </div>
  );
}
```

### useDiscounts()

Manage discount codes and validation.

```tsx theme={null}
import { useDiscounts } from '@tagadapay/plugin-sdk/v2';

function DiscountInput() {
  const { data: discounts, mutate: applyDiscount } = useDiscounts();

  const handleApply = (code: string) => {
    applyDiscount({ code });
  };

  return (
    <div>
      <input type="text" placeholder="Enter discount code" onBlur={(e) => handleApply(e.target.value)} />
      {discounts?.applied && <p>✅ Discount applied: {discounts.applied.code}</p>}
    </div>
  );
}
```

### useOrder()

Fetch order details.

```tsx theme={null}
import { useOrder } from '@tagadapay/plugin-sdk/v2';

function OrderDetails({ orderId }: { orderId: string }) {
  const { data: order, isLoading } = useOrder({ orderId });

  if (isLoading) return <div>Loading order...</div>;

  return (
    <div>
      <h2>Order #{order.id}</h2>
      <p>Status: {order.status}</p>
      <p>
        Total: {order.total} {order.currency}
      </p>
    </div>
  );
}
```

### useOrderBump()

Manage upsell offers (order bumps).

```tsx theme={null}
import { useOrderBump } from '@tagadapay/plugin-sdk/v2';

function OrderBumpSection() {
  const { data: orderBumps } = useOrderBump();

  return (
    <div>
      {orderBumps?.map((bump) => (
        <OrderBumpCard key={bump.id} orderBump={bump} />
      ))}
    </div>
  );
}
```

### useStoreConfig()

Access store configuration and settings.

```tsx theme={null}
import { useStoreConfig } from '@tagadapay/plugin-sdk/v2';

function StoreHeader() {
  const { data: config } = useStoreConfig();

  return (
    <header>
      <h1>{config?.storeName}</h1>
      <p>{config?.storeDescription}</p>
    </header>
  );
}
```

### useShippingRates()

Fetch available shipping options.

```tsx theme={null}
import { useShippingRates } from '@tagadapay/plugin-sdk/v2';

function ShippingSelector() {
  const { data: rates, isLoading } = useShippingRates();

  return (
    <div>
      {rates?.map((rate) => (
        <ShippingOption key={rate.id} rate={rate} />
      ))}
    </div>
  );
}
```

### usePostPurchases()

Fetch post-purchase offers.

```tsx theme={null}
import { usePostPurchases } from '@tagadapay/plugin-sdk/v2';

function PostPurchaseOffers() {
  const { data: offers } = usePostPurchases();

  return (
    <div>
      {offers?.map((offer) => (
        <PostPurchaseOffer key={offer.id} offer={offer} />
      ))}
    </div>
  );
}
```

### useVipOffers()

Fetch VIP exclusive offers.

```tsx theme={null}
import { useVipOffers } from '@tagadapay/plugin-sdk/v2';

function VipSection() {
  const { data: vipOffers } = useVipOffers();

  return (
    <div className="vip-section">
      <h2>VIP Exclusive Offers</h2>
      {vipOffers?.map((offer) => (
        <VipOfferCard key={offer.id} offer={offer} />
      ))}
    </div>
  );
}
```

### useClubOffers()

Manage subscription/club offers.

```tsx theme={null}
import { useClubOffers } from '@tagadapay/plugin-sdk/v2';

function ClubOffers() {
  const { data: clubOffers } = useClubOffers();

  return (
    <div>
      {clubOffers?.map((offer) => (
        <ClubOfferCard key={offer.id} offer={offer} />
      ))}
    </div>
  );
}
```

### useCustomerOrders()

Fetch customer order history.

```tsx theme={null}
import { useCustomerOrders } from '@tagadapay/plugin-sdk/v2';

function OrderHistory() {
  const { data: orders, isLoading } = useCustomerOrders();

  if (isLoading) return <div>Loading orders...</div>;

  return (
    <div>
      <h2>Order History</h2>
      {orders?.map((order) => (
        <OrderCard key={order.id} order={order} />
      ))}
    </div>
  );
}
```

### useCustomerSubscriptions()

Manage customer subscriptions.

```tsx theme={null}
import { useCustomerSubscriptions } from '@tagadapay/plugin-sdk/v2';

function Subscriptions() {
  const { data: subscriptions } = useCustomerSubscriptions();

  return (
    <div>
      {subscriptions?.map((sub) => (
        <SubscriptionCard key={sub.id} subscription={sub} />
      ))}
    </div>
  );
}
```

## Mutation Hooks

### useCheckout()

Manage checkout sessions with create, update, and payment capabilities.

```tsx theme={null}
import { useCheckout } from '@tagadapay/plugin-sdk/v2';

function CheckoutPage() {
  const { 
    checkout, 
    init,
    updateLineItems,
    updateCustomerAndSessionInfo,
    error 
  } = useCheckout({
    checkoutToken: '', // Empty if creating new checkout
  });

  // Initialize new checkout with items
  const handleCreateCheckout = async () => {
    await init({
      storeId: 'your-store-id',
      lineItems: [
        {
          variantId: 'variant_abc123',
          quantity: 1,
        },
      ],
    });
  };

  return <button onClick={handleCreateCheckout}>Create Checkout</button>;
}
```

**Parameters:**

* `checkoutToken`: String - Existing checkout token, or empty string to create new

**Returns:**

* `checkout`: Checkout session object
* `init()`: Function to create a new checkout session with line items
* `updateLineItems()`: Function to update cart items
* `updateCustomerAndSessionInfo()`: Function to update customer/shipping info
* `error`: Error object if any operation fails

<Tip>
  **Creating a checkout from scratch?** See the complete [Initialize Checkout guide](/developer-tools/sdk/init-checkout-example) for detailed examples including BOGO funnels, bundle selectors, and static resources.
</Tip>

***

### usePayment()

Process payments with automatic state management.

```tsx theme={null}
import { usePayment } from '@tagadapay/plugin-sdk/v2';

function PaymentForm() {
  const { mutate: processPayment, isPending, error } = usePayment();

  const handleSubmit = async (paymentData) => {
    await processPayment({
      method: 'card',
      cardNumber: '4242424242424242',
      // ... other payment data
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* Payment form fields */}
      <button type="submit" disabled={isPending}>
        {isPending ? 'Processing...' : 'Pay Now'}
      </button>
      {error && <p>Error: {error.message}</p>}
    </form>
  );
}
```

### usePaymentPolling()

Poll payment status for async payments.

```tsx theme={null}
import { usePaymentPolling } from '@tagadapay/plugin-sdk/v2';

function PaymentStatus({ paymentId }: { paymentId: string }) {
  const { data: status, isPolling } = usePaymentPolling({ paymentId });

  return (
    <div>
      {isPolling && <p>Checking payment status...</p>}
      <p>Status: {status?.status}</p>
    </div>
  );
}
```

## Utility Hooks

### useAuth()

Manage authentication and user sessions.

```tsx theme={null}
import { useAuth } from '@tagadapay/plugin-sdk/v2';

function AuthButton() {
  const { user, isAuthenticated, login, logout } = useAuth();

  if (isAuthenticated) {
    return (
      <div>
        <p>Welcome, {user?.name}</p>
        <button onClick={logout}>Logout</button>
      </div>
    );
  }

  return <button onClick={login}>Login</button>;
}
```

**Returns:**

* `user`: Current user object
* `isAuthenticated`: Boolean auth state
* `login()`: Login function
* `logout()`: Logout function
* `isLoading`: Auth check in progress

### useCustomer()

Access customer profile data.

```tsx theme={null}
import { useCustomer } from '@tagadapay/plugin-sdk/v2';

function CustomerProfile() {
  const { data: customer, updateProfile } = useCustomer();

  return (
    <div>
      <h2>
        {customer?.firstName} {customer?.lastName}
      </h2>
      <p>{customer?.email}</p>
      <button onClick={() => updateProfile({ phone: '123-456-7890' })}>Update Phone</button>
    </div>
  );
}
```

### useCustomerInfos()

Manage customer information and validation.

```tsx theme={null}
import { useCustomerInfos } from '@tagadapay/plugin-sdk/v2';

function CustomerInfoForm() {
  const { data, update, validate } = useCustomerInfos();

  const handleSubmit = async (formData) => {
    const isValid = await validate(formData);
    if (isValid) {
      await update(formData);
    }
  };

  return <form onSubmit={handleSubmit}>{/* form fields */}</form>;
}
```

### useCredits()

Manage store credit and balance.

```tsx theme={null}
import { useCredits } from '@tagadapay/plugin-sdk/v2';

function CreditBalance() {
  const { data: credits, apply, remove } = useCredits();

  return (
    <div>
      <p>Available Credits: ${credits?.balance}</p>
      <button onClick={() => apply(10)}>Apply $10 Credit</button>
      {credits?.applied && <button onClick={remove}>Remove Credit</button>}
    </div>
  );
}
```

### useFunnel()

Navigate and track funnel steps.

```tsx theme={null}
import { useFunnel } from '@tagadapay/plugin-sdk/v2';

function FunnelNavigation() {
  const { currentStep, nextStep, previousStep, goToStep } = useFunnel();

  return (
    <div>
      <p>Current Step: {currentStep}</p>
      <button onClick={previousStep}>← Back</button>
      <button onClick={nextStep}>Next →</button>
      <button onClick={() => goToStep(3)}>Skip to Step 3</button>
    </div>
  );
}
```

### useCheckoutToken()

Manage checkout session tokens.

```tsx theme={null}
import { useCheckoutToken } from '@tagadapay/plugin-sdk/v2';

function CheckoutSession() {
  const { checkoutToken, isValid, refresh } = useCheckoutToken();

  if (!isValid) {
    return (
      <div>
        Session expired. <button onClick={refresh}>Refresh</button>
      </div>
    );
  }

  return <div>Token: {checkoutToken}</div>;
}
```

### useCurrency()

Format money and handle currency conversions.

```tsx theme={null}
import { useCurrency } from '@tagadapay/plugin-sdk/v2';

function PriceDisplay({ amount, currency }) {
  const { formatMoney, convertCurrency } = useCurrency();

  return (
    <div>
      <p>Price: {formatMoney(amount, currency)}</p>
      <p>In USD: {formatMoney(convertCurrency(amount, currency, 'USD'), 'USD')}</p>
    </div>
  );
}
```

**formatMoney Options:**

```typescript theme={null}
formatMoney(amount: number, currency: string, options?: {
  showSymbol?: boolean;     // Show currency symbol (default: true)
  showCode?: boolean;       // Show currency code (default: false)
  decimals?: number;        // Decimal places (default: 2)
  locale?: string;          // Locale for formatting (default: 'en-US')
})
```

### useGeoLocation()

Detect user's geographic location.

```tsx theme={null}
import { useGeoLocation } from '@tagadapay/plugin-sdk/v2';

function LocationBasedContent() {
  const { country, region, city, loading } = useGeoLocation();

  if (loading) return <div>Detecting location...</div>;

  return (
    <div>
      <p>
        Shipping to: {city}, {region}, {country}
      </p>
    </div>
  );
}
```

### usePluginConfig()

Access plugin-specific configuration.

```tsx theme={null}
import { usePluginConfig } from '@tagadapay/plugin-sdk/v2';

function ThemedButton() {
  const config = usePluginConfig();

  return (
    <button
      style={{
        backgroundColor: config?.theme?.primaryColor,
        color: config?.theme?.textColor,
      }}
    >
      Buy Now
    </button>
  );
}
```

### useTranslation()

Internationalization and localization.

```tsx theme={null}
import { useTranslation } from '@tagadapay/plugin-sdk/v2';

function TranslatedContent() {
  const { formatMessage, locale, changeLocale } = useTranslation();

  return (
    <div>
      <h1>{formatMessage({ id: 'checkout.title' })}</h1>
      <p>Current locale: {locale}</p>
      <button onClick={() => changeLocale('fr')}>French</button>
      <button onClick={() => changeLocale('es')}>Spanish</button>
    </div>
  );
}
```

### useApiClient()

Direct access to API client for custom requests.

```tsx theme={null}
import { useApiClient } from '@tagadapay/plugin-sdk/v2';

function CustomApiCall() {
  const apiClient = useApiClient();

  const fetchCustomData = async () => {
    const response = await apiClient.get('/custom-endpoint');
    return response.data;
  };

  return <button onClick={fetchCustomData}>Fetch Data</button>;
}
```

### useApiQuery()

Create custom API queries with TanStack Query.

```tsx theme={null}
import { useApiQuery } from '@tagadapay/plugin-sdk/v2';

function CustomQuery() {
  const { data, isLoading } = useApiQuery({
    queryKey: ['custom-data'],
    queryFn: async () => {
      // Custom API call
      return await fetch('/api/custom').then((r) => r.json());
    },
  });

  return <div>{data?.result}</div>;
}
```

## Payment Hooks

### useThreeds()

Handle 3D Secure authentication.

```tsx theme={null}
import { useThreeds } from '@tagadapay/plugin-sdk/v2';

function PaymentWithThreeDS() {
  const { handleThreeDS, isProcessing } = useThreeds();

  const processPayment = async (paymentData) => {
    const result = await handleThreeDS(paymentData);
    if (result.authenticated) {
      // Proceed with payment
    }
  };

  return (
    <button onClick={() => processPayment(data)} disabled={isProcessing}>
      Pay with 3DS
    </button>
  );
}
```

### useThreedsModal()

Manage 3DS modal display.

```tsx theme={null}
import { useThreedsModal } from '@tagadapay/plugin-sdk/v2';

function ThreeDSModalManager() {
  const { isOpen, open, close, authUrl } = useThreedsModal();

  return (
    <>
      {isOpen && (
        <div className="modal">
          <iframe src={authUrl} />
          <button onClick={close}>Cancel</button>
        </div>
      )}
    </>
  );
}
```

### useExpressPaymentMethods()

Integrate Apple Pay and Google Pay.

```tsx theme={null}
import { useExpressPaymentMethods } from '@tagadapay/plugin-sdk/v2';

function ExpressCheckout() {
  const { applePay, googlePay, isAvailable } = useExpressPaymentMethods();

  return (
    <div>
      {isAvailable.applePay && <button onClick={() => applePay.pay()}>Apple Pay</button>}
      {isAvailable.googlePay && <button onClick={() => googlePay.pay()}>Google Pay</button>}
    </div>
  );
}
```

## Location Hooks

### useGoogleAutocomplete()

Address autocomplete with Google Places API.

```tsx theme={null}
import { useGoogleAutocomplete } from '@tagadapay/plugin-sdk/v2';

function AddressInput() {
  const { getPlacePredictions, getPlaceDetails } = useGoogleAutocomplete();

  const [predictions, setPredictions] = useState([]);

  const handleSearch = async (input) => {
    const results = await getPlacePredictions(input);
    setPredictions(results);
  };

  const handleSelect = async (placeId) => {
    const details = await getPlaceDetails(placeId);
    // Use address details
  };

  return (
    <div>
      <input type="text" onChange={(e) => handleSearch(e.target.value)} placeholder="Enter address" />
      <ul>
        {predictions.map((p) => (
          <li key={p.place_id} onClick={() => handleSelect(p.place_id)}>
            {p.description}
          </li>
        ))}
      </ul>
    </div>
  );
}
```

### useISOData()

Access country and region data.

```tsx theme={null}
import { useISOData } from '@tagadapay/plugin-sdk/v2';

function CountrySelector() {
  const { countries, regions, getCountry, getRegions } = useISOData();

  const [selectedCountry, setSelectedCountry] = useState('US');

  const countryData = getCountry(selectedCountry);
  const countryRegions = getRegions(selectedCountry);

  return (
    <div>
      <select onChange={(e) => setSelectedCountry(e.target.value)}>
        {countries.map((country) => (
          <option key={country.code} value={country.code}>
            {country.name}
          </option>
        ))}
      </select>
      <select>
        {countryRegions?.map((region) => (
          <option key={region.code} value={region.code}>
            {region.name}
          </option>
        ))}
      </select>
    </div>
  );
}
```

## Components

### ApplePayButton

Pre-styled Apple Pay button component.

```tsx theme={null}
import { ApplePayButton } from '@tagadapay/plugin-sdk/v2';

function Checkout() {
  const handleApplePay = async (paymentData) => {
    // Process Apple Pay payment
  };

  return <ApplePayButton onPayment={handleApplePay} amount={99.99} currency="USD" />;
}
```

### GooglePayButton

Pre-styled Google Pay button component.

```tsx theme={null}
import { GooglePayButton } from '@tagadapay/plugin-sdk/v2';

function Checkout() {
  const handleGooglePay = async (paymentData) => {
    // Process Google Pay payment
  };

  return <GooglePayButton onPayment={handleGooglePay} amount={99.99} currency="USD" />;
}
```

### DebugDrawer

Development helper for debugging plugin state.

```tsx theme={null}
import { DebugDrawer } from '@tagadapay/plugin-sdk/v2';

function App() {
  return (
    <div>
      <YourPlugin />
      {process.env.NODE_ENV === 'development' && <DebugDrawer />}
    </div>
  );
}
```

## Path Remapping Functions

<Card title="Path Remapping Guide" icon="route" href="/developer-tools/sdk/path-remapping">
  See the complete path remapping guide for detailed examples, testing, and advanced patterns
</Card>

### matchRoute()

<Badge type="success">New in v2.7.14</Badge>

Check if the current URL matches an internal path pattern **AND extract URL parameters**.

**Signature:**

```typescript theme={null}
function matchRoute(internalPath: string): RouteMatchResult;

interface RouteMatchResult {
  matched: boolean;
  params: Record<string, string>;
}
```

**Parameters:**

* `internalPath` - Your plugin's internal path pattern (e.g., `/checkout`, `/product/:id`)

**Returns:**

* `matched` - `true` if the current URL matches the internal path (considering remapping)
* `params` - Object containing extracted URL parameters

**Example 1: Basic Usage**

```tsx theme={null}
import { matchRoute } from '@tagadapay/plugin-sdk/v2';

function RemappableRoutes() {
  const match = matchRoute('/checkout');

  if (match.matched) {
    return <CheckoutPage />;
  }

  return <NotFound />;
}
```

**Example 2: Parameter Extraction**

```tsx theme={null}
function ProductRoutes() {
  const match = matchRoute('/product/:productId');

  if (match.matched) {
    // ✅ Params automatically extracted!
    // Works with both:
    // - /product/headphones (no remapping)
    // - /p/headphones (remapped to /product/:productId)
    return <ProductPage productId={match.params.productId} />;
  }

  return <NotFound />;
}
```

**Example 3: Multiple Parameters**

```tsx theme={null}
function OrderRoutes() {
  const match = matchRoute('/order/:orderId/item/:itemId');

  if (match.matched) {
    const { orderId, itemId } = match.params;
    return <OrderItemPage orderId={orderId} itemId={itemId} />;
  }

  return <NotFound />;
}
```

**Example 4: Conditional Rendering**

```tsx theme={null}
function App() {
  const checkoutMatch = matchRoute('/checkout/:step');
  const productMatch = matchRoute('/product/:id');

  if (checkoutMatch.matched) {
    return <CheckoutFlow step={checkoutMatch.params.step} />;
  }

  if (productMatch.matched) {
    return <ProductDetail id={productMatch.params.id} />;
  }

  return <HomePage />;
}
```

***

### shouldMatchRoute()

Check if the current URL matches an internal path pattern (without parameter extraction).

<Note>
  **Tip:** Use `matchRoute()` instead if you need URL parameters. `shouldMatchRoute()` only returns a boolean.
</Note>

**Signature:**

```typescript theme={null}
function shouldMatchRoute(internalPath: string): boolean;
```

**Parameters:**

* `internalPath` - Your plugin's internal path pattern

**Returns:**

* `boolean` - `true` if the current URL matches

**Example:**

```tsx theme={null}
import { shouldMatchRoute } from '@tagadapay/plugin-sdk/v2';

function RemappableRoute() {
  // Simple boolean check
  if (shouldMatchRoute('/checkout')) {
    return <CheckoutPage />;
  }

  if (shouldMatchRoute('/products/:id')) {
    return <ProductPage />;
  }

  return <NotFound />;
}
```

**When to use:**

* ✅ Simple route matching without parameters
* ✅ Conditional rendering based on route
* ✅ Route guards and redirects

**When to use `matchRoute()` instead:**

* ✅ When you need URL parameters
* ✅ When passing params to child components

***

### getPathInfo()

Get detailed information about the current path and remapping status.

**Signature:**

```typescript theme={null}
function getPathInfo(): PathInfo;

interface PathInfo {
  externalPath: string; // URL the user sees in browser
  internalPath: string | null; // Plugin's internal path (if remapped)
  isRemapped: boolean; // Whether path remapping is active
  query: URLSearchParams; // Query string parameters
  hash: string; // URL hash fragment
}
```

**Returns:**

* `PathInfo` object with detailed path information

**Example 1: Debug Panel**

```tsx theme={null}
import { getPathInfo } from '@tagadapay/plugin-sdk/v2';

function PathDebugger() {
  const pathInfo = getPathInfo();

  return (
    <div className="debug-panel">
      <h3>🔍 Path Information</h3>

      <dl>
        <dt>Current URL:</dt>
        <dd>
          <code>{pathInfo.externalPath}</code>
        </dd>

        {pathInfo.isRemapped && (
          <>
            <dt>Internal Path:</dt>
            <dd>
              <code>{pathInfo.internalPath}</code>
            </dd>

            <dt>Status:</dt>
            <dd>✅ Path remapping active</dd>
          </>
        )}

        {!pathInfo.isRemapped && (
          <>
            <dt>Status:</dt>
            <dd>ℹ️ No remapping (using original paths)</dd>
          </>
        )}

        {pathInfo.query.size > 0 && (
          <>
            <dt>Query Parameters:</dt>
            <dd>
              <code>?{pathInfo.query.toString()}</code>
            </dd>
          </>
        )}

        {pathInfo.hash && (
          <>
            <dt>Hash:</dt>
            <dd>
              <code>{pathInfo.hash}</code>
            </dd>
          </>
        )}
      </dl>
    </div>
  );
}
```

**Example 2: SEO Canonical URL**

```tsx theme={null}
import { Helmet } from 'react-helmet';

function CheckoutPage() {
  const pathInfo = getPathInfo();

  // Use external path for SEO (what user/search engines see)
  const canonicalUrl = `https://example.com${pathInfo.externalPath}`;

  return (
    <>
      <Helmet>
        <link rel="canonical" href={canonicalUrl} />
        <meta property="og:url" content={canonicalUrl} />
      </Helmet>
      <div>Checkout content...</div>
    </>
  );
}
```

**Example 3: Analytics Tracking**

```tsx theme={null}
function AnalyticsTracker() {
  const pathInfo = getPathInfo();

  useEffect(() => {
    // Track with external path (user-facing URL)
    analytics.page({
      path: pathInfo.externalPath,
      isRemapped: pathInfo.isRemapped,
      internalPath: pathInfo.internalPath,
    });
  }, [pathInfo.externalPath]);

  return null;
}
```

**Example 4: Conditional Feature Display**

```tsx theme={null}
function RemappingIndicator() {
  const pathInfo = getPathInfo();

  // Show indicator only in development
  if (process.env.NODE_ENV !== 'development') return null;

  if (!pathInfo.isRemapped) return null;

  return (
    <div className="dev-indicator">
      🔄 Path Remapping Active
      <br />
      External: {pathInfo.externalPath}
      <br />
      Internal: {pathInfo.internalPath}
    </div>
  );
}
```

***

### getInternalPath()

Get the current internal path, or `null` if no remapping is active.

**Signature:**

```typescript theme={null}
function getInternalPath(): string | null;
```

**Returns:**

* `string` - Internal path if remapping is active
* `null` - If no remapping is active

**Example 1: Simple Check**

```tsx theme={null}
import { getInternalPath } from '@tagadapay/plugin-sdk/v2';

function CurrentPath() {
  const internalPath = getInternalPath();

  if (internalPath) {
    return (
      <div>
        ✅ Remapping active
        <br />
        Internal path: <code>{internalPath}</code>
      </div>
    );
  }

  return <div>ℹ️ No remapping - using original paths</div>;
}
```

**Example 2: Conditional Logic**

```tsx theme={null}
function App() {
  const internalPath = getInternalPath();

  // Different behavior based on remapping
  if (internalPath) {
    console.log('Plugin remapped to:', internalPath);
  } else {
    console.log('Plugin using original paths');
  }

  return <YourApp />;
}
```

**When to use:**

* ✅ Quick remapping status check
* ✅ Logging and debugging
* ✅ Conditional behavior based on remapping

**When to use `getPathInfo()` instead:**

* ✅ Need both external and internal paths
* ✅ Need query parameters or hash
* ✅ Building debug UI

***

## Path Remapping Types

### RouteMatchResult

```typescript theme={null}
interface RouteMatchResult {
  matched: boolean; // Whether route matched
  params: Record<string, string>; // Extracted URL parameters
}
```

**Example Usage:**

```tsx theme={null}
const result = matchRoute('/product/:productId');

if (result.matched) {
  console.log('Product ID:', result.params.productId);
}
```

### PathInfo

```typescript theme={null}
interface PathInfo {
  externalPath: string; // User-facing URL
  internalPath: string | null; // Plugin's internal path
  isRemapped: boolean; // Remapping status
  query: URLSearchParams; // Query parameters
  hash: string; // URL hash (#fragment)
}
```

**Example:**

```typescript theme={null}
const info = getPathInfo();

// info.externalPath = "/buy-now"
// info.internalPath = "/checkout"
// info.isRemapped = true
// info.query = URLSearchParams { }
// info.hash = ""
```

***

## Path Remapping Best Practices

<Warning>
  **Never parse `window.location` directly!** Always use SDK functions to ensure remapping works correctly.
</Warning>

### ✅ Good Practices

```tsx theme={null}
// ✅ Use matchRoute() for params
const match = matchRoute('/product/:id');
if (match.matched) {
  return <Product id={match.params.id} />;
}

// ✅ Use shouldMatchRoute() for simple checks
if (shouldMatchRoute('/checkout')) {
  return <CheckoutPage />;
}

// ✅ Use getPathInfo() for detailed info
const pathInfo = getPathInfo();
if (pathInfo.isRemapped) {
  console.log('External:', pathInfo.externalPath);
  console.log('Internal:', pathInfo.internalPath);
}
```

### ❌ Bad Practices

```tsx theme={null}
// ❌ Don't parse window.location manually
if (window.location.pathname === '/checkout') {
  // Won't work with remapping!
}

// ❌ Don't use React Router params directly with remapping
const { id } = useParams(); // May be empty with remapping
return <Product id={id} />; // ❌

// ✅ Instead, use matchRoute()
const match = matchRoute('/product/:id');
if (match.matched) {
  return <Product id={match.params.id} />; // ✅
}

// ❌ Don't assume specific URL format
if (location.pathname.startsWith('/checkout/')) {
  // Won't work if remapped to /buy-now/
}

// ✅ Use SDK functions
if (shouldMatchRoute('/checkout/*')) {
  // Works with any external URL
}
```

***

<Card title="Complete Path Remapping Guide" icon="book" href="/developer-tools/sdk/path-remapping">
  See the complete guide for configuration, testing, troubleshooting, and advanced patterns
</Card>

## TypeScript Types

The SDK exports comprehensive TypeScript types:

```typescript theme={null}
import type {
  CheckoutData,
  ProductData,
  OfferData,
  OrderData,
  CustomerData,
  PaymentData,
  ShippingData,
  // ... many more
} from '@tagadapay/plugin-sdk/v2';
```

## Best Practices

### 1. Always Use V2 for New Projects

```tsx theme={null}
// ✅ Recommended
import { useCheckout } from '@tagadapay/plugin-sdk/v2';

// ❌ Avoid (V1)
import { useCheckout } from '@tagadapay/plugin-sdk';
```

### 2. Handle Loading and Error States

```tsx theme={null}
function SafeComponent() {
  const { data, isLoading, error } = useCheckout();

  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorMessage error={error} />;
  if (!data) return <EmptyState />;

  return <YourContent data={data} />;
}
```

### 3. Use TanStack Query Features

```tsx theme={null}
function OptimizedComponent() {
  const { data, refetch } = useCheckout({
    staleTime: 60000, // Cache for 1 minute
    refetchInterval: 30000, // Refetch every 30s
    refetchOnWindowFocus: true, // Refetch on tab focus
  });

  return <YourContent data={data} />;
}
```

### 4. Combine Multiple Hooks

```tsx theme={null}
function ComprehensiveCheckout() {
  const { data: checkout } = useCheckout();
  const { data: offers } = useOffers();
  const { formatMoney } = useCurrency();
  const { mutate: pay, isPending } = usePayment();

  // Use all data together
  return (
    <CheckoutUI
      checkout={checkout}
      offers={offers}
      formatMoney={formatMoney}
      onPay={pay}
      isProcessing={isPending}
    />
  );
}
```

## Support

* **Examples**: See [SDK Examples](/developer-tools/sdk/examples)
* **Tutorial**: Follow the [SDK Tutorial](/developer-tools/sdk/tutorial)
* **Best Practices**: Read [Best Practices](/developer-tools/sdk/best-practices)
* **Support**: [developer-support@tagadapay.com](mailto:developer-support@tagadapay.com)
