How user preferences work
A user’s preference is an override on a subscription topic’s default. Each topic you define in the Preferences Editor has a default status, and a user falls back to that default until they set their own choice. When they do, Courier stores it as an override on that topic. This shapes how the API behaves:- Reading returns each topic with the user’s
statusand the topic’sdefault_status. - Writing sets overrides. You only need to send topics where the user differs from the default.
- Deleting an override reverts the topic to its default.
status—OPTED_INorOPTED_OUT.custom_routing— the channels the user wants for the topic (email,sms,push,inbox,direct_message,webhook). Sethas_custom_routing: trueto apply it.topic_id— the subscription topic the preference belongs to. You get topic IDs from the Preferences Editor.
Authentication
Call the API server-side with your workspace API key as a bearer token:tenant_id query parameter to any of these endpoints to scope the preferences to one tenant.
Endpoints
Get a user’s preferences
GET /users/{user_id}/preferences returns every topic the user has an override for:
cURL
GET /users/{user_id}/preferences/{topic_id}.
Set a single preference
PUT /users/{user_id}/preferences/{topic_id} creates or updates one topic. Wrap the preference in a topic object:
cURL
DELETE /users/{user_id}/preferences/{topic_id} removes the override and reverts the topic to its default.
Bulk update preferences
The two bulk endpoints set many topics for a user in one request, which is how you import a user’s existing subscriptions when migrating to Courier. Both take atopics array of the same preference objects. They differ in what happens to the topics you don’t send.
Replace preferences (PUT)
PUT /users/{user_id}/preferences makes the request body the user’s complete override set. Topics you send are created or updated, and any existing override you leave out is reset to its default. An empty topics array clears every override. Validation is atomic: if one topic is invalid, the whole request fails and nothing changes.
cURL
deleted shows any overrides that were reset because they weren’t in the request:
Update preferences (POST)
POST /users/{user_id}/preferences is additive. It only touches the topics you send and leaves every other override untouched. It processes each topic independently: successful ones come back in items, and any that can’t be applied are collected in errors with a reason.
cURL
Replace vs update
Importing existing preferences
Bulk replace is the usual way to bring subscription and opt-out data from another system into Courier. Define your topics in the Preferences Editor first so you have their IDs, then send onePUT per user with their overrides, iterating over your user base. You only need to send topics where a user differs from the default; the rest fall back automatically.
Because replace is idempotent, you can re-run the import safely or use it to keep users in sync with your source of truth. If you’d rather not reset the topics you omit, use POST instead and check its errors array for anything that didn’t apply, like a topic_id that doesn’t exist yet.
Field reference
Next steps
User Preferences API
Full endpoint reference, parameters, and language snippets
Preferences Editor
Create the subscription topics your preferences reference
User Preference Logs
Review a user’s preferences and history in the dashboard
Configure preferences tutorial
A worked example in curl, Node, and Python