curl https://api.bodhveda.com/recipients/recipient_123/preferences \
-H "Authorization: Bearer bv_xxxxxxxxx" import { Bodhveda } from "@bodhveda/js";
const bodhveda = new Bodhveda("bv_xxxxxxxxx");
const { preferences } = await bodhveda.recipients.preferences.list("recipient_123");import (
"context"
bodhveda "github.com/MudgalLabs/bodhveda/sdk/go"
)
ctx := context.Background()
client := bodhveda.NewClient("bv_xxxxxxxxx", nil)
res, _ := client.Recipients.Preferences.List(ctx, "recipient_123")
// res.Preferencesimport { usePreferences } from "@bodhveda/react";
// Requires a <BodhvedaProvider recipientID="recipient_123"> higher in the tree.
function Preferences() {
const { data, isLoading } = usePreferences();
if (isLoading) return null;
return <PreferenceList items={data.preferences} />;
}{
"data": {
"preferences": [
{
"target": {
"channel": "posts",
"topic": "any",
"event": "new_comment",
"medium": "in_app",
"name": "Comments on your posts"
},
"state": {
"enabled": true,
"inherited": true,
"cataloged": true,
"mandatory": false
}
},
{
"target": {
"channel": "announcements",
"topic": "none",
"event": "new_feature",
"medium": "email",
"name": "Product Announcements"
},
"state": {
"enabled": false,
"inherited": false,
"cataloged": true,
"mandatory": false
}
},
{
"target": {
"channel": "announcements",
"topic": "none",
"event": "new_feature",
"medium": "in_app"
},
"state": {
"enabled": true,
"inherited": true,
"cataloged": false,
"mandatory": false
}
}
]
}
}List preferences
Every (target, medium) known for this recipient, each with the state a send would actually act on.
state.enabled is the resolved decision — the same answer the delivery path computes — not a raw stored row. Resolution walks, in order:
- the recipient’s rule for the exact target,
- the recipient’s
topic: anyrule for the channel/event, - the project’s rule for the exact target,
- the project’s
topic: anyrule, - the medium’s default.
The default is per medium: in_app delivers, every other medium does not. A topic: none target never takes an any rule.
The response covers every target in the project catalog plus any target this recipient has a rule of their own for, across the active mediums (in_app and email). So a recipient can have an entry for a (target, medium) you never cataloged — if they have an explicit rule for it, it is live, and this reports it.
Each state carries:
enabled— whether a send to this(target, medium)would deliver.inherited—truewhen the recipient has no rule of their own for this exact(target, medium); the value came from elsewhere in the cascade.falsemeans they set it explicitly.cataloged— whether a project-level rule exists for this exact(target, medium). This is context, not a gate: an explicit recipient rule on an uncataloged pair still delivers, andin_appdelivers by default with no catalog entry at all. Use it to decide what to render, never to predict delivery —enabledis the answer.
curl https://api.bodhveda.com/recipients/recipient_123/preferences \
-H "Authorization: Bearer bv_xxxxxxxxx" import { Bodhveda } from "@bodhveda/js";
const bodhveda = new Bodhveda("bv_xxxxxxxxx");
const { preferences } = await bodhveda.recipients.preferences.list("recipient_123");import (
"context"
bodhveda "github.com/MudgalLabs/bodhveda/sdk/go"
)
ctx := context.Background()
client := bodhveda.NewClient("bv_xxxxxxxxx", nil)
res, _ := client.Recipients.Preferences.List(ctx, "recipient_123")
// res.Preferencesimport { usePreferences } from "@bodhveda/react";
// Requires a <BodhvedaProvider recipientID="recipient_123"> higher in the tree.
function Preferences() {
const { data, isLoading } = usePreferences();
if (isLoading) return null;
return <PreferenceList items={data.preferences} />;
}{
"data": {
"preferences": [
{
"target": {
"channel": "posts",
"topic": "any",
"event": "new_comment",
"medium": "in_app",
"name": "Comments on your posts"
},
"state": {
"enabled": true,
"inherited": true,
"cataloged": true,
"mandatory": false
}
},
{
"target": {
"channel": "announcements",
"topic": "none",
"event": "new_feature",
"medium": "email",
"name": "Product Announcements"
},
"state": {
"enabled": false,
"inherited": false,
"cataloged": true,
"mandatory": false
}
},
{
"target": {
"channel": "announcements",
"topic": "none",
"event": "new_feature",
"medium": "in_app"
},
"state": {
"enabled": true,
"inherited": true,
"cataloged": false,
"mandatory": false
}
}
]
}
}(target, medium) known for this recipient, each resolved — state.enabled is what a send would actually do, not a raw stored row. To manage project preferences (the catalog), use the Project Preferences endpoints or Bodhveda Console > Preferences.
💡 You should show these preferences on your “Notification settings” screen where the recipient can see their current preferences and update them with set preference.
inherited: falsemeans the recipient has explicitly overridden this(target, medium);truemeans the value came from elsewhere in the cascade (atopic: anyrule, the catalog, or the medium’s default).cataloged: falsemeans your project has no rule declared for that exact(target, medium). It is not a reason to treat the pair as unavailable — in-app delivers by default, and a recipient’s own rule sends email regardless. It tells you what you declared, not what happens;enabledtells you what happens.
(target, medium) pairs you never cataloged, whenever they resolve to something a recipient can act on. That is deliberate: if a recipient has a rule for it, or a medium delivers by default, hiding it would show them a setting that disagrees with their inbox.Authorizations
Bearer authentication header of the form Bearer bv_xxxxxxxxx, where bv_xxxxxxxxx is your API Key with Full access or Recipient acess scope.
Path Parameters
The unique identifier of the recipient.
Response
List of recipient's resolved preferences.