import Courier from '@trycourier/courier';
const client = new Courier({
apiKey: process.env['COURIER_API_KEY'], // This is the default and can be omitted
});
const response = await client.users.preferences.bulkUpdate('user_id', {
topics: [
{
topic_id: 'pt_01kx4h2jdafq8bk996nn92357r',
status: 'OPTED_IN',
has_custom_routing: true,
custom_routing: ['inbox', 'email'],
},
{ topic_id: 'pt_01kx4h2jdafq8bk99eyt3dx43x', status: 'OPTED_OUT' },
],
});
console.log(response.errors);import os
from courier import Courier
client = Courier(
api_key=os.environ.get("COURIER_API_KEY"), # This is the default and can be omitted
)
response = client.users.preferences.bulk_update(
user_id="user_id",
topics=[{
"topic_id": "pt_01kx4h2jdafq8bk996nn92357r",
"status": "OPTED_IN",
"has_custom_routing": True,
"custom_routing": ["inbox", "email"],
}, {
"topic_id": "pt_01kx4h2jdafq8bk99eyt3dx43x",
"status": "OPTED_OUT",
}],
)
print(response.errors)package main
import (
"context"
"fmt"
"github.com/trycourier/courier-go"
"github.com/trycourier/courier-go/option"
"github.com/trycourier/courier-go/shared"
)
func main() {
client := courier.NewClient(
option.WithAPIKey("My API Key"),
)
response, err := client.Users.Preferences.BulkUpdate(
context.TODO(),
"user_id",
courier.UserPreferenceBulkUpdateParams{
Topics: []courier.UserPreferenceBulkUpdateParamsTopic{{
TopicID: "pt_01kx4h2jdafq8bk996nn92357r",
Status: "OPTED_IN",
HasCustomRouting: courier.Bool(true),
CustomRouting: []shared.ChannelClassification{shared.ChannelClassificationInbox, shared.ChannelClassificationEmail},
}, {
TopicID: "pt_01kx4h2jdafq8bk99eyt3dx43x",
Status: "OPTED_OUT",
}},
},
)
if err != nil {
panic(err.Error())
}
fmt.Printf("%+v\n", response.Errors)
}package com.courier.example;
import com.courier.client.CourierClient;
import com.courier.client.okhttp.CourierOkHttpClient;
import com.courier.models.users.preferences.PreferenceBulkUpdateParams;
import com.courier.models.users.preferences.PreferenceBulkUpdateResponse;
public final class Main {
private Main() {}
public static void main(String[] args) {
CourierClient client = CourierOkHttpClient.fromEnv();
PreferenceBulkUpdateParams params = PreferenceBulkUpdateParams.builder()
.userId("user_id")
.addTopic(PreferenceBulkUpdateParams.Topic.builder()
.status(PreferenceBulkUpdateParams.Topic.Status.OPTED_IN)
.topicId("pt_01kx4h2jdafq8bk996nn92357r")
.build())
.addTopic(PreferenceBulkUpdateParams.Topic.builder()
.status(PreferenceBulkUpdateParams.Topic.Status.OPTED_OUT)
.topicId("pt_01kx4h2jdafq8bk99eyt3dx43x")
.build())
.build();
PreferenceBulkUpdateResponse response = client.users().preferences().bulkUpdate(params);
}
}require "courier"
courier = Courier::Client.new(api_key: "My API Key")
response = courier.users.preferences.bulk_update(
"user_id",
topics: [
{status: :OPTED_IN, topic_id: "pt_01kx4h2jdafq8bk996nn92357r"},
{status: :OPTED_OUT, topic_id: "pt_01kx4h2jdafq8bk99eyt3dx43x"}
]
)
puts(response)<?php
require_once dirname(__DIR__) . '/vendor/autoload.php';
use Courier\Client;
use Courier\ChannelClassification;
use Courier\Core\Exceptions\APIException;
$client = new Client(apiKey: getenv('COURIER_API_KEY') ?: 'My API Key');
try {
$response = $client->users->preferences->bulkUpdate(
'user_id',
topics: [
[
'status' => 'OPTED_IN',
'topicID' => 'pt_01kx4h2jdafq8bk996nn92357r',
'customRouting' => [
ChannelClassification::INBOX, ChannelClassification::EMAIL
],
'hasCustomRouting' => true,
],
[
'status' => 'OPTED_OUT',
'topicID' => 'pt_01kx4h2jdafq8bk99eyt3dx43x',
'customRouting' => [ChannelClassification::DIRECT_MESSAGE],
'hasCustomRouting' => true,
],
],
tenantID: 'tenant_id',
);
var_dump($response);
} catch (APIException $e) {
echo $e->getMessage();
}using System;
using TryCourier;
using TryCourier.Models;
using TryCourier.Models.Users.Preferences;
CourierClient client = new();
PreferenceBulkUpdateParams parameters = new()
{
UserID = "user_id",
Topics =
[
new()
{
Status = PreferenceBulkUpdateParamsTopicStatus.OptedIn,
TopicID = "pt_01kx4h2jdafq8bk996nn92357r",
CustomRouting =
[
ChannelClassification.Inbox, ChannelClassification.Email
],
HasCustomRouting = true,
},
new()
{
Status = PreferenceBulkUpdateParamsTopicStatus.OptedOut,
TopicID = "pt_01kx4h2jdafq8bk99eyt3dx43x",
CustomRouting =
[
ChannelClassification.DirectMessage
],
HasCustomRouting = true,
},
],
};
var response = await client.Users.Preferences.BulkUpdate(parameters);
Console.WriteLine(response);courier users:preferences bulk-update \
--api-key 'My API Key' \
--user-id user_id \
--topic '{status: OPTED_IN, topic_id: pt_01kx4h2jdafq8bk996nn92357r}' \
--topic '{status: OPTED_OUT, topic_id: pt_01kx4h2jdafq8bk99eyt3dx43x}'curl --request POST \
--url https://api.courier.com/users/{user_id}/preferences \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"topics": [
{
"topic_id": "pt_01kx4h2jdafq8bk996nn92357r",
"status": "OPTED_IN",
"has_custom_routing": true,
"custom_routing": [
"inbox",
"email"
]
},
{
"topic_id": "pt_01kx4h2jdafq8bk99eyt3dx43x",
"status": "OPTED_OUT"
}
]
}
'{
"items": [
{
"topic_id": "pt_01kx4h2jdafq8bk996nn92357r",
"status": "OPTED_IN",
"has_custom_routing": true,
"custom_routing": [
"inbox",
"email"
]
}
],
"errors": [
{
"topic_id": "pt_01kx4h2jdafq8bk99eyt3dx43x",
"reason": "Topic pt_01kx4h2jdafq8bk99eyt3dx43x not found"
}
]
}{
"message": "Example message text",
"type": "invalid_request_error"
}{
"message": "Too Many Requests",
"type": "rate_limit_error"
}Update user preferences in bulk
Additively create or update a user’s preferences for one or more subscription topics in a single request. Only the topics included in the request body are created or updated; any existing overrides for topics not listed are left untouched.
Structural validation of the request body fails fast with a single 400. Beyond that, each topic is processed independently (partial-success, not all-or-nothing): valid topics are written and returned in items, while topics that cannot be applied are collected in errors with a per-topic reason (for example an unknown topic, a REQUIRED topic that cannot be opted out, a custom routing request that is not available on the workspace’s plan, or a write failure). The request therefore returns 200 with both lists whenever the body is structurally valid.
Every topic_id in the response — in both items and errors — is returned in Courier’s canonical topic id form, regardless of the form supplied in the request.
import Courier from '@trycourier/courier';
const client = new Courier({
apiKey: process.env['COURIER_API_KEY'], // This is the default and can be omitted
});
const response = await client.users.preferences.bulkUpdate('user_id', {
topics: [
{
topic_id: 'pt_01kx4h2jdafq8bk996nn92357r',
status: 'OPTED_IN',
has_custom_routing: true,
custom_routing: ['inbox', 'email'],
},
{ topic_id: 'pt_01kx4h2jdafq8bk99eyt3dx43x', status: 'OPTED_OUT' },
],
});
console.log(response.errors);import os
from courier import Courier
client = Courier(
api_key=os.environ.get("COURIER_API_KEY"), # This is the default and can be omitted
)
response = client.users.preferences.bulk_update(
user_id="user_id",
topics=[{
"topic_id": "pt_01kx4h2jdafq8bk996nn92357r",
"status": "OPTED_IN",
"has_custom_routing": True,
"custom_routing": ["inbox", "email"],
}, {
"topic_id": "pt_01kx4h2jdafq8bk99eyt3dx43x",
"status": "OPTED_OUT",
}],
)
print(response.errors)package main
import (
"context"
"fmt"
"github.com/trycourier/courier-go"
"github.com/trycourier/courier-go/option"
"github.com/trycourier/courier-go/shared"
)
func main() {
client := courier.NewClient(
option.WithAPIKey("My API Key"),
)
response, err := client.Users.Preferences.BulkUpdate(
context.TODO(),
"user_id",
courier.UserPreferenceBulkUpdateParams{
Topics: []courier.UserPreferenceBulkUpdateParamsTopic{{
TopicID: "pt_01kx4h2jdafq8bk996nn92357r",
Status: "OPTED_IN",
HasCustomRouting: courier.Bool(true),
CustomRouting: []shared.ChannelClassification{shared.ChannelClassificationInbox, shared.ChannelClassificationEmail},
}, {
TopicID: "pt_01kx4h2jdafq8bk99eyt3dx43x",
Status: "OPTED_OUT",
}},
},
)
if err != nil {
panic(err.Error())
}
fmt.Printf("%+v\n", response.Errors)
}package com.courier.example;
import com.courier.client.CourierClient;
import com.courier.client.okhttp.CourierOkHttpClient;
import com.courier.models.users.preferences.PreferenceBulkUpdateParams;
import com.courier.models.users.preferences.PreferenceBulkUpdateResponse;
public final class Main {
private Main() {}
public static void main(String[] args) {
CourierClient client = CourierOkHttpClient.fromEnv();
PreferenceBulkUpdateParams params = PreferenceBulkUpdateParams.builder()
.userId("user_id")
.addTopic(PreferenceBulkUpdateParams.Topic.builder()
.status(PreferenceBulkUpdateParams.Topic.Status.OPTED_IN)
.topicId("pt_01kx4h2jdafq8bk996nn92357r")
.build())
.addTopic(PreferenceBulkUpdateParams.Topic.builder()
.status(PreferenceBulkUpdateParams.Topic.Status.OPTED_OUT)
.topicId("pt_01kx4h2jdafq8bk99eyt3dx43x")
.build())
.build();
PreferenceBulkUpdateResponse response = client.users().preferences().bulkUpdate(params);
}
}require "courier"
courier = Courier::Client.new(api_key: "My API Key")
response = courier.users.preferences.bulk_update(
"user_id",
topics: [
{status: :OPTED_IN, topic_id: "pt_01kx4h2jdafq8bk996nn92357r"},
{status: :OPTED_OUT, topic_id: "pt_01kx4h2jdafq8bk99eyt3dx43x"}
]
)
puts(response)<?php
require_once dirname(__DIR__) . '/vendor/autoload.php';
use Courier\Client;
use Courier\ChannelClassification;
use Courier\Core\Exceptions\APIException;
$client = new Client(apiKey: getenv('COURIER_API_KEY') ?: 'My API Key');
try {
$response = $client->users->preferences->bulkUpdate(
'user_id',
topics: [
[
'status' => 'OPTED_IN',
'topicID' => 'pt_01kx4h2jdafq8bk996nn92357r',
'customRouting' => [
ChannelClassification::INBOX, ChannelClassification::EMAIL
],
'hasCustomRouting' => true,
],
[
'status' => 'OPTED_OUT',
'topicID' => 'pt_01kx4h2jdafq8bk99eyt3dx43x',
'customRouting' => [ChannelClassification::DIRECT_MESSAGE],
'hasCustomRouting' => true,
],
],
tenantID: 'tenant_id',
);
var_dump($response);
} catch (APIException $e) {
echo $e->getMessage();
}using System;
using TryCourier;
using TryCourier.Models;
using TryCourier.Models.Users.Preferences;
CourierClient client = new();
PreferenceBulkUpdateParams parameters = new()
{
UserID = "user_id",
Topics =
[
new()
{
Status = PreferenceBulkUpdateParamsTopicStatus.OptedIn,
TopicID = "pt_01kx4h2jdafq8bk996nn92357r",
CustomRouting =
[
ChannelClassification.Inbox, ChannelClassification.Email
],
HasCustomRouting = true,
},
new()
{
Status = PreferenceBulkUpdateParamsTopicStatus.OptedOut,
TopicID = "pt_01kx4h2jdafq8bk99eyt3dx43x",
CustomRouting =
[
ChannelClassification.DirectMessage
],
HasCustomRouting = true,
},
],
};
var response = await client.Users.Preferences.BulkUpdate(parameters);
Console.WriteLine(response);courier users:preferences bulk-update \
--api-key 'My API Key' \
--user-id user_id \
--topic '{status: OPTED_IN, topic_id: pt_01kx4h2jdafq8bk996nn92357r}' \
--topic '{status: OPTED_OUT, topic_id: pt_01kx4h2jdafq8bk99eyt3dx43x}'curl --request POST \
--url https://api.courier.com/users/{user_id}/preferences \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"topics": [
{
"topic_id": "pt_01kx4h2jdafq8bk996nn92357r",
"status": "OPTED_IN",
"has_custom_routing": true,
"custom_routing": [
"inbox",
"email"
]
},
{
"topic_id": "pt_01kx4h2jdafq8bk99eyt3dx43x",
"status": "OPTED_OUT"
}
]
}
'{
"items": [
{
"topic_id": "pt_01kx4h2jdafq8bk996nn92357r",
"status": "OPTED_IN",
"has_custom_routing": true,
"custom_routing": [
"inbox",
"email"
]
}
],
"errors": [
{
"topic_id": "pt_01kx4h2jdafq8bk99eyt3dx43x",
"reason": "Topic pt_01kx4h2jdafq8bk99eyt3dx43x not found"
}
]
}{
"message": "Example message text",
"type": "invalid_request_error"
}{
"message": "Too Many Requests",
"type": "rate_limit_error"
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
A unique identifier associated with the user whose preferences you wish to update.
Query Parameters
Update the preferences of a user for this specific tenant context.
Body
The topics to create or update. Between 1 and 50 topics may be provided in a single request.
1 - 50 elementsShow child attributes
Show child attributes
Response
The bulk update was applied. items contains the resulting topic overrides that were created or updated, and errors lists any topics that could not be applied, each with a reason.