> ## 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.

# Plugin SDK

> Build powerful e-commerce plugins with React, TypeScript, or Vanilla JavaScript

# TagadaPay Plugin SDK v2

Build custom checkout pages, multi-step funnels, and e-commerce experiences that run on TagadaPay's hosting infrastructure. The SDK connects your page to TagadaPay's backend — sessions, checkout data, payments, analytics — so you focus on the UI.

<Info>
  **When to use this SDK:**

  * You're building a checkout / landing / thank-you page that should be **hosted on TagadaPay** (deployed via the [Plugin CLI](/developer-tools/cli/introduction))
  * You want React hooks (`useCheckout`, `usePayment`, `useApplePayCheckout`) that read from the runtime-injected step config
  * You need TagadaPay's funnel-step navigation, A/B routing, and edge CDN for free

  **When NOT to use this SDK:**

  * You're hosting your store on your **own domain** (Vercel, Netlify, etc.) — use the [Headless SDK](/developer-tools/headless-sdk/introduction) instead
  * You're building a **payment platform that charges for many merchants** — use the [Partners section](/developer-tools/partners/introduction)
  * You only need server automation — use the [Node SDK](/developer-tools/node-sdk/quick-start)
</Info>

<Tip>
  **Not sure which SDK fits your project?** Compare all five SDKs side-by-side on [SDKs at a glance](/developer-tools/sdks-at-a-glance).
</Tip>

<Info>
  **Prefer to start from a working plugin?** We publish **five open-source, MIT-licensed checkout examples**
  on GitHub — editorial, neon, luxe, solar, and arcade — each a complete, deployable plugin with
  matching thank-you pages.

  👉 [**Browse the gallery**](/developer-tools/sdk/open-source-examples) • [**github.com/TagadaPay/plugins**](https://github.com/TagadaPay/plugins)
</Info>

<CardGroup cols={2}>
  <Card title="React + TypeScript" icon="react">
    Modern React hooks with full TypeScript support
  </Card>

  <Card title="Vanilla JavaScript" icon="js">
    Framework-agnostic standalone SDK
  </Card>

  <Card title="Funnel System" icon="route">
    Pass data seamlessly between funnel steps
  </Card>

  <Card title="Auto-redirect" icon="map">
    Automatic navigation and URL routing
  </Card>
</CardGroup>

***

## Quick Start

<Tabs>
  <Tab title="React">
    ```bash theme={null}
    npm install @tagadapay/plugin-sdk
    ```

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

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

    function CheckoutPage() {
      const funnel = useFunnel();

      const handlePayment = async () => {
        await funnel.next({
          type: 'payment_success',
          data: {
            resources: {
              order: { id: 'ord_123', amount: 99.99 }
            }
          }
        });
      };

      return <button onClick={handlePayment}>Pay Now</button>;
    }
    ```
  </Tab>

  <Tab title="Vanilla JS">
    ```bash theme={null}
    npm install @tagadapay/plugin-sdk
    ```

    ```typescript theme={null}
    import { createTagadaClient, FunnelActionType } from '@tagadapay/plugin-sdk/v2/standalone';

    const client = createTagadaClient({
      features: { funnel: true }
    });

    // Funnel auto-initializes. Subscribe to know when it's ready.
    if (client.funnel) {
      client.funnel.subscribe((funnelState) => {
        if (funnelState.isInitialized && funnelState.context) {
          document.getElementById('pay-btn')!.onclick = async () => {
            await client.funnel!.navigate({
              type: FunnelActionType.PAYMENT_SUCCESS,
              data: {
                order: { id: 'ord_123', amount: 99.99 }
              }
            });
          };
        }
      });
    }
    ```
  </Tab>
</Tabs>

***

## Core Concepts

### 1. Provider-Based Architecture (React)

The SDK uses React Context to provide global state and functionality:

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

export default function App() {
  return (
    <TagadaProvider>
      {/* Your plugin components */}
    </TagadaProvider>
  );
}
```

**What TagadaProvider does:**

* Initializes authentication and session
* Auto-initializes funnel if enabled
* Provides hooks like `useFunnel()`, `useCheckout()`, etc.
* Handles automatic redirects
* Manages debug mode based on environment

### 2. Funnel System

Build multi-step funnels where data flows automatically between steps:

```tsx theme={null}
// Step 1: Checkout
await funnel.next({
  type: 'payment_success',
  data: {
    resources: {
      order: { id: 'ord_123', amount: 100 },
      customer: { id: 'cus_456', email: 'user@example.com' }
    }
  }
});

// Step 2: Thank You Page - order data is automatically available
const order = funnel.context?.resources?.order;
```

**Learn more**: [Funnel Resources Guide](/developer-tools/sdk/funnel-resources)

***

### 3. Automatic Features

The SDK handles common tasks automatically:

**Auto-initialization**

* Funnel session initializes automatically when `TagadaProvider` mounts
* No manual `initializeSession()` calls needed
* Controlled via `autoInitializeFunnel` prop (default: `true`)

**Auto-redirect**

* Navigating with `funnel.next()` automatically redirects to the next step URL
* No need for custom `onNavigate` handlers
* Browser is redirected immediately after successful navigation

**Debug Mode**

* Automatically enabled in local development
* Loads local config from `config/resources.static.json`
* Disabled in production automatically

```tsx theme={null}
// All of this happens automatically:
<TagadaProvider>
  {/* ✅ Funnel initializes
       ✅ Session created
       ✅ Debug mode enabled (if local)
       ✅ Redirects handled */}
  <YourPlugin />
</TagadaProvider>
```

***

### 4. Plugin Manifest

Define your plugin's pages, features, and requirements:

```json theme={null}
{
  "name": "My Checkout",
  "pluginId": "my-checkout",
  "version": "1.0.0",
  "mode": "direct-mode",
  "category": "checkout",
  "pages": [
    {
      "path": "/checkout",
      "features": [
        {
          "type": "checkout",
          "requirements": [
            {
              "resource": "checkoutSession",
              "from": [{ "name": "checkoutToken", "type": "query" }]
            }
          ]
        }
      ],
      "remappable": true
    },
    {
      "path": "/thankyou/:orderId",
      "features": [
        {
          "type": "thankyou",
          "requirements": [
            {
              "resource": "order",
              "from": [{ "name": "id", "type": "path" }]
            }
          ]
        }
      ],
      "remappable": true
    }
  ]
}
```

**Learn more**: [Manifest Documentation](/developer-tools/sdk/manifest)

***

## Available Hooks (React)

### Funnel Navigation

| Hook          | Description                                       |
| ------------- | ------------------------------------------------- |
| `useFunnel()` | Navigate between steps and access session context |

### Data Fetching

| Hook                | Description                                                            |
| ------------------- | ---------------------------------------------------------------------- |
| `useCheckout()`     | Fetch and manage checkout session                                      |
| `useProducts()`     | Fetch products with caching                                            |
| `usePreviewOffer()` | Recommended hook for post-checkout upsell pages (auto-applies MIT/CIT) |
| `useOffer()`        | ⚠️ Deprecated — use `usePreviewOffer()` instead                        |
| `useStoreConfig()`  | Fetch store settings                                                   |
| `useCustomer()`     | Fetch customer data                                                    |

### Step Configuration

| Hook                     | Description                                                                     |
| ------------------------ | ------------------------------------------------------------------------------- |
| `useStepConfig()`        | Access per-step runtime config: scripts, static resources, payment flow, pixels |
| `useFunnel().stepConfig` | Same data, available directly from the funnel hook                              |

### Utilities

| Hook                | Description                       |
| ------------------- | --------------------------------- |
| `useCurrency()`     | Format money with `formatMoney()` |
| `useTranslation()`  | Multi-language translation helper |
| `usePluginConfig()` | Access plugin configuration       |

***

## Standalone SDK (Vanilla JS)

For non-React applications, use the standalone SDK. It gives you the same features — just without React hooks.

```typescript theme={null}
import { createTagadaClient, FunnelActionType } from '@tagadapay/plugin-sdk/v2/standalone';

const client = createTagadaClient({
  features: { funnel: true }
});

// Funnel auto-initializes. Subscribe to react when ready.
if (client.funnel) {
  client.funnel.subscribe((funnelState) => {
    if (funnelState.isInitialized && funnelState.context) {
      console.log('Funnel ready:', funnelState.context);
    }
  });
}

// Navigate to next step
await client.funnel.navigate({
  type: FunnelActionType.PAYMENT_SUCCESS,
  data: { order: { id: 'ord_123', amount: 99.99 } }
});
```

***

## Environment Detection

The SDK automatically detects your environment:

| Environment   | When                           | Behavior                           |
| ------------- | ------------------------------ | ---------------------------------- |
| `local`       | localhost, \*.localhost, ngrok | Debug mode ON, local config loaded |
| `development` | dev.*, staging.*               | Debug mode ON                      |
| `production`  | app.\*, other domains          | Debug mode OFF                     |

Override with the `debugMode` prop:

```tsx theme={null}
<TagadaProvider debugMode={false}>
  {/* Force debug mode off */}
</TagadaProvider>
```

***

## Configuration Presets

Define multiple configuration variants with metadata:

```json theme={null}
{
  "meta": {
    "id": "premium",
    "name": "Premium Theme",
    "description": "High-end checkout design"
  },
  "branding": {
    "primaryColor": "#000000",
    "companyName": "Premium Store"
  }
}
```

The `meta.name` is displayed in the CRM marketplace when merchants select presets.

***

## Step Config & Script Injection

Every funnel step can carry **runtime configuration** — scripts, tracking pixels, static resources, and payment flow overrides — that are injected when the page is served. This lets merchants customize behavior **per funnel step without touching your plugin code**.

### How It Works

When TagadaPay serves your plugin, it injects a `stepConfig` object into the HTML (via `window.__TGD_STEP_CONFIG__`). The SDK reads it automatically and makes it available through `useStepConfig()` or `useFunnel().stepConfig`.

```
┌──────────────────────────────────────────────────┐
│  Merchant configures in CRM:                     │
│    Step "Checkout" → Scripts → Add "Facebook Pixel" │
│                                                  │
│  TagadaPay injects into HTML at serve time:      │
│    window.__TGD_STEP_CONFIG__ = {                │
│      scripts: [{ name: "Facebook Pixel", ... }], │
│      pixels: { facebook: [{ pixelId: "123" }] }, │
│      staticResources: { offer: "offer_abc" }     │
│    }                                             │
│                                                  │
│  SDK reads it → your plugin code stays unchanged │
└──────────────────────────────────────────────────┘
```

### Script Injection

Merchants can add custom JavaScript to any funnel step. Scripts are injected at one of four positions and run automatically — your plugin doesn't need any code for this.

| Position     | Where it runs                                     |
| ------------ | ------------------------------------------------- |
| `head-start` | First thing in `<head>` (before CSS, fonts)       |
| `head-end`   | End of `<head>` (after CSS, good for analytics)   |
| `body-start` | First thing in `<body>` (before your app renders) |
| `body-end`   | End of `<body>` (after your app, default)         |

Scripts have access to `window.Tagada` — a global object the SDK sets up with helper methods and funnel context:

```javascript theme={null}
// Example: a script added by the merchant in the CRM
// Runs automatically — no code changes needed in the plugin

Tagada.ready(function() {
  console.log('Page type:', Tagada.pageType);       // "checkout", "thankyou", etc.
  console.log('Resources:', Tagada.ressources);      // order, customer data from funnel
  console.log('Step config:', Tagada.stepConfig);    // full runtime config for this step
});

// Wait for both page load AND funnel initialization
Tagada.loaded(function() {
  console.log('Funnel session:', Tagada.funnel.sessionId);
  console.log('Current step:', Tagada.funnel.currentStepId);
});

// Wait for a specific DOM element (useful for injecting into React apps)
Tagada.waitForElement('#checkout-form', function(el) {
  el.style.border = '2px solid green';
});
```

### `window.Tagada` API

The SDK exposes these helpers on `window.Tagada` for injected scripts:

| Method                                                     | Description                                         |
| ---------------------------------------------------------- | --------------------------------------------------- |
| `Tagada.ready(callback)`                                   | Run when DOM is ready                               |
| `Tagada.loaded(callback)`                                  | Run when DOM is ready **and** funnel is initialized |
| `Tagada.delay(callback, ms)`                               | Run after a delay (default 1s)                      |
| `Tagada.retry(condition, callback, maxAttempts, interval)` | Retry until condition is true                       |
| `Tagada.waitForElement(selector, callback, timeout)`       | Run when a CSS selector matches                     |
| `Tagada.waitForElements(selector, callback, timeout)`      | Same, but for multiple elements                     |

| Property               | Description                                                                 |
| ---------------------- | --------------------------------------------------------------------------- |
| `Tagada.pageType`      | Current step ID (e.g. `"checkout"`, `"thankyou"`)                           |
| `Tagada.isInitialized` | `true` once the funnel is ready                                             |
| `Tagada.ressources`    | Resources from the current funnel context (order, customer, etc.)           |
| `Tagada.funnel`        | Funnel metadata: `sessionId`, `funnelId`, `currentStepId`, `previousStepId` |
| `Tagada.stepConfig`    | Full `RuntimeStepConfig` object for this step                               |

### Reading stepConfig in Your Plugin (Optional)

If your plugin needs to read the step config directly (e.g., to conditionally render based on static resources), use the hook:

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

function MyComponent() {
  const { staticResources, paymentFlowId, getScripts } = useStepConfig();

  const offerId = staticResources?.offer;
  const headScripts = getScripts('head-end');

  return <div>Offer: {offerId || 'none configured'}</div>;
}
```

Or access it through `useFunnel()`:

```tsx theme={null}
const { stepConfig } = useFunnel();
const offerId = stepConfig.staticResources?.offer;
```

### Practical Examples

<AccordionGroup>
  <Accordion title="Add a Facebook Pixel to checkout only" icon="meta">
    In the CRM, go to your funnel → Checkout step → Scripts, and add:

    **Name**: Facebook Pixel\
    **Position**: head-end\
    **Content**:

    ```html theme={null}
    <script>
    !function(f,b,e,v,n,t,s)
    {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
    n.callMethod.apply(n,arguments):n.queue.push(arguments)};
    if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
    n.queue=[];t=b.createElement(e);t.async=!0;
    t.src=v;s=b.getElementsByTagName(e)[0];
    s.parentNode.insertBefore(t,s)}(window, document,'script',
    'https://connect.facebook.net/en_US/fbevents.js');
    fbq('init', 'YOUR_PIXEL_ID');
    fbq('track', 'PageView');
    </script>
    ```

    This runs only on the checkout step. Other steps (upsell, thank you) won't have this pixel unless you add it there too.
  </Accordion>

  <Accordion title="Show a banner on a specific step" icon="flag">
    **Name**: Promo Banner\
    **Position**: body-end\
    **Content**:

    ```html theme={null}
    <script>
    Tagada.waitForElement('#root', function() {
      var banner = document.createElement('div');
      banner.style.cssText = 'background:#ff6b35;color:white;text-align:center;padding:12px;font-weight:bold;';
      banner.textContent = 'Limited time: Free shipping on all orders!';
      document.body.insertBefore(banner, document.body.firstChild);
    });
    </script>
    ```

    No plugin code changes needed — the merchant adds this in the CRM.
  </Accordion>

  <Accordion title="Track conversions on the thank you page" icon="chart-line">
    Add this script to the **Thank You** step only:

    **Name**: Conversion Tracking\
    **Position**: body-end\
    **Content**:

    ```html theme={null}
    <script>
    Tagada.loaded(function() {
      var order = Tagada.ressources?.order;
      if (order) {
        console.log('Conversion:', order.id, 'Amount:', order.amount);
        // Send to your analytics platform
        // gtag('event', 'purchase', { value: order.amount / 100 });
      }
    });
    </script>
    ```

    `Tagada.loaded()` waits until the funnel is initialized, so `Tagada.ressources` is guaranteed to have the order data.
  </Accordion>

  <Accordion title="Different scripts per A/B variant" icon="flask-vial">
    Each A/B variant has its own `stepConfig`. If variant A has a script and variant B doesn't, only visitors assigned to variant A will see that script.

    This is configured in the CRM when you set up split testing on a funnel step — each variant can have its own scripts, static resources, and pixel configuration.
  </Accordion>
</AccordionGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Quick Start" icon="rocket" href="/developer-tools/sdk/quick-start">
    Build your first plugin in 15 minutes
  </Card>

  <Card title="Initialize Checkout" icon="cart-plus" href="/developer-tools/sdk/init-checkout-example">
    Create checkout sessions programmatically
  </Card>

  <Card title="Tutorial" icon="graduation-cap" href="/developer-tools/sdk/tutorial">
    Step-by-step plugin development
  </Card>

  <Card title="API Reference" icon="book" href="/developer-tools/sdk/api">
    Complete API documentation
  </Card>

  <Card title="Funnel Resources" icon="database" href="/developer-tools/sdk/funnel-resources">
    Learn how to pass data between steps
  </Card>

  <Card title="Examples" icon="code" href="/developer-tools/sdk/examples">
    See real plugin examples
  </Card>

  <Card title="Best Practices" icon="star" href="/developer-tools/sdk/best-practices">
    Production-ready tips
  </Card>
</CardGroup>
