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

# Embeddable Templates SDK

> Embed SuprSend multi-channel template editor inside your product with React SDK. Supports editing, testing and committing template variants.

The **`@suprsend/react-editor`** package provides the UI for embeddable templates: channel editors, preview, test, commit, and theming. You can use this to let your customers edit their notification templates or for your internal team to manage templates and run campaigns within your product.

Import the CSS bundle for correct layout and styling.

***

## Installation

<CodeGroup>
  ```bash npm theme={"system"}
  npm install @suprsend/react-editor
  ```

  ```bash yarn theme={"system"}
  yarn add @suprsend/react-editor
  ```
</CodeGroup>

<Warning>
  You must import the stylesheet (`@suprsend/react-editor/styles.css`) for the components to render correctly.
</Warning>

***

## Authentication

Provide an `accessToken` and optionally a `refreshAccessToken` callback to handle token expiration.

```tsx theme={"system"}
<SuprSendTemplateProvider
  workspaceUid="ws_123"
  accessToken={token}
  refreshAccessToken={async (oldToken) => {
    const response = await fetch('/api/refresh-token', {
      method: 'POST',
      body: JSON.stringify({ token: oldToken }),
    });
    const { newToken } = await response.json();
    return newToken;
  }}
  // ...other props
/>
```

When a `401` response is received, the SDK automatically calls `refreshAccessToken`, queues pending requests, and retries them with the new token.

### Generating access token

```python theme={"system"}
import time
import jwt
from typing import Dict, Any

# ==================== CONFIGURATION ====================

signing_key_uid = "signing_key_xxxxxx"

# Private key in PEM format
signing_private_key = """-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-----END PRIVATE KEY-----"""

# ==================== PAYLOAD ====================

payload: Dict[str, Any] = {
    "workspace_uid": "<ws_uid>",
    "entity_type": "template",
    "entity_id": "<template-slug>",          # Use "*" to allow access to all templates
    
    # unique key used to share resources,
    # ex: if you pass tenant_id then resources like designer editor's images will be shared within that tenant.
    # if you pass workspace_uid then resources will shared within that workspace.
    # defaults to organization_uid
    "resource_namespace": "",
    "scope": {
        # Template-level scope
        "variant_scope": {                   # variant_scope: If missing, user can access all variants
            "channels": ["email"],           # If missing, any channel can be accessed
            "variant_id": "v1",              # If missing, any variant can be accessed
            "tenant_id": "<tenant1>",        # If missing or null, variants of all tenants can be accessed
            "locale": "en",                  # If missing, variants of all locales can be accessed

            "conditions": [                  # If missing, variants of all conditions can be accessed
                {
                    "expression_v1": {
                        "op": "AND",
                        "args": [
                            {"variable_ns": "", "variable": "age", "op": "==", "value": "18"},
                            {"variable_ns": "", "variable": "age", "op": "==", "value": "18"}
                        ]
                    }
                }
            ],

            "fallback_variant_id": "var_1"   # If the requested variant is not present,
                                             # use content from this fallback variant
        },

        # Only the recipients mentioned below can be accessed
        # (used for mock testing and variable fetching)
        # If this key is missing, mock/variable functionality might not work properly
        "recipients": [
            {"distinct_id": "id1"},
            {"distinct_id": "id2"}
        ]
    },

    # Token expiration settings
    "iat": int(time.time()),                    # Issued at (current time in unix seconds)
    "exp": int(time.time()) + 3600              # Expiration time (add extra seconds as needed)
}

# ==================== JWT HEADER ====================

header_dict = {
    "alg": "ES256",
    "kid": signing_key_id,
    "typ": "JWT"
}

# ==================== GENERATE TOKEN ====================

auth_token = jwt.encode(
    payload=payload,
    key=signing_private_key,
    algorithm="ES256",
    headers=header_dict
)

print(auth_token)
```

***

## Components

### SuprSendTemplateProvider

The root context provider. Wrap your editor UI with this component. This is where you configure which template and variant to edit, which channels to enable, theming, and authentication.

```tsx theme={"system"}
<SuprSendTemplateProvider
  workspaceUid="ws_123"
  templateSlug="welcome-email"
  variantId="default"
  channels={['email', 'inbox', 'webpush']}
  tenantId={null}
  locale="en"
  themeOverrides={{ primary: '#6366f1', radius: '8px' }}
  accessToken="your-access-token"
  refreshAccessToken={async (oldToken) => {
    const newToken = await fetchNewToken(oldToken);
    return newToken;
  }}
>
  {children}
</SuprSendTemplateProvider>
```

**Props**

| Prop                   | Type                                    | Description                                                                      | Required | Default   |
| ---------------------- | --------------------------------------- | -------------------------------------------------------------------------------- | -------- | --------- |
| `workspaceUid`         | `string`                                | Your SuprSend workspace identifier. You can find it on workspace settings        | Yes      | —         |
| `templateSlug`         | `string`                                | The template slug                                                                | Yes      | —         |
| `variantId`            | `string`                                | The variant identifier                                                           | Yes      | —         |
| `channels`             | `ChannelId[]`                           | Array of channels to enable in the editor                                        | Yes      | —         |
| `tenantId`             | `string \| null`                        | Tenant ID for multi-tenant workspaces (pass `null` if N/A)                       | Yes      | —         |
| `locale`               | `string`                                | Language/locale code (for example `"en"`)                                        | Yes      | —         |
| `conditions`           | `ConditionExpr[]`                       | Audience rules that select which variant to load (see [Conditions](#conditions)) | No       | —         |
| `accessToken`          | `string`                                | Authentication token                                                             | Yes      | —         |
| `refreshAccessToken`   | `(oldToken: string) => Promise<string>` | Callback to refresh an expired token                                             | No       | —         |
| `mode`                 | `'live' \| 'draft'`                     | Start in draft (editable) or live (read-only) mode                               | No       | `'draft'` |
| `theme`                | -                                       | Coming soon                                                                      | No       | -         |
| `themeOverrides`       | `ThemeOverrides`                        | Custom color and styling overrides (see [Theming](#theming))                     | No       | -         |
| `recipientDistinctId`  | `string`                                | Recipient ID for populating mock/preview data                                    | No       | -         |
| `actorDistinctId`      | `string`                                | Actor ID for populating mock/preview data                                        | No       | -         |
| `notificationCategory` | `string`                                | Preference category for triggering test                                          | No       | -         |

<Note>
  For self-hosted deployments, pass prop `host={{apiHost:<your-management-api-service-url>}}`.
</Note>

#### Conditions

Use the `conditions` prop when you want to specify the variant based on conditions **other than** `tenantId` and `locale`. If your variant is identified solely by `tenantId` and `locale`, you don't need this prop.

Conditions can be evaluated against the input payload, tenant, actor, and recipient properties to decide which variant applies. Passing `conditions` scopes the editor to the variant matching those rules.

The shape follows the `variant_condition_expr_v1_def` definition in the [variant schema](https://schema.suprsend.com/template/v2/variant_schema.json). `conditions` is an **array** of expression objects, where each object has:

| Field           | Type     | Description                                                                      |
| --------------- | -------- | -------------------------------------------------------------------------------- |
| `type`          | `string` | Always `"expression_v1"`                                                         |
| `expression_v1` | `object` | The condition group. Has an `op` (always `"AND"`) and an `args` array of clauses |

Each clause in `args` is a single comparison:

| Field         | Type             | Required | Description                                                                                               |
| ------------- | ---------------- | -------- | --------------------------------------------------------------------------------------------------------- |
| `variable`    | `string`         | Yes      | The property on the left-hand side of the comparison                                                      |
| `variable_ns` | `string \| null` | No       | Namespace of the variable — `""` for the input payload, or one of `"$tenant"`, `"$actor"`, `"$recipient"` |
| `op`          | `string`         | Yes      | Comparison operator (see below)                                                                           |
| `value`       | `string`         | Cond.    | Right-hand side value. Required for all operators except `EMPTY` and `NON_EMPTY`                          |

All clauses inside a single `expression_v1.args` are combined with **AND**. The `conditions` array itself can hold multiple expression objects to express alternative (OR) audience groups.

<br />

**Supported operators (`op`)**

| Operator                                          | Description                                                       | Data Types          |
| ------------------------------------------------- | ----------------------------------------------------------------- | ------------------- |
| `==` / `!=`                                       | Equal to / not equal to (case sensitive)                          | All                 |
| `>` / `>=`                                        | Greater than / greater than or equal to                           | Numbers, timestamps |
| `<` / `<=`                                        | Less than / less than or equal to                                 | Numbers, timestamps |
| `CONTAINS` / `NOT_CONTAINS`                       | Substring or array item match / no substring or array item match  | Strings, arrays     |
| `EMPTY` / `NON_EMPTY`                             | Key is missing, empty or null / key is present, not empty or null | All                 |
| `ARRAY_INTERSECTS` / `NOT_ARRAY_INTERSECTS`       | Any array value matches / no array values match                   | Arrays              |
| `DATETIME_EQUALS` / `DATETIME_LT` / `DATETIME_GT` | Datetime equal to / before / after                                | Timestamps          |

<Note>
  If a key's data type doesn't match the operator (for example, using `>` on a string), the condition always evaluates to false.
</Note>

**Example** — each object in the `conditions` array is OR-ed, while the clauses inside one `expression_v1.args` are AND-ed. The variant below loads when **either** the order is high-priority for a Pro-plan tenant **OR** the acting user is an admin sending to a recipient in India:

```tsx theme={"system"}
<SuprSendTemplateProvider
  workspaceUid="ws_123"
  templateSlug="order-update"
  variantId="v1"
  channels={['email']}
  tenantId={null}
  locale="en"
  accessToken="your-access-token"
  conditions={[
    // Group 1 — high-priority order (input payload) from a Pro-plan tenant
    {
      type: 'expression_v1',
      expression_v1: {
        op: 'AND',
        args: [
          { variable_ns: '', variable: 'priority', op: '==', value: 'high' },
          { variable_ns: '$tenant', variable: 'plan', op: '==', value: 'pro' },
        ],
      },
    },
    // OR Group 2 — admin actor sending to a recipient in India
    {
      type: 'expression_v1',
      expression_v1: {
        op: 'AND',
        args: [
          { variable_ns: '$actor', variable: 'role', op: '==', value: 'admin' },
          { variable_ns: '$recipient', variable: 'country', op: '==', value: 'IN' },
        ],
      },
    },
  ]}
>
  {children}
</SuprSendTemplateProvider>
```

***

#### Supported channels

| Channel          | ID            | Editor Functionality                                                                                                                                     |
| ---------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Email**        | `email`       | 3 types of editor available: **Visual designer**, **raw HTML**, **plain text**. Users can switch between editors and see live preview while editing.     |
| **Slack**        | `slack`       | 2 types of editor available: **Plain text** for designing simple text based notifications and **Block Kit (JSON)** for advanced interactive messages.    |
| **MS Teams**     | `ms_teams`    | 2 types of editor available: **Markdown** for designing simple text based notifications and **Adaptive Cards** (JSON) for advanced interactive messages. |
| **Android Push** | `androidpush` | Single Form editor with rich text messaging support (title, body, image, buttons).                                                                       |
| **iOS Push**     | `iospush`     | Single Form editor with rich text messaging support (title, body, image, action URL).                                                                    |
| **Web Push**     | `webpush`     | Single Form editor with support to add title, body, image, buttons.                                                                                      |
| **In-app Inbox** | `inbox`       | Single Form editor with support for rich content, avatar, buttons, tags, expiry and Pinning.                                                             |
| **SMS**          | `sms`         | Coming soon                                                                                                                                              |
| **WhatsApp**     | `whatsapp`    | Coming soon                                                                                                                                              |

***

### TemplateEditor

The main editor component. Renders channel tabs, channel editor forms, and preview panes.

```tsx theme={"system"}
<TemplateEditor
  hideActionButtons={false}
  onCommit={() => console.log('Committed!')}
/>
```

**Props**

| Prop                | Type         | Required | Default | Description                                                                                                                                 |
| ------------------- | ------------ | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `hideActionButtons` | `boolean`    | No       | `false` | Hide the default action buttons (Test, Commit, Edit, Exit)                                                                                  |
| `hideTestButton`    | `boolean`    | No       | `false` | Hide only the Test button while keeping other action buttons visible                                                                        |
| `onCommit`          | `() => void` | No       | -       | Callback invoked after a successful commit. If you hide action buttons, you can pass your handler to the standalone `CommitButton` instead. |

<Tip>
  When `hideActionButtons` is `true`, use the standalone `TestButton` and `CommitButton` components to place actions anywhere in your layout.
</Tip>

***

### CommitButton

A button that opens the commit modal. Validates all variants, lets the user select which to publish, and requires a commit message.

```tsx theme={"system"}
<CommitButton onCommit={() => console.log('Published!')} />
```

**Props**

| Prop       | Type         | Required | Description                   |
| ---------- | ------------ | -------- | ----------------------------- |
| `onCommit` | `() => void` | Yes      | Callback invoked after commit |

***

### TestButton

A button that opens the test modal. Allows sending a test notification to a real recipient with mock data.

```tsx theme={"system"}
<TestButton onTestSent={() => console.log('Test sent!')} />
```

**Props**

| Prop         | Type         | Required | Description                         |
| ------------ | ------------ | -------- | ----------------------------------- |
| `onTestSent` | `() => void` | No       | Callback invoked after test is sent |

***

## Theming

The `theme` prop (`light`, `dark`, `system`) is **coming soon**. Customize the look and feel today using `themeOverrides`.

```tsx theme={"system"}
<SuprSendTemplateProvider
  themeOverrides={{
    primary: '#6366f1',
    primaryForeground: '#ffffff',
    background: '#fafafa',
    foreground: '#111827',
    border: '#e5e7eb',
    radius: '8px',
  }}
  // ...other props
>
  {children}
</SuprSendTemplateProvider>
```

### Available overrides

| Property                | Description                                     |
| ----------------------- | ----------------------------------------------- |
| `background`            | Main background color                           |
| `foreground`            | Main text color                                 |
| `card`                  | Card/panel background                           |
| `cardForeground`        | Card text color                                 |
| `popover`               | Popover/dropdown background                     |
| `popoverForeground`     | Popover text color                              |
| `primary`               | Primary brand color                             |
| `primaryForeground`     | Text on primary backgrounds                     |
| `secondary`             | Secondary color                                 |
| `secondaryForeground`   | Text on secondary backgrounds                   |
| `muted`                 | Muted/subtle backgrounds                        |
| `mutedForeground`       | Muted text color                                |
| `accent`                | Accent highlight color                          |
| `accentForeground`      | Text on accent backgrounds                      |
| `destructive`           | Error/danger color                              |
| `destructiveForeground` | Text on destructive backgrounds                 |
| `border`                | Border color                                    |
| `input`                 | Input field border color                        |
| `ring`                  | Focus ring color                                |
| `radius`                | Border radius (for example `"8px"`, `"0.5rem"`) |

All CSS classes are scoped with a `suprsend-` prefix to prevent conflicts with your application's styles.
