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 sametopicKey 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.
- Server API: pass a
contextobject in the create request body (same shape as trigger Context). @novu/js/@novu/react: passcontextwhen initializing the Novu client or<NovuProvider>. The session inherits that Context for all subscription API calls.
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
- Node.js
- Python
- Go
- PHP
- .NET
- Java
- cURL
Subscription with Context
Scope a subscription to a tenant (or any Context type) by passingcontext in the request body:
- Node.js
- Python
- Go
- PHP
- .NET
- Java
- cURL
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 totrue receive the notification.
- Node.js
- Python
- Go
- PHP
- .NET
- Java
- cURL
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:
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
Pre-built components
If you want a ready-made subscribe/preferences UI, use<Subscription />, <SubscriptionButton />, and <SubscriptionPreferences /> inside <NovuProvider>:
<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.*.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., orcontext.). For example, usepayload.tierrather thantier.
Examples
Tier is premium:actor, conditions that reference actor.* evaluate against missing data and typically do not match.
Context tenant:
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:- Novu looks up subscriptions on the topic (including Context exact-match filtering).
- For each candidate subscription, Novu evaluates JSON Logic conditions against the trigger payload, subscriber profile, optional actor, and resolved context.
- Only subscriptions that pass proceed to workflow run creation.
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)