# API reference for the @novu/js package (/platform/sdks/javascript)

Complete API reference for the Novu JavaScript package

import { Tab, Tabs } from 'fumadocs-ui/components/tabs';

## Novu

The Novu client provides methods to interact with notifications, preferences, and real-time events.

### Constructor Options

<TypeTable
  name="NovuOptions"
  type={{
"backendUrl": {
  "description": "",
  "type": "string"
},
"applicationIdentifier": {
  "description": "",
  "type": "string | undefined"
},
"subscriberHash": {
  "description": "",
  "type": "string"
},
"contextHash": {
  "description": "",
  "type": "string"
},
"apiUrl": {
  "description": "",
  "type": "string"
},
"socketUrl": {
  "description": "",
  "type": "string"
},
"socketOptions": {
  "description": "Custom socket configuration options. These options will be merged with the default socket configuration.\nUse `socketType` to explicitly select the socket implementation: `'cloud'` for PartySocket or `'self-hosted'` for socket.io.\nFor socket.io-client connections, supports all socket.io-client options (e.g., `path`, `reconnectionDelay`, `timeout`, etc.).\nFor PartySocket connections, options are applied to the WebSocket instance.",
  "type": "NovuSocketOptions"
},
"useCache": {
  "description": "",
  "type": "boolean"
},
"defaultSchedule": {
  "description": "",
  "type": "DefaultSchedule"
},
"context": {
  "description": "",
  "type": "Partial<Record<string, ContextValue>>"
},
"subscriberId": {
  "description": "",
  "type": "string"
},
"subscriber": {
  "description": "",
  "type": "string | Subscriber"
}
}}
/>

### Usage

<Tabs items={['US', 'EU', 'Using Context', 'HMAC Encryption']}>
  <Tab value="US">
    ```typescript
    import { Novu } from "@novu/js";

    const novu = new Novu({
      subscriberId: "SUBSCRIBER_ID",
      applicationIdentifier: "APPLICATION_IDENTIFIER",
    });
    ```
  </Tab>

  <Tab value="EU">
    ```typescript
    import { Novu } from "@novu/js";

    const novu = new Novu({
      subscriberId: "SUBSCRIBER_ID",
      applicationIdentifier: "APPLICATION_IDENTIFIER",
      apiUrl: "https://eu.api.novu.co",
      socketUrl: "wss://eu.socket.novu.co",
    });
    ```
  </Tab>

  <Tab value="Using Context">
    <Callout type="info"> Learn how Context is used to filter Inbox notifications in the [Inbox with Context](/platform/inbox/customization-and-configuration/inbox-with-context) guide. </Callout>

    ```tsx
    import { Novu } from '@novu/js';

    const novu = new Novu({
      applicationIdentifier: 'YOUR_APP_ID',
      subscriberId: 'user-123',
      context: {
        tenant: { id: 'org-123', data: { name: 'Acme Corp' } },
        team: 'team-456',
      },
    });

    // Access the current context
    console.log(novu.context);
    // → { tenant: { id: 'org-123', data: { name: 'Acme Corp' } }, team: 'team-456' }

    // Get a stable string key (used internally for caching/filtering)
    console.log(novu.contextKey);
    // → "team:team-456,tenant:org-123"

    ```
  </Tab>

  <Tab value="HMAC Encryption">
    ```typescript
    import { Novu } from "@novu/js";

    const novu = new Novu({
      subscriberId: "SUBSCRIBER_ID",
      applicationIdentifier: "APPLICATION_IDENTIFIER",
      subscriberHash: "SUBSCRIBER_HASH_HMAC_ENCRYPTION",
    });
    ```
  </Tab>
</Tabs>

## Notifications

### Methods

#### list

Fetches a list of notifications based on provided filters.

<TypeTable
  name="NotificationFilter"
  type={{
"tags": {
  "description": "",
  "type": "string[]"
},
"read": {
  "description": "",
  "type": "boolean"
},
"archived": {
  "description": "",
  "type": "boolean"
},
"snoozed": {
  "description": "",
  "type": "boolean"
},
"seen": {
  "description": "",
  "type": "boolean"
},
"data": {
  "description": "",
  "type": "Record<string, unknown>"
},
"severity": {
  "description": "",
  "type": "SeverityLevelEnum | SeverityLevelEnum[]"
},
"createdGte": {
  "description": "",
  "type": "number"
},
"createdLte": {
  "description": "",
  "type": "number"
}
}}
/>

```typescript
import { SeverityLevelEnum } from '@novu/js';
import dayjs from "dayjs";

const now = dayjs();
// convert to milliseconds
const startDate = now.subtract(60, "days").valueOf();
const endDate = now.valueOf();  

const notifications = await novu.notifications.list({
  limit: 30,
  read: false,
  seen: false,
  archived: false,
  tags: ['tag1', 'tag2'],
  severity: SeverityLevelEnum.HIGH,
  // data attributes
  data: {
    type: 'login',
  },
  offset: 0,
  // fetch last 60 days notifications
  createdGte: startDate,
  createdLte: endDate,
});
```

The response will be of type:

<TypeTable
  name="NotificationsResponse"
  type={{
"notifications": {
  "description": "",
  "type": "Notification[]"
},
"hasMore": {
  "description": "",
  "type": "boolean"
},
"filter": {
  "description": "",
  "type": "NotificationFilter"
}
}}
/>

#### count

Fetches the count of notifications based on filters.

<TypeTable
  name="NotificationFilter"
  type={{
"tags": {
  "description": "",
  "type": "string[]"
},
"read": {
  "description": "",
  "type": "boolean"
},
"archived": {
  "description": "",
  "type": "boolean"
},
"snoozed": {
  "description": "",
  "type": "boolean"
},
"seen": {
  "description": "",
  "type": "boolean"
},
"data": {
  "description": "",
  "type": "Record<string, unknown>"
},
"severity": {
  "description": "",
  "type": "SeverityLevelEnum | SeverityLevelEnum[]"
},
"createdGte": {
  "description": "",
  "type": "number"
},
"createdLte": {
  "description": "",
  "type": "number"
}
}}
/>

<Tabs items={['Single Filter', 'Multiple Filters']}>
  <Tab value="Single Filter">
    ```typescript
    // Single filter
    const count = await novu.notifications.count({
      read: false,
      seen: false,
      archived: false,
      severity: SeverityLevelEnum.HIGH,
       // data attributes
      data: {
        type: 'login',
      },
    });
    ```
  </Tab>

  <Tab value="Multiple Filters">
    ```typescript
    // Multiple filters
    const counts = await novu.notifications.count({
      filters: [
        { read: false }, 
        { seen: false }, 
        { severity: SeverityLevelEnum.HIGH }
        { archived: true }, 
        { tags: ['tag1'] }, 
        { data: { type: 'login' } }
      ],
    });
    ```
  </Tab>
</Tabs>

#### read

Marks a notification as read.

```typescript
await novu.notifications.read({ notificationId: 'NOTIFICATION_ID' });
```

#### unread

Marks a notification as unread.

```typescript
await novu.notifications.unread({ notificationId: 'NOTIFICATION_ID' });
```

#### seen

Marks a notification as seen.

```typescript
await novu.notifications.seen({ notificationId: 'NOTIFICATION_ID' });
```

<Callout type="info">
  **Seen vs Read**: Notifications can be "seen" (automatically tracked when visible) or "read" (explicitly marked by user interaction). The Inbox component automatically marks notifications as seen when they're visible for 1+ seconds using the browser's IntersectionObserver API. This automatic tracking batches requests for performance and works seamlessly with infinite scroll and pagination, while read status requires explicit user action.

  **Why no `unseen` method?** Unlike `read`/`unread` which can be toggled, `seen` is designed as a one-way operation. Once a notification has been seen by a user, it remains seen. This reflects the natural user experience where visibility cannot be "undone". Use filtering with `seen: false` to get unseen notifications instead.
</Callout>

#### seenAll

Marks notifications as seen. You can filter them by notification IDs, tags, or data attributes.

```typescript
// Mark specific notifications as seen
await novu.notifications.seenAll({
  notificationIds: ['NOTIFICATION_ID_1', 'NOTIFICATION_ID_2']
});

// Mark notifications by tags as seen
await novu.notifications.seenAll({
  tags: ['tag1', 'tag2']
});

// Mark notifications by data as seen
await novu.notifications.seenAll({
  data: { type: 'login' }
});

// Mark all notifications as seen (no filters)
await novu.notifications.seenAll();
```

#### archive

Archives a notification.

```typescript
await novu.notifications.archive({ notificationId: 'NOTIFICATION_ID' });
```

#### unarchive

Unarchives a notification.

```typescript
await novu.notifications.unarchive({ notificationId: 'NOTIFICATION_ID' });
```

#### readAll

Marks all notifications as read. You can filter them by tags.

```typescript
await novu.notifications.readAll({
  tags: ['tag1', 'tag2'],
  // data attributes
  data: {
    type: 'login',
  },
});
```

#### archiveAll

Archives all notifications. You can filter them by tags.

```typescript
await novu.notifications.archiveAll({
  tags: ['tag1', 'tag2'],
  // data attributes
  data: {
    type: 'login',
  },
});
```

#### archiveAllRead

Archives all read notifications. You can filter them by tags.

```typescript
await novu.notifications.archiveAllRead({
  tags: ['tag1', 'tag2'],
  // data attributes
  data: {
    type: 'login',
  },
});
```

#### delete

Deletes a single notification permanently.

```typescript
await novu.notifications.delete({ notificationId: 'NOTIFICATION_ID' });
```

#### deleteAll

Deletes multiple notifications permanently. You can filter them by tags or data attributes.

```typescript
// Delete specific notifications by tags
await novu.notifications.deleteAll({
  tags: ['tag1', 'tag2'],
});

// Delete notifications by data attributes
await novu.notifications.deleteAll({
  data: { type: 'login' },
});

// Delete all notifications (no filters)
await novu.notifications.deleteAll();
```

#### snooze

Snoozes a notification for a specified duration. Here `snoozeUntil` is **ISO 8601** formatted string timestamp, representing the date and time the notification is un-snoozed, it should be a future date and time.

```typescript
await novu.notifications.snooze({ notificationId: 'NOTIFICATION_ID', snoozeUntil: '2025-01-01T00:00:00.000Z' });
```

#### unsnooze

Unsnoozes a notification.

```typescript
await novu.notifications.unsnooze({ notificationId: 'NOTIFICATION_ID' });
```

#### completePrimary

Marks primary action of a notification as completed.

```typescript
await novu.notifications.completePrimary({ notificationId: 'NOTIFICATION_ID' });
```

#### completeSecondary

Marks secondary action of a notification as completed.

```typescript
await novu.notifications.completeSecondary({ notificationId: 'NOTIFICATION_ID' });
```

#### revertPrimary

Reverts primary action of a notification to pending.

```typescript
await novu.notifications.revertPrimary({ notificationId: 'NOTIFICATION_ID' });
```

#### revertSecondary

Reverts secondary action of a notification to pending.

```typescript
await novu.notifications.revertSecondary({ notificationId: 'NOTIFICATION_ID' });
```

## Notification

Individual notification instances have their own methods for marking as seen, read, archived, etc. These methods are available directly on each notification object.

### Methods

* `seen()` - Marks the notification as seen
* `read()` - Marks the notification as read
* `unread()` - Marks the notification as unread
* `archive()` - Archives the notification
* `unarchive()` - Unarchives the notification
* `delete()` - Deletes the notification
* `snooze()` - Snoozes the notification
* `unsnooze()` - Unsnoozes the notification
* `completePrimary()` - Marks primary action as completed
* `completeSecondary()` - Marks secondary action as completed
* `revertPrimary()` - Reverts primary action to pending
* `revertSecondary()` - Reverts secondary action to pending

<Callout type="info">The `seen()` method is only available on individual notification instances, not on the `novu.notifications` object. Use `novu.notifications.seenAll()` for bulk operations.</Callout>

### Usage

```typescript
// Get notifications
const { data: notifications } = await novu.notifications.list();

// Mark a specific notification as seen using the instance method
await notifications[0].seen();

// Mark as read using the instance method
await notifications[0].read();

// Archive using the instance method
await notifications[0].archive();

// Snooze using the instance method
await notifications[0].snooze('2025-01-01T00:00:00.000Z');

// Unsnooze using the instance method
await notifications[0].unsnooze();

// Delete using the instance method
await notifications[0].delete();
```

## Preferences

### Methods

#### list

Fetches the subscriber's notification preferences.

```typescript
const { data: preferences } = await novu.preferences.list();
```

#### update

`update` method is available with each preference object.

```typescript
const { data: preferences } = await novu.preferences.list();

// Update a single preference

await preferences[0].update({ channels: { email: false, sms: true } });
```

The response will be of type:

<TypeTable
  name="PreferenceResponse"
  type={{
"level": {
  "description": "",
  "type": "PreferenceLevel"
},
"enabled": {
  "description": "",
  "type": "boolean"
},
"condition": {
  "description": "",
  "type": "RulesLogic"
},
"subscriptionId": {
  "description": "",
  "type": "string"
},
"channels": {
  "description": "",
  "type": "ChannelPreference"
},
"overrides": {
  "description": "",
  "type": "IPreferenceOverride[]"
},
"workflow": {
  "description": "",
  "type": "Workflow"
},
"schedule": {
  "description": "",
  "type": "{ isEnabled: boolean; weeklySchedule?: WeeklySchedule | undefined; }"
}
}}
/>

#### bulkUpdate

Updates multiple workflow's channel preferences at once.

```typescript
await novu.preferences.bulkUpdate([
  { workflowId: 'workflow_id', channels: { email: false, sms: true } },
  { workflowId: 'workflow_id_2', channels: { email: true, sms: false, in_app: true } },
]);
```

### Schedule

The `preferences.schedule` submodule lets you fetch and update a subscriber’s delivery schedule.

#### get

Fetches the subscriber’s schedule.

```tsx
const novu = new Novu(...);

const { data: { schedule } } = await novu.preferences.schedule.get();
```

#### update

Updates the subscriber’s schedule. You can update the entire weekly schedule or only specific days.

```tsx
const novu = new Novu(...);

// Update schedule via preferences
const { data: { schedule } } = await novu.preferences.schedule.update({
  weeklySchedule: {
    monday: {
      isEnabled: true,
      hours: [{ start: '09:00 AM', end: '05:00 PM' }],
    },
  },
});

// Or update directly from a Schedule instance
const { data: { schedule: updatedSchedule } } =
  await schedule.update({ isEnabled: false });
```

### Schedule Class

A `Schedule` instance is returned when fetching or updating a schedule.

<TypeTable
  name="Schedule"
  type={{
"isEnabled": {
  "description": "",
  "type": "boolean | undefined"
},
"weeklySchedule": {
  "description": "",
  "type": "WeeklySchedule | undefined"
},
"update": {
  "description": "",
  "type": "(args: UpdateScheduleArgs) => Result<Schedule, NovuError>"
}
}}
/>

## Events

The Novu client provides real-time event handling through WebSocket connections.

### Available Events

* `notifications.notification_received`: Triggered when a new notification is received.
* `notifications.unread_count_changed`: Triggered when the unread count changes.
* `notifications.unseen_count_changed`: Triggered when the unseen count changes.
* `preferences.schedule.get.pending`: Triggered when fetching a schedule starts.
* `preferences.schedule.get.resolved`: Triggered when fetching a schedule succeeds.
* `preferences.schedule.update.pending`: Triggered when updating a schedule starts.
* `preferences.schedule.update.resolved`: Triggered when updating a schedule succeeds.
* `subscriptions.list.pending`: Triggered when loading subscriptions starts.
* `subscriptions.list.resolved`: Triggered when subscriptions are loaded.
* `subscriptions.get.pending`: Triggered when fetching a subscription starts.
* `subscriptions.get.resolved`: Triggered when a specific subscription is fetched.
* `subscriptions.create.pending`: Triggered when creating a subscription starts.
* `subscriptions.create.resolved`: Triggered when a subscription is created.
* `subscriptions.update.pending`: Triggered when updating a subscription starts.
* `subscriptions.update.resolved`: Triggered when a subscription is updated.
* `subscriptions.delete.pending`: Triggered when deleting a subscription start.
* `subscriptions.delete.resolved`: Triggered when a subscription is deleted.

### Usage

```typescript

novu.on('session.initialize.resolved', ({ data }: { data: Session }) => {
  console.log(data.unreadCount.total);
  console.log(data.unreadCount.severity[SeverityLevelEnum.HIGH]);
});

novu.on('notifications.notification_received', (data) => {
  console.log('New notification:', data);
});

novu.on('notifications.unread_count_changed', (data) => {
  console.log('Unread count:', data);
});

novu.on('notifications.unseen_count_changed', (data) => {
  console.log('Unseen count:', data);
});

novu.on('preferences.schedule.update.resolved', ({ data }) => {
  console.log('Schedule updated:', data.schedule);
});

novu.on('subscriptions.create.resolved', ({ data: subscription }) => {
  console.log('New subscription created:', subscription.identifier);
});

novu.on('subscriptions.list.resolved', ({ data: subscriptions }) => {
  console.log('Loaded subscriptions:', subscriptions.length);
});

```

## Subscriptions

The Subscriptions module lets you manage a subscriber’s subscriptions to topics. A subscription represents a subscriber’s opt-in to a topic and defines which workflows within that topic they receive notifications from.

It supports creating conditional subscriptions where users only receive notifications if specific criteria (payload filters) are met.

Manage subscriptions at two levels:

* Module-level methods on `novu.subscriptions`
* Instance-level methods on a `TopicSubscription` object

### Methods

#### List

Fetches all subscriptions for a specific topic.

<TypeTable
  name="ListSubscriptionsArgs"
  type={{
"topicKey": {
  "description": "",
  "type": "string"
}
}}
/>

```tsx
const { data: subscriptions } = await novu.subscriptions.list({
  topicKey: 'product-updates'
});
```

The response items are `TopicSubscription` instances.

#### get

Fetch a single subscription by topic and identifier.

<TypeTable
  name="GetSubscriptionArgs"
  type={{
"topicKey": {
  "description": "",
  "type": "string"
},
"identifier": {
  "description": "",
  "type": "string"
},
"workflowIds": {
  "description": "",
  "type": "string[]"
},
"tags": {
  "description": "",
  "type": "string[]"
}
}}
/>

```tsx
const { data: subscription } = await novu.subscriptions.get({
  topicKey: 'product-updates',
  identifier: 'user-product-alert'
});
```

#### create

Create a new subscription to a topic. You can pass a list of preferences to filter specific workflows or tags.

<TypeTable
  name="CreateSubscriptionArgs"
  type={{
"topicKey": {
  "description": "",
  "type": "string"
},
"topicName": {
  "description": "",
  "type": "string"
},
"identifier": {
  "description": "",
  "type": "string"
},
"name": {
  "description": "",
  "type": "string"
},
"preferences": {
  "description": "",
  "type": "PreferenceFilter[]"
}
}}
/>

```tsx
const { data: subscription } = await novu.subscriptions.create({
  topicKey: 'product-updates',
  identifier: 'user-product-alert',
  preferences: [
    {
      // Simple workflow toggle
      workflowId: 'issue-created',
      enabled: true
    },
    {
      // Conditional filter
      workflowId: 'price-alert',
      condition: {
        field: 'price',
        operation: 'below',
        value: 100
      }
    }
  ]
});
```

#### update

Updates an existing subscription.

<TypeTable
  name="UpdateSubscriptionArgs"
  type={{
"name": {
  "description": "",
  "type": "string"
},
"preferences": {
  "description": "",
  "type": "PreferenceFilter[]"
}
}}
/>

```tsx
const { data: subscription } = await novu.subscriptions.update({
  topicKey: 'product-updates',
  subscriptionId: 'subscription-id-123',
  preferences: [...]
});
```

#### delete

Delete a subscription by topic and subscription ID.

```tsx
await novu.subscriptions.delete({
  topicKey: 'product-updates',
  subscriptionId: 'product-updates-subscription',
});
```

### TopicSubscription

A `TopicSubscription` instance represents a single subscription and provides methods for updating or deleting it, as well as managing its preferences.

<TypeTable
  name="TopicSubscription"
  type={{
"id": {
  "description": "",
  "type": "string"
},
"identifier": {
  "description": "",
  "type": "string"
},
"topicKey": {
  "description": "",
  "type": "string"
},
"preferences": {
  "description": "",
  "type": "SubscriptionPreference[]"
},
"update": {
  "description": "",
  "type": "{ (args: BaseUpdateSubscriptionArgs): Result<TopicSubscription, NovuError>; (args: InstanceUpdateSubscriptionArgs): Result<...>; }"
},
"updatePreference": {
  "description": "",
  "type": "{ (args: BaseSubscriptionPreferenceArgs): Result<SubscriptionPreference, NovuError>; (args: InstanceSubscriptionPreferenceArgs): Result<...>; }"
},
"bulkUpdatePreferences": {
  "description": "",
  "type": "{ (args: BaseSubscriptionPreferenceArgs[]): Result<SubscriptionPreference[], NovuError>; (args: InstanceSubscriptionPreferenceArgs[]): Result<...>; }"
},
"delete": {
  "description": "",
  "type": "() => Result<void, NovuError>"
}
}}
/>

#### Update a subscription

Update subscription metadata or replace its preferences list. Use this method when updating the subscription as a whole.
For granular preference updates, use preference-level methods instead.

```tsx
const { data: subscription } =
  await novu.subscriptions.get({
    topicKey: 'product-updates',
    identifier: 'product-updates-subscription',
  });

await subscription.update({
  preferences: [
    {
      workflowId: 'workflow-identifier',
      enabled: true,
    },
  ],
});
```

#### Update SubscriptionPreference

Each subscription contains a list of `SubscriptionPreference` objects that you can update individually.

<TypeTable
  name="SubscriptionPreference"
  type={{
"subscriptionId": {
  "description": "",
  "type": "string"
},
"workflow": {
  "description": "",
  "type": "Workflow"
},
"enabled": {
  "description": "",
  "type": "boolean"
},
"condition": {
  "description": "",
  "type": "RulesLogic"
},
"update": {
  "description": "",
  "type": "(args: { value: RulesLogic; }) => Result<SubscriptionPreference, NovuError>"
}
}}
/>

```tsx
subscription.preferences.map((preference) => {
  const onChange = (value: boolean) => {
    preference.update({ value });
  };

  return <Checkbox onChange={onChange} />;
});
```

#### Delete a subscription (instance method)

```
await subscription.delete();
```

## Types

### Notification

<TypeTable
  name="Notification"
  type={{
"id": {
  "description": "",
  "type": "string"
},
"transactionId": {
  "description": "",
  "type": "string"
},
"subject": {
  "description": "",
  "type": "string"
},
"body": {
  "description": "",
  "type": "string"
},
"to": {
  "description": "",
  "type": "Subscriber"
},
"isRead": {
  "description": "",
  "type": "boolean"
},
"isSeen": {
  "description": "",
  "type": "boolean"
},
"isArchived": {
  "description": "",
  "type": "boolean"
},
"isSnoozed": {
  "description": "",
  "type": "boolean"
},
"snoozedUntil": {
  "description": "",
  "type": "string | null"
},
"deliveredAt": {
  "description": "",
  "type": "string[]"
},
"createdAt": {
  "description": "",
  "type": "string"
},
"readAt": {
  "description": "",
  "type": "string | null"
},
"firstSeenAt": {
  "description": "",
  "type": "string | null"
},
"archivedAt": {
  "description": "",
  "type": "string | null"
},
"avatar": {
  "description": "",
  "type": "string"
},
"primaryAction": {
  "description": "",
  "type": "Action"
},
"secondaryAction": {
  "description": "",
  "type": "Action"
},
"channelType": {
  "description": "",
  "type": "ChannelType"
},
"tags": {
  "description": "",
  "type": "string[] | undefined"
},
"redirect": {
  "description": "",
  "type": "Redirect | undefined"
},
"data": {
  "description": "",
  "type": "NotificationData"
},
"workflow": {
  "description": "",
  "type": "Workflow"
},
"severity": {
  "description": "",
  "type": "SeverityLevelEnum"
},
"read": {
  "description": "",
  "type": "() => Result<Notification, NovuError>"
},
"unread": {
  "description": "",
  "type": "() => Result<Notification, NovuError>"
},
"seen": {
  "description": "",
  "type": "() => Result<Notification, NovuError>"
},
"archive": {
  "description": "",
  "type": "() => Result<Notification, NovuError>"
},
"unarchive": {
  "description": "",
  "type": "() => Result<Notification, NovuError>"
},
"delete": {
  "description": "",
  "type": "() => Result<void, NovuError>"
},
"snooze": {
  "description": "",
  "type": "(snoozeUntil: string) => Result<Notification, NovuError>"
},
"unsnooze": {
  "description": "",
  "type": "() => Result<Notification, NovuError>"
},
"completePrimary": {
  "description": "",
  "type": "() => Result<Notification, NovuError>"
},
"completeSecondary": {
  "description": "",
  "type": "() => Result<Notification, NovuError>"
},
"revertPrimary": {
  "description": "",
  "type": "() => Result<Notification, NovuError>"
},
"revertSecondary": {
  "description": "",
  "type": "() => Result<Notification, NovuError>"
},
"on": {
  "description": "",
  "type": "<Key extends EventNames>(eventName: Key, listener: EventHandler<Events[Key]>) => () => void"
},
"off": {
  "description": "",
  "type": "<Key extends EventNames>(eventName: Key, listener: EventHandler<Events[Key]>) => void"
}
}}
/>

### Subscriber

<TypeTable
  name="Subscriber"
  type={{
"id": {
  "description": "",
  "type": "string"
},
"subscriberId": {
  "description": "",
  "type": "string"
},
"firstName": {
  "description": "",
  "type": "string"
},
"lastName": {
  "description": "",
  "type": "string"
},
"email": {
  "description": "",
  "type": "string"
},
"phone": {
  "description": "",
  "type": "string"
},
"avatar": {
  "description": "",
  "type": "string"
},
"locale": {
  "description": "",
  "type": "string"
},
"data": {
  "description": "",
  "type": "Record<string, unknown>"
},
"timezone": {
  "description": "",
  "type": "string"
}
}}
/>
