Prerequisites
- A Facebook Page with Messenger enabled
- A Facebook App with the Messenger platform
- Your Page Access Token
Setup
1
Generate a Page Access Token
In Meta, open your apps, add Messenger to the app, and generate a Page Access Token for the page you send from.
2
Configure in Courier
Open the in Courier, enter your Page Access Token, then save.
Profile requirements
Facebook Messenger addresses the recipient by Page-Scoped ID, so the profile you send to needs afacebookPSID. 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: {
facebookPSID: '1254477777772919',
},
});
profile = client.profiles.create(
user_id="user_123",
profile={
"facebookPSID": "1254477777772919",
},
)
curl --request POST \
--url https://api.courier.com/profiles/user_123 \
--header "Authorization: Bearer $COURIER_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
"profile": {
"facebookPSID": "1254477777772919"
}
}'
profile = courier.profiles.create(
"user_123",
profile: {
facebookPSID: "1254477777772919"
}
)
profile, err := client.Profiles.New(
context.TODO(),
"user_123",
courier.ProfileNewParams{
Profile: map[string]any{
"facebookPSID": "1254477777772919",
},
},
)
ProfileCreateParams params = ProfileCreateParams.builder()
.userId("user_123")
.profile(ProfileCreateParams.Profile.builder()
.putAdditionalProperty("facebookPSID", JsonValue.from("1254477777772919"))
.build())
.build();
ProfileCreateResponse profile = client.profiles().create(params);
$profile = $client->profiles->create('user_123', profile: [
'facebookPSID' => '1254477777772919',
]);
ProfileCreateParams parameters = new()
{
UserID = "user_123",
Profile = new Dictionary<string, JsonElement>()
{
{ "facebookPSID", JsonSerializer.SerializeToElement("1254477777772919") },
},
};
var profile = await client.Profiles.Create(parameters);
courier profiles create \
--api-key "$COURIER_API_KEY" \
--user-id user_123 \
--profile '{"facebookPSID":"1254477777772919"}'
With Courier MCP, create a profile for user_123 with the facebookPSID 1254477777772919.
user_id and Courier resolves the address.
For a one-off with no stored profile, pass it inline instead: "to": { "facebookPSID": "1254477777772919" }.
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 a PSID
Courier reads
facebookPSID 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: {
facebookPSID: "1254477777772919",
} as any,
template: "nt_01kx4h2jdafq8bk9aftxak4b40",
},
});
response = client.send.message(
message={
"to": {
"facebookPSID": "1254477777772919",
},
"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": {
"facebookPSID": "1254477777772919"
},
"template": "nt_01kx4h2jdafq8bk9aftxak4b40"
}
}'
response = courier.send_.message(
message: {
to: {
facebookPSID: "1254477777772919"
},
template: "nt_01kx4h2jdafq8bk9aftxak4b40"
}
)
// A provider recipient is a profile field, so it sits outside the typed union.
to := param.Override[shared.UserRecipientParam](
json.RawMessage(`{"facebookPSID": "1254477777772919"}`),
)
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("facebookPSID", JsonValue.from("1254477777772919"))
.build();
client.send().message(SendMessageParams.builder()
.message(SendMessageParams.Message.builder()
.to(to)
.template("nt_01kx4h2jdafq8bk9aftxak4b40")
.build())
.build());
$response = $client->send->message(
message: [
'to' => [
'facebookPSID' => '1254477777772919',
],
'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>>(
"""{"facebookPSID": "1254477777772919"}"""
)
);
var response = await client.Send.Message(new() { Message = new() { To = to, Template = "nt_01kx4h2jdafq8bk9aftxak4b40" } });
courier send message \
--api-key "$COURIER_API_KEY" \
--message.to '{"facebookPSID": "1254477777772919"}' \
--message.template nt_01kx4h2jdafq8bk9aftxak4b40
With Courier MCP, send my template to the Facebook PSID 1254477777772919.
Overrides
covers the two levels and which one wins. A provider override changes the request body Courier sends to Messenger, or swaps the Page Access Token and API URL.Body overrides
You can override any of the fields in the request body that Courier sends to the Messenger Send API.const { requestId } = await courier.send.message({
message: {
template: "nt_01kx4h2jdafq8bk9aftxak4b40",
to: {
facebookPSID: "1254477777772919",
},
providers: {
"facebook-messenger": {
override: {
body: {
messaging_type: "UPDATE",
},
},
},
},
},
});
response = client.send.message(
message={
"template": "nt_01kx4h2jdafq8bk9aftxak4b40",
"to": {
"facebookPSID": "1254477777772919",
},
"providers": {
"facebook-messenger": {
"override": {
"body": {
"messaging_type": "UPDATE",
},
},
},
},
},
)
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": {
"facebookPSID": "1254477777772919"
},
"providers": {
"facebook-messenger": {
"override": {
"body": {
"messaging_type": "UPDATE"
}
}
}
}
}
}'
response = courier.send_.message(
message: {
template: "nt_01kx4h2jdafq8bk9aftxak4b40",
to: {
facebookPSID: "1254477777772919"
},
providers: {
"facebook-messenger": {
override: {
body: {
messaging_type: "UPDATE"
}
}
}
}
}
)
// 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(`{
"facebookPSID": "1254477777772919"
}`))
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{
"facebook-messenger": shared.MessageProvidersTypeParam{
Override: map[string]any{
"body": map[string]any{
"messaging_type": "UPDATE",
},
},
},
},
},
})
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("facebookPSID", JsonValue.from("1254477777772919"))
.build())
.template("nt_01kx4h2jdafq8bk9aftxak4b40")
.providers(MessageProviders.builder()
.putAdditionalProperty("facebook-messenger", JsonValue.from(java.util.Map.of("override", java.util.Map.of(
"body", java.util.Map.of(
"messaging_type", "UPDATE"
)
))))
.build())
.build())
.build();
SendMessageResponse response = client.send().message(params);
$response = $client->send->message(
message: [
'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
'to' => [
'facebookPSID' => '1254477777772919',
],
'providers' => [
'facebook-messenger' => [
'override' => [
'body' => [
'messaging_type' => 'UPDATE',
],
],
],
],
],
);
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>>(
"""
{
"facebookPSID": "1254477777772919"
}
"""
)
),
Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
Providers = new Dictionary<string, MessageProvidersType>()
{
{
"facebook-messenger",
new()
{
Override = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
"""
{
"body": {
"messaging_type": "UPDATE"
}
}
"""
),
}
},
},
},
};
var response = await client.Send.Message(parameters);
courier send message \
--api-key "$COURIER_API_KEY" \
--message.to '{"facebookPSID": "1254477777772919"}' \
--message.template nt_01kx4h2jdafq8bk9aftxak4b40 \
--message.providers '{"facebook-messenger": {"override": {"body": {"messaging_type": "UPDATE"}}}}'
With Courier MCP, send my template to this Messenger PSID and override the message body.
Config overrides
You can swap the Page Access Token or API URL at send time:const { requestId } = await courier.send.message({
message: {
template: "nt_01kx4h2jdafq8bk9aftxak4b40",
to: {
facebookPSID: "1254477777772919",
},
providers: {
"facebook-messenger": {
override: {
config: {
access_token: "RUNTIME_PAGE_ACCESS_TOKEN",
},
},
},
},
},
});
response = client.send.message(
message={
"template": "nt_01kx4h2jdafq8bk9aftxak4b40",
"to": {
"facebookPSID": "1254477777772919",
},
"providers": {
"facebook-messenger": {
"override": {
"config": {
"access_token": "RUNTIME_PAGE_ACCESS_TOKEN",
},
},
},
},
},
)
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": {
"facebookPSID": "1254477777772919"
},
"providers": {
"facebook-messenger": {
"override": {
"config": {
"access_token": "RUNTIME_PAGE_ACCESS_TOKEN"
}
}
}
}
}
}'
response = courier.send_.message(
message: {
template: "nt_01kx4h2jdafq8bk9aftxak4b40",
to: {
facebookPSID: "1254477777772919"
},
providers: {
"facebook-messenger": {
override: {
config: {
access_token: "RUNTIME_PAGE_ACCESS_TOKEN"
}
}
}
}
}
)
// 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(`{
"facebookPSID": "1254477777772919"
}`))
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{
"facebook-messenger": shared.MessageProvidersTypeParam{
Override: map[string]any{
"config": map[string]any{
"access_token": "RUNTIME_PAGE_ACCESS_TOKEN",
},
},
},
},
},
})
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("facebookPSID", JsonValue.from("1254477777772919"))
.build())
.template("nt_01kx4h2jdafq8bk9aftxak4b40")
.providers(MessageProviders.builder()
.putAdditionalProperty("facebook-messenger", JsonValue.from(java.util.Map.of("override", java.util.Map.of(
"config", java.util.Map.of(
"access_token", "RUNTIME_PAGE_ACCESS_TOKEN"
)
))))
.build())
.build())
.build();
SendMessageResponse response = client.send().message(params);
$response = $client->send->message(
message: [
'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
'to' => [
'facebookPSID' => '1254477777772919',
],
'providers' => [
'facebook-messenger' => [
'override' => [
'config' => [
'access_token' => 'RUNTIME_PAGE_ACCESS_TOKEN',
],
],
],
],
],
);
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>>(
"""
{
"facebookPSID": "1254477777772919"
}
"""
)
),
Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
Providers = new Dictionary<string, MessageProvidersType>()
{
{
"facebook-messenger",
new()
{
Override = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
"""
{
"config": {
"access_token": "RUNTIME_PAGE_ACCESS_TOKEN"
}
}
"""
),
}
},
},
},
};
var response = await client.Send.Message(parameters);
courier send message \
--api-key "$COURIER_API_KEY" \
--message.to '{"facebookPSID": "1254477777772919"}' \
--message.template nt_01kx4h2jdafq8bk9aftxak4b40 \
--message.providers '{"facebook-messenger": {"override": {"config": {"access_token": "RUNTIME_PAGE_ACCESS_TOKEN"}}}}'
With Courier MCP, send my template to this Messenger PSID with a different page access token.
Provider details
facebook-messenger
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.