Prerequisites
- Your Intercom access token
- An Intercom admin or bot user ID
Setup
1
Get your Intercom access token
In Intercom, follow the authentication guide to create an access token.
2
Configure in Courier
Install the in Courier and enter your access token and user ID.
Profile requirements
Intercom addresses the recipient by user ID, nested underintercom.to.id on the profile. Courier assumes the user is of type user. Store it once with , which merges into the profile and creates it if it does not exist:
const profile = await client.profiles.create('user_123', {
profile: {
intercom: {
to: {
id: 'INTERCOM_USER_ID',
},
},
},
});
profile = client.profiles.create(
user_id="user_123",
profile={
"intercom": {
"to": {
"id": "INTERCOM_USER_ID",
},
},
},
)
curl --request POST \
--url https://api.courier.com/profiles/user_123 \
--header "Authorization: Bearer $COURIER_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
"profile": {
"intercom": {
"to": {
"id": "INTERCOM_USER_ID"
}
}
}
}'
profile = courier.profiles.create(
"user_123",
profile: {
intercom: {
to: {
id: "INTERCOM_USER_ID"
}
}
}
)
profile, err := client.Profiles.New(
context.TODO(),
"user_123",
courier.ProfileNewParams{
Profile: map[string]any{
"intercom": map[string]any{
"to": map[string]any{
"id": "INTERCOM_USER_ID",
},
},
},
},
)
ProfileCreateParams params = ProfileCreateParams.builder()
.userId("user_123")
.profile(ProfileCreateParams.Profile.builder()
.putAdditionalProperty("intercom", JsonValue.from(java.util.Map.of(
"to", java.util.Map.of(
"id", "INTERCOM_USER_ID"))))
.build())
.build();
ProfileCreateResponse profile = client.profiles().create(params);
$profile = $client->profiles->create('user_123', profile: [
'intercom' => [
'to' => [
'id' => 'INTERCOM_USER_ID',
],
],
]);
ProfileCreateParams parameters = new()
{
UserID = "user_123",
Profile = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
"""
{
"intercom": {
"to": {
"id": "INTERCOM_USER_ID"
}
}
}
"""
),
};
var profile = await client.Profiles.Create(parameters);
courier profiles create \
--api-key "$COURIER_API_KEY" \
--user-id user_123 \
--profile '{"intercom":{"to":{"id":"INTERCOM_USER_ID"}}}'
With Courier MCP, save the Intercom user id INTERCOM_USER_ID on user_123.
user_id and Courier resolves the address.
For a one-off with no stored profile, pass it inline instead: "to": { "intercom": { "to": { "id": "INTERCOM_USER_ID" } } }.
Send by user id
The call in every language, and the rest of the profile object.
Send to a recipient
- Send to user id
- Send to
intercom
Courier reads
intercom off the saved profile, so preferences apply and the value can change without touching this code.const { requestId } = await courier.send.message({
message: {
to: {
user_id: "user_123",
},
template: "nt_01kx4h2jdafq8bk9aftxak4b40",
},
});
response = client.send.message(
message={
"to": {
"user_id": "user_123",
},
"template": "nt_01kx4h2jdafq8bk9aftxak4b40",
},
)
curl -X POST https://api.courier.com/send \
-H "Authorization: Bearer $COURIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": {
"to": {
"user_id": "user_123"
},
"template": "nt_01kx4h2jdafq8bk9aftxak4b40"
}
}'
response = courier.send_.message(
message: {
to: {
user_id: "user_123"
},
template: "nt_01kx4h2jdafq8bk9aftxak4b40"
}
)
response, err := client.Send.Message(context.TODO(), courier.SendMessageParams{
Message: courier.SendMessageParamsMessage{
To: courier.SendMessageParamsMessageToUnion{
OfUserRecipient: &shared.UserRecipientParam{
UserID: courier.String("user_123"),
},
},
Template: courier.String("nt_01kx4h2jdafq8bk9aftxak4b40"),
},
})
SendMessageParams params = SendMessageParams.builder()
.message(SendMessageParams.Message.builder()
.to(UserRecipient.builder().userId("user_123").build())
.template("nt_01kx4h2jdafq8bk9aftxak4b40")
.build())
.build();
SendMessageResponse response = client.send().message(params);
$response = $client->send->message(
message: [
'to' => [
'user_id' => 'user_123',
],
'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
],
);
SendMessageParams parameters = new()
{
Message = new()
{
To = new UserRecipient { UserID = "user_123" },
Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
},
};
var response = await client.Send.Message(parameters);
courier send message \
--api-key "$COURIER_API_KEY" \
--message.to '{"user_id": "user_123"}' \
--message.template nt_01kx4h2jdafq8bk9aftxak4b40
With Courier MCP, send my template to user_123 by email.
Pass it inline instead and nothing is stored. Swap this
to object into the call on the other tab.const { requestId } = await courier.send.message({
message: {
// A provider recipient is a profile field, so it sits outside the typed union.
to: {
intercom: {
to: {
id: "INTERCOM_USER_ID",
},
},
} as any,
template: "nt_01kx4h2jdafq8bk9aftxak4b40",
},
});
response = client.send.message(
message={
"to": {
"intercom": {
"to": {
"id": "INTERCOM_USER_ID",
},
},
},
"template": "nt_01kx4h2jdafq8bk9aftxak4b40",
},
)
curl -X POST https://api.courier.com/send \
-H "Authorization: Bearer $COURIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": {
"to": {
"intercom": {
"to": {
"id": "INTERCOM_USER_ID"
}
}
},
"template": "nt_01kx4h2jdafq8bk9aftxak4b40"
}
}'
response = courier.send_.message(
message: {
to: {
intercom: {
to: {
id: "INTERCOM_USER_ID"
}
}
},
template: "nt_01kx4h2jdafq8bk9aftxak4b40"
}
)
// A provider recipient is a profile field, so it sits outside the typed union.
to := param.Override[shared.UserRecipientParam](
json.RawMessage(`{"intercom": {"to": {"id": "INTERCOM_USER_ID"}}}`),
)
response, err := client.Send.Message(context.TODO(), courier.SendMessageParams{
Message: courier.SendMessageParamsMessage{
To: courier.SendMessageParamsMessageToUnion{OfUserRecipient: &to},
Template: courier.String("nt_01kx4h2jdafq8bk9aftxak4b40"),
},
})
// A provider recipient is a profile field, so it sits outside the typed union.
UserRecipient to = UserRecipient.builder()
.putAdditionalProperty("intercom", JsonValue.from(Map.of(
"to", Map.of(
"id", "INTERCOM_USER_ID"))))
.build();
client.send().message(SendMessageParams.builder()
.message(SendMessageParams.Message.builder()
.to(to)
.template("nt_01kx4h2jdafq8bk9aftxak4b40")
.build())
.build());
$response = $client->send->message(
message: [
'to' => [
'intercom' => [
'to' => [
'id' => 'INTERCOM_USER_ID',
],
],
],
'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
],
);
// A provider recipient is a profile field, so it sits outside the typed union.
UserRecipient to = UserRecipient.FromRawUnchecked(
JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
"""{"intercom": {"to": {"id": "INTERCOM_USER_ID"}}}"""
)
);
var response = await client.Send.Message(new() { Message = new() { To = to, Template = "nt_01kx4h2jdafq8bk9aftxak4b40" } });
courier send message \
--api-key "$COURIER_API_KEY" \
--message.to '{"intercom": {"to": {"id": "INTERCOM_USER_ID"}}}' \
--message.template nt_01kx4h2jdafq8bk9aftxak4b40
With Courier MCP, send my template to the Intercom user INTERCOM_USER_ID.
Overrides
covers the two levels and which one wins. A provider override changes what Courier sends as an Intercom Message. Overrides are deep-merged into the request: fields you set replace their counterparts, and everything you leave out is still sent. You can override the message body and the From User ID. This example overrides both:const { requestId } = await courier.send.message({
message: {
template: "nt_01kx4h2jdafq8bk9aftxak4b40",
to: {
intercom: {
to: {
id: "INTERCOM_USER_ID",
},
},
},
providers: {
intercom: {
override: {
body: {
body: "I overrode this message",
from: {
id: "012345",
},
},
},
},
},
},
});
response = client.send.message(
message={
"template": "nt_01kx4h2jdafq8bk9aftxak4b40",
"to": {
"intercom": {
"to": {
"id": "INTERCOM_USER_ID",
},
},
},
"providers": {
"intercom": {
"override": {
"body": {
"body": "I overrode this message",
"from": {
"id": "012345",
},
},
},
},
},
},
)
curl -X POST https://api.courier.com/send \
-H "Authorization: Bearer $COURIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": {
"template": "nt_01kx4h2jdafq8bk9aftxak4b40",
"to": {
"intercom": {
"to": {
"id": "INTERCOM_USER_ID"
}
}
},
"providers": {
"intercom": {
"override": {
"body": {
"body": "I overrode this message",
"from": {
"id": "012345"
}
}
}
}
}
}
}'
response = courier.send_.message(
message: {
template: "nt_01kx4h2jdafq8bk9aftxak4b40",
to: {
intercom: {
to: {
id: "INTERCOM_USER_ID"
}
}
},
providers: {
intercom: {
override: {
body: {
body: "I overrode this message",
from: {
id: "012345"
}
}
}
}
}
}
)
// This provider addresses the recipient with fields outside the typed
// UserRecipient model, so pass the recipient as raw JSON.
to := param.Override[shared.UserRecipientParam](json.RawMessage(`{
"intercom": {
"to": {
"id": "INTERCOM_USER_ID"
}
}
}`))
response, err := client.Send.Message(context.TODO(), courier.SendMessageParams{
Message: courier.SendMessageParamsMessage{
To: courier.SendMessageParamsMessageToUnion{OfUserRecipient: &to},
Template: courier.String("nt_01kx4h2jdafq8bk9aftxak4b40"),
Providers: shared.MessageProvidersParam{
"intercom": shared.MessageProvidersTypeParam{
Override: map[string]any{
"body": map[string]any{
"body": "I overrode this message",
"from": map[string]any{
"id": "012345",
},
},
},
},
},
},
})
SendMessageParams params = SendMessageParams.builder()
.message(SendMessageParams.Message.builder()
// This provider addresses the recipient with fields outside the
// typed UserRecipient model, so pass them as additional properties.
.to(UserRecipient.builder()
.putAdditionalProperty("intercom", JsonValue.from(java.util.Map.of(
"to", java.util.Map.of(
"id", "INTERCOM_USER_ID"
)
)))
.build())
.template("nt_01kx4h2jdafq8bk9aftxak4b40")
.providers(MessageProviders.builder()
.putAdditionalProperty("intercom", JsonValue.from(java.util.Map.of("override", java.util.Map.of(
"body", java.util.Map.of(
"body", "I overrode this message",
"from", java.util.Map.of(
"id", "012345"
)
)
))))
.build())
.build())
.build();
SendMessageResponse response = client.send().message(params);
$response = $client->send->message(
message: [
'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
'to' => [
'intercom' => [
'to' => [
'id' => 'INTERCOM_USER_ID',
],
],
],
'providers' => [
'intercom' => [
'override' => [
'body' => [
'body' => 'I overrode this message',
'from' => [
'id' => '012345',
],
],
],
],
],
],
);
SendMessageParams parameters = new()
{
Message = new()
{
// This provider addresses the recipient with fields outside the
// typed UserRecipient model, so build it from raw JSON.
To = UserRecipient.FromRawUnchecked(
JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
"""
{
"intercom": {
"to": {
"id": "INTERCOM_USER_ID"
}
}
}
"""
)
),
Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
Providers = new Dictionary<string, MessageProvidersType>()
{
{
"intercom",
new()
{
Override = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
"""
{
"body": {
"body": "I overrode this message",
"from": {
"id": "012345"
}
}
}
"""
),
}
},
},
},
};
var response = await client.Send.Message(parameters);
courier send message \
--api-key "$COURIER_API_KEY" \
--message.to '{"intercom": {"to": {"id": "INTERCOM_USER_ID"}}}' \
--message.template nt_01kx4h2jdafq8bk9aftxak4b40 \
--message.providers '{"intercom": {"override": {"body": {"body": "I overrode this message", "from": {"id": "012345"}}}}}'
With Courier MCP, send my template to this Intercom contact with a body override.
Provider details
intercom
routing.channels instead is supported, and sends through just this provider.
Send to a specific provider
When that is worth doing, and what you give up: failover, channel priority, and providers you add later.