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

# @novu/js

> Complete API reference for the @novu/js browser SDK, covering the Novu client, notification streams, preferences, counts, Web Chat, and session management.

## Novu

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

### Constructor Options

| Property | Type | Description |
| - | - | - |
| `backendUrl` | `string` | |
| `applicationIdentifier` | `string` | |
| `subscriberHash` | `string` | |
| `contextHash` | `string` | |
| `apiUrl` | `string` | |
| `socketUrl` | `string` | |
| `socketOptions` | `NovuSocketOptions` | Custom socket configuration options. These options will be merged with the default socket configuration. Use `socketType` to explicitly select the socket implementation: `'cloud'` for PartySocket or `'self-hosted'` for socket.io. For socket.io-client connections, supports all socket.io-client options (e.g., `path`, `reconnectionDelay`, `timeout`, etc.). For PartySocket connections, options are applied to the WebSocket instance. |
| `useCache` | `boolean` | |
| `defaultSchedule` | `DefaultSchedule` | |
| `context` | `Partial<Record<string, ContextValue>>` | |
| `subscriberId` | `string` | |
| `subscriber` | `string \| Subscriber` | |

### Usage

<Tabs>
  <Tab title="US">
    ```typescript theme={null}
    import { Novu } from "@novu/js";

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

  <Tab title="EU">
    ```typescript theme={null}
    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 title="Using Context">
    <Note> Learn how Context is used to filter Inbox notifications in the [Inbox with Context](/platform/inbox/configuration/inbox-with-context) guide. </Note>

    ```tsx theme={null}
    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 title="HMAC Encryption">
    ```typescript theme={null}
    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.

| Property | Type | Description |
| - | - | - |
| `tags` | `TagsFilter` | |
| `read` | `boolean` | |
| `archived` | `boolean` | |
| `snoozed` | `boolean` | |
| `seen` | `boolean` | |
| `data` | `Record<string, unknown>` | |
| `severity` | `SeverityLevelEnum \| SeverityLevelEnum[]` | |
| `createdGte` | `number` | |
| `createdLte` | `number` | |

```typescript theme={null}
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:

| Property | Type | Description |
| - | - | - |
| `notifications` | `Notification[]` | |
| `hasMore` | `boolean` | |
| `filter` | `NotificationFilter` | |

#### count

Fetches the count of notifications based on filters.

| Property | Type | Description |
| - | - | - |
| `tags` | `TagsFilter` | |
| `read` | `boolean` | |
| `archived` | `boolean` | |
| `snoozed` | `boolean` | |
| `seen` | `boolean` | |
| `data` | `Record<string, unknown>` | |
| `severity` | `SeverityLevelEnum \| SeverityLevelEnum[]` | |
| `createdGte` | `number` | |
| `createdLte` | `number` | |

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

  <Tab title="Multiple Filters">
    ```typescript theme={null}
    // 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 theme={null}
await novu.notifications.read({ notificationId: 'NOTIFICATION_ID' });
```

#### unread

Marks a notification as unread.

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

#### seen

Marks a notification as seen.

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

<Note>
  **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.
</Note>

#### seenAll

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

```typescript theme={null}
// 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 theme={null}
await novu.notifications.archive({ notificationId: 'NOTIFICATION_ID' });
```

#### unarchive

Unarchives a notification.

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

#### readAll

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

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

#### archiveAll

Archives all notifications. You can filter them by tags.

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

#### archiveAllRead

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

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

#### delete

Deletes a single notification permanently.

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

#### deleteAll

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

```typescript theme={null}
// 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 theme={null}
await novu.notifications.snooze({ notificationId: 'NOTIFICATION_ID', snoozeUntil: '2025-01-01T00:00:00.000Z' });
```

#### unsnooze

Unsnoozes a notification.

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

#### completePrimary

Marks primary action of a notification as completed.

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

#### completeSecondary

Marks secondary action of a notification as completed.

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

#### revertPrimary

Reverts primary action of a notification to pending.

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

#### revertSecondary

Reverts secondary action of a notification to pending.

```typescript theme={null}
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

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

### Usage

```typescript theme={null}
// 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 theme={null}
const { data: preferences } = await novu.preferences.list();
```

#### update

`update` method is available with each preference object.

```typescript theme={null}
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:

| Property | Type | Description |
| - | - | - |
| `level` | `PreferenceLevel` | |
| `enabled` | `boolean` | |
| `condition` | `RulesLogic` | |
| `subscriptionId` | `string` | |
| `channels` | `ChannelPreference` | |
| `overrides` | `IPreferenceOverride[]` | |
| `workflow` | `Workflow` | |
| `schedule` | `{ isEnabled: boolean; weeklySchedule?: WeeklySchedule; }` | |

#### bulkUpdate

Updates multiple workflow's channel preferences at once.

```typescript theme={null}
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 theme={null}
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 theme={null}
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.

| Property | Type | Description |
| - | - | - |
| `isEnabled` | `boolean` | |
| `weeklySchedule` | `WeeklySchedule` | |
| `update` | `(args: UpdateScheduleArgs) => Result<Schedule>` | |

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

#### Connection events

The client also emits socket lifecycle events so you can surface real-time connection state (for example, a "reconnecting" banner). Each payload carries the `socketUrl` in its `args`.

* `socket.connect.pending`: Triggered when the real-time socket starts connecting.
* `socket.connect.resolved`: Triggered when a connection attempt finishes, whether it succeeds or fails. On failure, the payload includes an `error`.
* `socket.disconnect.resolved`: Triggered when the real-time socket drops or `disconnect()` is called. Use it to show a connection-lost state.

### Usage

```typescript theme={null}

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);
});

novu.on('socket.connect.resolved', ({ args, error }) => {
  if (error) {
    console.error('Real-time connection failed:', args.socketUrl, error);
    return;
  }
  console.log('Real-time connection is live:', args.socketUrl);
});

novu.on('socket.disconnect.resolved', ({ args }) => {
  console.log('Real-time connection dropped:', args.socketUrl);
});

```

## 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 when the trigger payload matches a JSON Logic rule (for example, `payload.tier` is `premium`). Subscriber profile, Context data, and step results are not available in subscription conditions. Use [step conditions](/platform/workflow/add-and-configure-steps/step-conditions) for those cases.

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.

| Property | Type | Description |
| - | - | - |
| `topicKey` | `string` | |

```tsx theme={null}
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.

| Property | Type | Description |
| - | - | - |
| `topicKey` | `string` | |
| `identifier` | `string` | |
| `workflowIds` | `string[]` | |
| `tags` | `string[]` | |

```tsx theme={null}
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.

| Property | Type | Description |
| - | - | - |
| `topicKey` | `string` | |
| `topicName` | `string` | |
| `identifier` | `string` | |
| `name` | `string` | |
| `preferences` | `PreferenceFilter[]` | |

```tsx theme={null}
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: JSON Logic evaluated against trigger payload
      workflowId: 'price-alert',
      condition: {
        '===': [{ var: 'payload.tier' }, 'premium'],
      },
    }
  ]
});
```

#### update

Updates an existing subscription.

| Property | Type | Description |
| - | - | - |
| `name` | `string` | |
| `preferences` | `PreferenceFilter[]` | |

```tsx theme={null}
const { data: subscription } = await novu.subscriptions.update({
  topicKey: 'product-updates',
  identifier: 'user-product-alert',
  preferences: [...]
});
```

#### delete

Delete a subscription by topic and subscription ID.

```tsx theme={null}
await novu.subscriptions.delete({
  topicKey: 'product-updates',
  identifier: '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.

| Property | Type | Description |
| - | - | - |
| `id` | `string` | |
| `identifier` | `string` | |
| `topicKey` | `string` | |
| `preferences` | `SubscriptionPreference[]` | |
| `update` | `{ (args: BaseUpdateSubscriptionArgs): Result<TopicSubscription>; (args: InstanceUpdateSubscriptionArgs): Result<TopicSubscription>; }` | |
| `updatePreference` | `{ (args: BaseSubscriptionPreferenceArgs): Result<SubscriptionPreference>; (args: InstanceSubscriptionPreferenceArgs): Result<SubscriptionPreference>; }` | |
| `bulkUpdatePreferences` | `{ (args: Array<BaseSubscriptionPreferenceArgs>): Result<SubscriptionPreference[]>; (args: Array<InstanceSubscriptionPreferenceArgs>): Result<SubscriptionPreference[]>; }` | |
| `delete` | `() => Result<void>` | |

#### 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 theme={null}
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.

| Property | Type | Description |
| - | - | - |
| `subscriptionId` | `string` | |
| `workflow` | `Workflow` | |
| `enabled` | `boolean` | |
| `condition` | `RulesLogic` | |
| `update` | `(args: { value: boolean \| RulesLogic; }) => Result<SubscriptionPreference>` | |

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

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

#### Delete a subscription (instance method)

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

## Web Chat

Two-way in-app chat with an agent. Call `loadWebChat(novu)` before `novu.webChat.conversation()`. React apps use [`useWebChat`](/platform/sdks/react/hooks/use-web-chat), which loads Web Chat automatically.

See [Web Chat](/agents/channels/web-chat).

### conversation()

`conversation()` returns a runtime for one conversation. If you pass `conversationId`, later calls with the same `agentId` and `conversationId` reuse that runtime. If you omit `conversationId`, each call creates a new runtime and a new socket. Keep the returned object. When the chat unmounts, call `dispose()`.

Do not call `novu.webChat.subscribe()` from UI code. The runtime owns the socket.

| Argument | Type | Description |
| - | - | - |
| `agentId` | `string` | Public agent identifier from the dashboard. |
| `conversationId` | `string` | Resume this conversation. Omit this argument to start a new chat. |
| `agentHash` | `string` | HMAC of `agentId`. Required when Web Chat HMAC is on. |

```typescript theme={null}
import { Novu, loadWebChat } from '@novu/js';

const novu = new Novu({
  applicationIdentifier: 'YOUR_APPLICATION_IDENTIFIER',
  subscriberId: 'YOUR_SUBSCRIBER_ID',
});

await loadWebChat(novu);

const conversation = novu.webChat.conversation({
  agentId: 'YOUR_AGENT_IDENTIFIER',
});

const stop = conversation.subscribe((snapshot) => {
  snapshot.messages;
  snapshot.run.isRunning;
  snapshot.conversationId;
});

const { data, error } = await conversation.sendMessage('Hello');
// data.conversationId — store this to resume later

stop();
conversation.dispose();
```

### Runtime methods

| Method | Description |
| - | - |
| `getSnapshot()` | Current immutable snapshot. |
| `subscribe(listener)` | Call `listener` on every snapshot. Returns a stop function. |
| `sendMessage(input)` | Send a user message. `input` is a string, or `{ text, metadata }`. Creates a conversation when `conversationId` is omitted. |
| `retryMessage(messageId)` | Resend a message whose `status` is `failed`. Reuses the original idempotency key. |
| `respondToAction({ approvalId, decision })` | Resolve a pending `approval`. Pass `approvalId` from `pendingActions` or message parts. |
| `sendAction({ actionId, sourceMessageId, value })` | Click a Card button. Do not use this for tool approval. |
| `fetchMore()` | Load the next older history page. |
| `load()` | Reload the newest history page. Runs on resume when `conversationId` is set. |
| `dispose()` | Stop listeners and release the socket. |

### Snapshot fields

| Field | Description |
| - | - |
| `messages` | Conversation timeline. |
| `pendingActions` | Tool approvals and MCP connect items that are still pending. |
| `conversationId` | Server id after create or resume. |
| `run.isRunning` / `run.typing` | Agent-turn snapshot. |
| `conversationStatus` | `'active'` or `'resolved'`. This is not a loading flag. |
| `status` | History load: `'ready'`, `'loading'`, or `'fetching'`. |
| `pagination.hasMore` / `pagination.status` | Older history pages. Call `fetchMore()`. |
| `isRecovering` / `catchUpError` | Reconnect recovery. The runtime reconnects on its own. |
| `error` | Last load, send, retry, or action error. |

See [Messages](/agents/channels/web-chat/messages).

## Types

### Notification

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

### Subscriber

| Property | Type | Description |
| - | - | - |
| `id` | `string` | |
| `subscriberId` | `string` | |
| `firstName` | `string` | |
| `lastName` | `string` | |
| `email` | `string` | |
| `phone` | `string` | |
| `avatar` | `string` | |
| `locale` | `string` | |
| `data` | `Record<string, unknown>` | |
| `timezone` | `string` | |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.