Skip to main content
Topic subscriptions let a subscriber opt in to a topic with fine-grained rules. Each subscription can target specific workflows and include a JSON Logic condition that is evaluated when a workflow is triggered to the topic.
Conditions are evaluated at trigger time, not when the subscription is created. A subscription is always stored; Novu decides at delivery whether the condition matches the incoming event data.

Context-scoped subscriptions

Topic subscriptions can be scoped to a Context, the same metadata you pass when triggering a workflow. This lets one subscriber maintain separate subscriptions to the same topicKey for different tenants, apps, or regions without duplicating topics or workflows. Novu uses exact-match Context filtering for subscriptions, the same rules as the Inbox: Both sides must match: key for key and value for value. Passing Context on only the subscription or only the trigger is not enough.
When you omit Context on a subscription or trigger, Novu treats it as the default (no Context) scope, not as a wildcard that matches all Contexts.
At subscription create time, Context is stored on the subscription record:
  • Server API: pass a context object in the create request body (same shape as trigger Context).
  • @novu/js / @novu/react: pass context when initializing the Novu client or <NovuProvider>. The session inherits that Context for all subscription API calls.
At trigger time, pass the same Context on the workflow trigger. Novu resolves topic members whose stored Context matches the trigger Context, then evaluates each matching subscription’s JSON Logic condition. If Novu auto-generates a subscription identifier and Context is present, the identifier includes a :ctx_ suffix so subscriptions in different Contexts remain unique. See Contexts for structure, limits (up to five keys per trigger), and how Context differs from payload.

Choose an integration path

A subscriber can have up to 10 subscriptions per topic, each with its own identifier and conditions. See the introduction for how subscriptions fit into the notification flow.

Server API (Topics v2)

Use the server API when your backend creates subscriptions on behalf of subscribers, for example during onboarding or when syncing preferences from your database. Endpoint: POST /v2/topics/{topicKey}/subscriptions The topic is created automatically if it does not exist. You can pass subscriber IDs directly or use custom subscription identifiers when a subscriber needs multiple subscriptions on the same topic.

Basic subscription

Subscription with Context

Scope a subscription to a tenant (or any Context type) by passing context in the request body:
When you trigger the workflow to the topic, pass the same Context so this subscription is included:

Subscription with a JSON Logic condition

Attach a condition to a workflow preference. When you trigger the workflow to the topic, only subscriptions whose condition evaluates to true receive the notification.

Other server endpoints

API reference

Full request and response schemas for topic subscription endpoints.

Inbox API

The Inbox API is the subscriber-facing surface that powers @novu/js and @novu/react. It uses a subscriber session token (created from your applicationIdentifier and subscriberId) instead of an API key. You typically do not call these endpoints directly. Use the SDKs below instead.

@novu/js

Initialize the client with the subscriber’s credentials. Pass context when the subscription belongs to a specific tenant or app scope:
Then use novu.subscriptions:

Create a conditional subscription

Update a condition on an existing subscription

List, update, and delete

@novu/js reference

Full Subscriptions module API.

@novu/react

The React SDK exposes the same operations as hooks and pre-built components.

Headless hooks

For the full hook reference, see Headless hooks.

Pre-built components

If you want a ready-made subscribe/preferences UI, use <Subscription />, <SubscriptionButton />, and <SubscriptionPreferences /> inside <NovuProvider>:
See the quickstart for setup steps. For Context on <NovuProvider>, see Inbox with Context.

JSON Logic conditions

Subscription conditions use JSON Logic, the same rule format as step conditions. Reference trigger data with { "var": "<namespace>.<path>" }.

Condition variables

Topic subscription conditions are evaluated at trigger time when fanning out a workflow to a topic. The following namespaces are in scope:
Topic subscription conditions are evaluated at trigger time when fanning out a workflow to a topic. Context matching (which subscriptions are candidates) still happens before JSON Logic runs via exact-match Context filtering. Condition rules can additionally read resolved Context fields under context.*, and the optional trigger actor under actor.*.
Do not confuse Context matching with condition variables. Exact-match Context filtering selects which subscriptions are evaluated. JSON Logic can then read resolved Context values (for example context.tenant.id) along with payload, subscriber, and actor data.

Syntax rules

  • Use dot paths in { "var": "..." }. For example, { "var": "payload.tier" }, { "var": "subscriber.data.plan" }, or { "var": "context.tenant.id" }.
  • Do not use Liquid/template syntax ({{payload.tier}}) in conditions. That syntax is for workflow step content, not JSON Logic rules.
  • Always use the full namespace prefix (payload., subscriber., actor., or context.). For example, use payload.tier rather than tier.

Examples

Tier is premium:
Subscriber custom data:
Trigger actor:
Only subscriptions whose condition passes are delivered when the trigger includes a matching actor. If the trigger omits actor, conditions that reference actor.* evaluate against missing data and typically do not match. Context tenant:
Status and price combined:
Multiple matching rules (OR):

condition vs enabled

Preference filter formats

When creating preferences, use any of these shapes:
filter.workflowIds accepts either the workflow MongoDB _id or the workflow trigger identifier.

End-to-end flow

1

Create a subscription with a condition

Subscribe a user to a topic and attach a JSON Logic rule to a workflow preference (server API, @novu/js, or @novu/react).
2

Trigger the workflow to the topic

Send the workflow to the topic topicKey. Include fields your condition references in payload, and pass the same Context as the subscription when the subscription is Context-scoped:
3

Novu matches Context, then evaluates conditions

Novu first selects topic subscriptions whose stored Context exactly matches the trigger Context (including the default/no-Context case). For each matching subscription, Novu evaluates the JSON Logic condition against the trigger payload, subscriber profile, optional actor, and resolved context. Subscriptions that pass receive the notification; others are skipped.
Global and workflow channel preferences still apply. If a subscriber has disabled email globally, they will not receive email even when a subscription condition matches.

Billing and workflow runs

Novu Cloud bills by workflow runs: one execution of a workflow for one subscriber. Usage is counted when Novu creates a workflow run for that subscriber, not when you call the trigger API. Topic subscription filtering happens before that point, during topic fan-out:
  1. Novu looks up subscriptions on the topic (including Context exact-match filtering).
  2. For each candidate subscription, Novu evaluates JSON Logic conditions against the trigger payload, subscriber profile, optional actor, and resolved context.
  3. Only subscriptions that pass proceed to workflow run creation.
If a subscriber is filtered out because their Context does not match the trigger, or because their subscription condition evaluates to false, no workflow run is created for that subscriber and it does not count toward usage.
This is different from step conditions and channel preferences. Those run after a workflow run already exists. A subscriber who passes topic subscription filters but has steps skipped or channels muted still counts as one workflow run. See Trigger FAQ for the full billing picture.

What counts as billable for topic triggers

Limits

  • 10 subscriptions per subscriber per topic (across all Context scopes)
  • 512 characters max for a custom subscription identifier
  • 100 subscribers per create request (batch limit)