> ## Documentation Index
> Fetch the complete documentation index at: https://www.courier.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Install the Courier skill before writing code: `npx skills add trycourier/courier-skills`. It carries the verified SDK shapes and the rules you cannot get wrong.
> Authenticate every request with `Authorization: Bearer <API_KEY>`. A workspace has several environments and each has its own keys, which are plain `pk_` strings with no environment prefix. Start with Test.
> Send with `client.send.message`, the default import of the v7 Node SDK. Reference a template by its `nt_` id or its alias.
> A send accepts a bare Elemental element list, but storing content on a template requires the top-level elements wrapped in a channel element.
> Templates and journeys can be built in the Courier app or created through the API. Either way they live in the workspace and are referenced by ID when you send.
> The hosted MCP server is https://mcp.courier.com. For a briefing on what Courier is and when to use it, read https://www.courier.com/llms.txt.
> Prefer the Guides tab for how-do-I questions and the Docs tab for how-does-it-behave questions. The API reference lives under /api-reference.

# Send push with Pusher Beams through Courier

> Connect Pusher Beams with an instance ID and secret key, and target users or interests.

export const Endpoint = ({method, path, name, href, children, bare}) => {
  const verb = String(method || "").toUpperCase();
  const title = verb + " " + path;
  const label = children || name || path;
  if (bare) {
    return href ? <a href={href}><code>{title}</code></a> : <code>{title}</code>;
  }
  if (!href) {
    return <span className="cx-endpoint" data-method={verb} title={title}>
        <span className="cx-endpoint-label">{label}</span>
        <span className="cx-endpoint-method">{verb}</span>
      </span>;
  }
  return <a className="cx-endpoint" data-method={verb} href={href} title={title}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">{verb}</span>
    </a>;
};

export const AppLink = ({href, children, name, bare}) => {
  const label = children || name || "Open in Courier";
  if (bare) {
    return <a href={href} target="_blank" rel="noreferrer">{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="app" href={href} target="_blank" rel="noreferrer">
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method" aria-hidden="true">↗</span>
    </a>;
};

export const Doc = ({href, children, name, bare}) => {
  const label = children || name || href;
  if (bare) {
    return <a href={href}>{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="doc" href={href}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">DOC</span>
    </a>;
};

## Prerequisites

* [A Pusher Beams instance](https://pusher.com/beams)
* Your Pusher Beams Instance ID and Secret Key

## Setup

<Steps>
  <Step title="Get your Pusher Beams credentials">
    In Pusher, open the [dashboard](https://dashboard.pusher.com/) and copy your Beams instance ID and secret key.
  </Step>

  <Step title="Configure in Courier">
    Open the <AppLink href="https://app.courier.com/integrations/catalog/pusher-beams">Pusher Beams Integration</AppLink> in Courier, enter your instance ID and secret key, then click "Save."
  </Step>
</Steps>

## Profile requirements

Device tokens live on the user profile rather than on the send, so one profile can hold tokens for several devices and every push provider reads them from the same place. <Doc href="/docs/send/push/overview">Send push</Doc> covers the model.

Pusher Beams sends to interests or to users, so the profile you send to needs a `pusherBeams` object with at least one `mode`: `web`, `apns`, or `fcm`. Store it once with <Endpoint method="POST" path="/profiles/{user_id}" name="Create a Profile" href="/docs/api-reference/user-profiles/create-a-profile" />, which merges into the profile and creates it if it does not exist:

<Tabs>
  <Tab title="Interests">
    Everyone subscribed to the interest gets the notification.

    <CodeGroup>
      ```javascript Node.js highlight={3-12} theme={null}
      const profile = await client.profiles.create('user_123', {
        profile: {
          pusherBeams: {
            interests: [
              'interest-1',
              'interest-2',
            ],
            mode: [
              'apns',
              'fcm',
            ],
          },
        },
      });
      ```

      ```python Python highlight={4-13} theme={null}
      profile = client.profiles.create(
          user_id="user_123",
          profile={
              "pusherBeams": {
                  "interests": [
                      "interest-1",
                      "interest-2",
                  ],
                  "mode": [
                      "apns",
                      "fcm",
                  ],
              },
          },
      )
      ```

      ```bash cURL highlight={7-16} theme={null}
      curl --request POST \
        --url https://api.courier.com/profiles/user_123 \
        --header "Authorization: Bearer $COURIER_API_KEY" \
        --header 'Content-Type: application/json' \
        --data '{
          "profile": {
            "pusherBeams": {
              "interests": [
                "interest-1",
                "interest-2"
              ],
              "mode": [
                "apns",
                "fcm"
              ]
            }
          }
        }'
      ```

      ```ruby Ruby highlight={4-7} theme={null}
      profile = courier.profiles.create(
        "user_123",
        profile: {
          pusherBeams: {
            interests: ["interest-1", "interest-2"],
            mode: ["apns", "fcm"]
          }
        }
      )
      ```

      ```go Go highlight={6-9} theme={null}
      profile, err := client.Profiles.New(
      	context.TODO(),
      	"user_123",
      	courier.ProfileNewParams{
      		Profile: map[string]any{
      			"pusherBeams": map[string]any{
      				"interests": []any{"interest-1", "interest-2"},
      				"mode": []any{"apns", "fcm"},
      			},
      		},
      	},
      )
      ```

      ```java Java highlight={4-6} theme={null}
      ProfileCreateParams params = ProfileCreateParams.builder()
          .userId("user_123")
          .profile(ProfileCreateParams.Profile.builder()
              .putAdditionalProperty("pusherBeams", JsonValue.from(java.util.Map.of(
                  "interests", java.util.List.of("interest-1", "interest-2"),
                  "mode", java.util.List.of("apns", "fcm"))))
              .build())
          .build();
      ProfileCreateResponse profile = client.profiles().create(params);
      ```

      ```php PHP highlight={2-5} theme={null}
      $profile = $client->profiles->create('user_123', profile: [
        'pusherBeams' => [
          'interests' => ['interest-1', 'interest-2'],
          'mode' => ['apns', 'fcm'],
        ],
      ]);
      ```

      ```csharp C# highlight={7-16} theme={null}
      ProfileCreateParams parameters = new()
      {
          UserID = "user_123",
          Profile = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
              """
              {
                "pusherBeams": {
                  "interests": [
                    "interest-1",
                    "interest-2"
                  ],
                  "mode": [
                    "apns",
                    "fcm"
                  ]
                }
              }
              """
          ),
      };
      var profile = await client.Profiles.Create(parameters);
      ```

      ```bash CLI highlight={4} wrap theme={null}
      courier profiles create \
        --api-key "$COURIER_API_KEY" \
        --user-id user_123 \
        --profile '{"pusherBeams":{"interests":["interest-1","interest-2"],"mode":["apns","fcm"]}}'
      ```

      ```text MCP theme={null}
      With Courier MCP, save the Pusher Beams interests interest-1 and interest-2 on user_123.
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Users">
    Beams resolves each id against the users it has registered.

    <CodeGroup>
      ```javascript Node.js highlight={3-12} theme={null}
      const profile = await client.profiles.create('user_123', {
        profile: {
          pusherBeams: {
            userIds: [
              'user-id-1',
              'user-id-2',
            ],
            mode: [
              'apns',
              'fcm',
            ],
          },
        },
      });
      ```

      ```python Python highlight={4-13} theme={null}
      profile = client.profiles.create(
          user_id="user_123",
          profile={
              "pusherBeams": {
                  "userIds": [
                      "user-id-1",
                      "user-id-2",
                  ],
                  "mode": [
                      "apns",
                      "fcm",
                  ],
              },
          },
      )
      ```

      ```bash cURL highlight={7-16} theme={null}
      curl --request POST \
        --url https://api.courier.com/profiles/user_123 \
        --header "Authorization: Bearer $COURIER_API_KEY" \
        --header 'Content-Type: application/json' \
        --data '{
          "profile": {
            "pusherBeams": {
              "userIds": [
                "user-id-1",
                "user-id-2"
              ],
              "mode": [
                "apns",
                "fcm"
              ]
            }
          }
        }'
      ```

      ```ruby Ruby highlight={4-7} theme={null}
      profile = courier.profiles.create(
        "user_123",
        profile: {
          pusherBeams: {
            userIds: ["user-id-1", "user-id-2"],
            mode: ["apns", "fcm"]
          }
        }
      )
      ```

      ```go Go highlight={6-9} theme={null}
      profile, err := client.Profiles.New(
      	context.TODO(),
      	"user_123",
      	courier.ProfileNewParams{
      		Profile: map[string]any{
      			"pusherBeams": map[string]any{
      				"userIds": []any{"user-id-1", "user-id-2"},
      				"mode": []any{"apns", "fcm"},
      			},
      		},
      	},
      )
      ```

      ```java Java highlight={4-6} theme={null}
      ProfileCreateParams params = ProfileCreateParams.builder()
          .userId("user_123")
          .profile(ProfileCreateParams.Profile.builder()
              .putAdditionalProperty("pusherBeams", JsonValue.from(java.util.Map.of(
                  "userIds", java.util.List.of("user-id-1", "user-id-2"),
                  "mode", java.util.List.of("apns", "fcm"))))
              .build())
          .build();
      ProfileCreateResponse profile = client.profiles().create(params);
      ```

      ```php PHP highlight={2-5} theme={null}
      $profile = $client->profiles->create('user_123', profile: [
        'pusherBeams' => [
          'userIds' => ['user-id-1', 'user-id-2'],
          'mode' => ['apns', 'fcm'],
        ],
      ]);
      ```

      ```csharp C# highlight={7-16} theme={null}
      ProfileCreateParams parameters = new()
      {
          UserID = "user_123",
          Profile = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
              """
              {
                "pusherBeams": {
                  "userIds": [
                    "user-id-1",
                    "user-id-2"
                  ],
                  "mode": [
                    "apns",
                    "fcm"
                  ]
                }
              }
              """
          ),
      };
      var profile = await client.Profiles.Create(parameters);
      ```

      ```bash CLI highlight={4} wrap theme={null}
      courier profiles create \
        --api-key "$COURIER_API_KEY" \
        --user-id user_123 \
        --profile '{"pusherBeams":{"userIds":["user-id-1","user-id-2"],"mode":["apns","fcm"]}}'
      ```

      ```text MCP theme={null}
      With Courier MCP, save the Pusher Beams user ids user-id-1 and user-id-2 on user_123.
      ```
    </CodeGroup>
  </Tab>
</Tabs>

Then send to `user_id` and Courier resolves the address.

For a one-off with no stored profile, pass it inline instead: `"to": { "pusherBeams": { "interests": ["interest-1"], "mode": ["apns"] } }`.

<CardGroup cols={1}>
  <Card title="Send by user id" icon="user" href="/docs/recipients/overview#send-by-user-id">
    The call in every language, and the rest of the profile object.
  </Card>
</CardGroup>

## Send to a recipient

<Tabs>
  <Tab title="Send to user id">
    Courier reads `pusherBeams` off the saved profile, so preferences apply and the value can change without touching this code.

    <CodeGroup>
      ```javascript Node.js highlight={4} theme={null}
      const { requestId } = await courier.send.message({
        message: {
          to: {
            user_id: "user_123",
          },
          template: "nt_01kx4h2jdafq8bk9aftxak4b40",
        },
      });
      ```

      ```python Python highlight={4} theme={null}
      response = client.send.message(
          message={
              "to": {
                  "user_id": "user_123",
              },
              "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
          },
      )
      ```

      ```bash cURL highlight={7} wrap theme={null}
      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"
          }
        }'
      ```

      ```ruby Ruby highlight={4} theme={null}
      response = courier.send_.message(
        message: {
          to: {
            user_id: "user_123"
          },
          template: "nt_01kx4h2jdafq8bk9aftxak4b40"
        }
      )
      ```

      ```go Go highlight={5} theme={null}
      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"),
      	},
      })
      ```

      ```java Java highlight={3} theme={null}
      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);
      ```

      ```php PHP highlight={4} theme={null}
      $response = $client->send->message(
        message: [
          'to' => [
            'user_id' => 'user_123',
          ],
          'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
        ],
      );
      ```

      ```csharp C# highlight={5} theme={null}
      SendMessageParams parameters = new()
      {
          Message = new()
          {
              To = new UserRecipient { UserID = "user_123" },
              Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
          },
      };

      var response = await client.Send.Message(parameters);
      ```

      ```bash CLI highlight={3} wrap theme={null}
      courier send message \
        --api-key "$COURIER_API_KEY" \
        --message.to '{"user_id": "user_123"}' \
        --message.template nt_01kx4h2jdafq8bk9aftxak4b40
      ```

      ```text MCP theme={null}
      With Courier MCP, send my template to user_123 by email.
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Send to `pusherBeams`">
    Pass it inline instead and nothing is stored. Swap this `to` object into the call on the other tab.

    <CodeGroup>
      ```javascript Node.js highlight={5-8} theme={null}
      const { requestId } = await courier.send.message({
        message: {
          // A provider recipient is a profile field, so it sits outside the typed union.
          to: {
            pusherBeams: {
              interests: ["interest-1", "interest-2"],
              mode: ["apns", "fcm"],
            },
          } as any,
          template: "nt_01kx4h2jdafq8bk9aftxak4b40",
        },
      });
      ```

      ```python Python highlight={4-7} theme={null}
      response = client.send.message(
          message={
              "to": {
                  "pusherBeams": {
                      "interests": ["interest-1", "interest-2"],
                      "mode": ["apns", "fcm"],
                  },
              },
              "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
          },
      )
      ```

      ```bash cURL highlight={7-16} wrap theme={null}
      curl -X POST https://api.courier.com/send \
        -H "Authorization: Bearer $COURIER_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "message": {
            "to": {
              "pusherBeams": {
                "interests": [
                  "interest-1",
                  "interest-2"
                ],
                "mode": [
                  "apns",
                  "fcm"
                ]
              }
            },
            "template": "nt_01kx4h2jdafq8bk9aftxak4b40"
          }
        }'
      ```

      ```ruby Ruby highlight={4-7} theme={null}
      response = courier.send_.message(
        message: {
          to: {
            pusherBeams: {
              interests: ["interest-1", "interest-2"],
              mode: ["apns", "fcm"]
            }
          },
          template: "nt_01kx4h2jdafq8bk9aftxak4b40"
        }
      )
      ```

      ```go Go highlight={2-4} theme={null}
      // A provider recipient is a profile field, so it sits outside the typed union.
      to := param.Override[shared.UserRecipientParam](
      	json.RawMessage(`{"pusherBeams": {"interests": ["interest-1", "interest-2"], "mode": ["apns", "fcm"]}}`),
      )

      response, err := client.Send.Message(context.TODO(), courier.SendMessageParams{
      	Message: courier.SendMessageParamsMessage{
      		To: courier.SendMessageParamsMessageToUnion{OfUserRecipient: &to},
      		Template: courier.String("nt_01kx4h2jdafq8bk9aftxak4b40"),
      	},
      })
      ```

      ```java Java highlight={3-5} theme={null}
      // A provider recipient is a profile field, so it sits outside the typed union.
      UserRecipient to = UserRecipient.builder()
          .putAdditionalProperty("pusherBeams", JsonValue.from(Map.of(
                  "interests", List.of("interest-1", "interest-2"),
                  "mode", List.of("apns", "fcm"))))
          .build();

      client.send().message(SendMessageParams.builder()
          .message(SendMessageParams.Message.builder()
              .to(to)
              .template("nt_01kx4h2jdafq8bk9aftxak4b40")
              .build())
          .build());
      ```

      ```php PHP highlight={4-7} theme={null}
      $response = $client->send->message(
        message: [
          'to' => [
            'pusherBeams' => [
              'interests' => ['interest-1', 'interest-2'],
              'mode' => ['apns', 'fcm'],
            ],
          ],
          'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
        ],
      );
      ```

      ```csharp C# highlight={3-5} theme={null}
      // A provider recipient is a profile field, so it sits outside the typed union.
      UserRecipient to = UserRecipient.FromRawUnchecked(
          JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
              """{"pusherBeams": {"interests": ["interest-1", "interest-2"], "mode": ["apns", "fcm"]}}"""
          )
      );

      var response = await client.Send.Message(new() { Message = new() { To = to, Template = "nt_01kx4h2jdafq8bk9aftxak4b40" } });
      ```

      ```bash CLI highlight={3} wrap theme={null}
      courier send message \
        --api-key "$COURIER_API_KEY" \
        --message.to '{"pusherBeams": {"interests": ["interest-1", "interest-2"], "mode": ["apns", "fcm"]}}' \
        --message.template nt_01kx4h2jdafq8bk9aftxak4b40
      ```

      ```text MCP theme={null}
      With Courier MCP, send my template to the Pusher Beams interests interest-1 and interest-2.
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Overrides

<Doc href="/docs/send/overrides#how-overrides-work">How overrides work</Doc> covers the two levels and which one wins. <Doc href="/docs/integrations/push/overview#channel-overrides">Push channel overrides</Doc> lists the fields every push provider takes.

A provider override changes the request body Courier sends to Pusher Beams, or swaps the instance ID and secret key.

### Body overrides

This example replaces the title and body:

<CodeGroup>
  ```javascript Node.js highlight={15-22} theme={null}
  const { requestId } = await courier.send.message({
    message: {
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      to: {
        pusherBeams: {
          interests: [
            "interest-1",
          ],
          mode: [
            "fcm",
          ],
        },
      },
      providers: {
        "pusher-beams": {
          override: {
            body: {
              title: "Custom Title",
              body: "Custom body text",
            },
          },
        },
      },
    },
  });
  ```

  ```python Python highlight={15-22} theme={null}
  response = client.send.message(
      message={
          "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
          "to": {
              "pusherBeams": {
                  "interests": [
                      "interest-1",
                  ],
                  "mode": [
                      "fcm",
                  ],
              },
          },
          "providers": {
              "pusher-beams": {
                  "override": {
                      "body": {
                          "title": "Custom Title",
                          "body": "Custom body text",
                      },
                  },
              },
          },
      },
  )
  ```

  ```bash cURL highlight={18-25} wrap theme={null}
  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": {
          "pusherBeams": {
            "interests": [
              "interest-1"
            ],
            "mode": [
              "fcm"
            ]
          }
        },
        "providers": {
          "pusher-beams": {
            "override": {
              "body": {
                "title": "Custom Title",
                "body": "Custom body text"
              }
            }
          }
        }
      }
    }'
  ```

  ```ruby Ruby highlight={15-22} theme={null}
  response = courier.send_.message(
    message: {
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      to: {
        pusherBeams: {
          interests: [
            "interest-1"
          ],
          mode: [
            "fcm"
          ]
        }
      },
      providers: {
        "pusher-beams": {
          override: {
            body: {
              title: "Custom Title",
              body: "Custom body text"
            }
          }
        }
      }
    }
  )
  ```

  ```go Go highlight={19-26} theme={null}
  // 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(`{
    "pusherBeams": {
      "interests": [
        "interest-1"
      ],
      "mode": [
        "fcm"
      ]
    }
  }`))

  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{
  			"pusher-beams": shared.MessageProvidersTypeParam{
  				Override: map[string]any{
  					"body": map[string]any{
  						"title": "Custom Title",
  						"body": "Custom body text",
  					},
  				},
  			},
  		},
  	},
  })
  ```

  ```java Java highlight={17-22} theme={null}
  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("pusherBeams", JsonValue.from(java.util.Map.of(
                  "interests", java.util.List.of(
                      "interest-1"
                  ),
                  "mode", java.util.List.of(
                      "fcm"
                  )
              )))
              .build())
          .template("nt_01kx4h2jdafq8bk9aftxak4b40")
          .providers(MessageProviders.builder()
              .putAdditionalProperty("pusher-beams", JsonValue.from(java.util.Map.of("override", java.util.Map.of(
                      "body", java.util.Map.of(
                          "title", "Custom Title",
                          "body", "Custom body text"
                      )
                  ))))
              .build())
          .build())
      .build();
  SendMessageResponse response = client.send().message(params);
  ```

  ```php PHP highlight={15-22} theme={null}
  $response = $client->send->message(
    message: [
      'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
      'to' => [
        'pusherBeams' => [
          'interests' => [
            'interest-1',
          ],
          'mode' => [
            'fcm',
          ],
        ],
      ],
      'providers' => [
        'pusher-beams' => [
          'override' => [
            'body' => [
              'title' => 'Custom Title',
              'body' => 'Custom body text',
            ],
          ],
        ],
      ],
    ],
  );
  ```

  ```csharp C# highlight={26-41} theme={null}
  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>>(
                  """
                  {
                    "pusherBeams": {
                      "interests": [
                        "interest-1"
                      ],
                      "mode": [
                        "fcm"
                      ]
                    }
                  }
                  """
              )
          ),
          Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
          Providers = new Dictionary<string, MessageProvidersType>()
          {
              {
                  "pusher-beams",
                  new()
                  {
                      Override = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
                          """
                          {
                            "body": {
                              "title": "Custom Title",
                              "body": "Custom body text"
                            }
                          }
                          """
                      ),
                  }
              },
          },
      },
  };

  var response = await client.Send.Message(parameters);
  ```

  ```bash CLI highlight={5} wrap theme={null}
  courier send message \
    --api-key "$COURIER_API_KEY" \
    --message.to '{"pusherBeams": {"interests": ["interest-1"], "mode": ["fcm"]}}' \
    --message.template nt_01kx4h2jdafq8bk9aftxak4b40 \
    --message.providers '{"pusher-beams": {"override": {"body": {"title": "Custom Title", "body": "Custom body text"}}}}'
  ```

  ```text MCP theme={null}
  With Courier MCP, send my template to these Pusher Beams interests with the body overridden.
  ```
</CodeGroup>

<Note>
  Courier sets only `title` and `body`. Overrides merge into that alert object and go out in every mode you select, so mode-specific shapes like `fcm.notification` are ignored.
</Note>

### Config overrides

Swap the instance ID or secret key at send time:

<CodeGroup>
  ```javascript Node.js highlight={15-22} theme={null}
  const { requestId } = await courier.send.message({
    message: {
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      to: {
        pusherBeams: {
          interests: [
            "interest-1",
          ],
          mode: [
            "fcm",
          ],
        },
      },
      providers: {
        "pusher-beams": {
          override: {
            config: {
              instanceId: "RUNTIME_INSTANCE_ID",
              secretKey: "RUNTIME_SECRET_KEY",
            },
          },
        },
      },
    },
  });
  ```

  ```python Python highlight={15-22} theme={null}
  response = client.send.message(
      message={
          "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
          "to": {
              "pusherBeams": {
                  "interests": [
                      "interest-1",
                  ],
                  "mode": [
                      "fcm",
                  ],
              },
          },
          "providers": {
              "pusher-beams": {
                  "override": {
                      "config": {
                          "instanceId": "RUNTIME_INSTANCE_ID",
                          "secretKey": "RUNTIME_SECRET_KEY",
                      },
                  },
              },
          },
      },
  )
  ```

  ```bash cURL highlight={18-25} wrap theme={null}
  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": {
          "pusherBeams": {
            "interests": [
              "interest-1"
            ],
            "mode": [
              "fcm"
            ]
          }
        },
        "providers": {
          "pusher-beams": {
            "override": {
              "config": {
                "instanceId": "RUNTIME_INSTANCE_ID",
                "secretKey": "RUNTIME_SECRET_KEY"
              }
            }
          }
        }
      }
    }'
  ```

  ```ruby Ruby highlight={15-22} theme={null}
  response = courier.send_.message(
    message: {
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      to: {
        pusherBeams: {
          interests: [
            "interest-1"
          ],
          mode: [
            "fcm"
          ]
        }
      },
      providers: {
        "pusher-beams": {
          override: {
            config: {
              instanceId: "RUNTIME_INSTANCE_ID",
              secretKey: "RUNTIME_SECRET_KEY"
            }
          }
        }
      }
    }
  )
  ```

  ```go Go highlight={19-26} theme={null}
  // 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(`{
    "pusherBeams": {
      "interests": [
        "interest-1"
      ],
      "mode": [
        "fcm"
      ]
    }
  }`))

  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{
  			"pusher-beams": shared.MessageProvidersTypeParam{
  				Override: map[string]any{
  					"config": map[string]any{
  						"instanceId": "RUNTIME_INSTANCE_ID",
  						"secretKey": "RUNTIME_SECRET_KEY",
  					},
  				},
  			},
  		},
  	},
  })
  ```

  ```java Java highlight={17-22} theme={null}
  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("pusherBeams", JsonValue.from(java.util.Map.of(
                  "interests", java.util.List.of(
                      "interest-1"
                  ),
                  "mode", java.util.List.of(
                      "fcm"
                  )
              )))
              .build())
          .template("nt_01kx4h2jdafq8bk9aftxak4b40")
          .providers(MessageProviders.builder()
              .putAdditionalProperty("pusher-beams", JsonValue.from(java.util.Map.of("override", java.util.Map.of(
                      "config", java.util.Map.of(
                          "instanceId", "RUNTIME_INSTANCE_ID",
                          "secretKey", "RUNTIME_SECRET_KEY"
                      )
                  ))))
              .build())
          .build())
      .build();
  SendMessageResponse response = client.send().message(params);
  ```

  ```php PHP highlight={15-22} theme={null}
  $response = $client->send->message(
    message: [
      'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
      'to' => [
        'pusherBeams' => [
          'interests' => [
            'interest-1',
          ],
          'mode' => [
            'fcm',
          ],
        ],
      ],
      'providers' => [
        'pusher-beams' => [
          'override' => [
            'config' => [
              'instanceId' => 'RUNTIME_INSTANCE_ID',
              'secretKey' => 'RUNTIME_SECRET_KEY',
            ],
          ],
        ],
      ],
    ],
  );
  ```

  ```csharp C# highlight={26-41} theme={null}
  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>>(
                  """
                  {
                    "pusherBeams": {
                      "interests": [
                        "interest-1"
                      ],
                      "mode": [
                        "fcm"
                      ]
                    }
                  }
                  """
              )
          ),
          Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
          Providers = new Dictionary<string, MessageProvidersType>()
          {
              {
                  "pusher-beams",
                  new()
                  {
                      Override = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
                          """
                          {
                            "config": {
                              "instanceId": "RUNTIME_INSTANCE_ID",
                              "secretKey": "RUNTIME_SECRET_KEY"
                            }
                          }
                          """
                      ),
                  }
              },
          },
      },
  };

  var response = await client.Send.Message(parameters);
  ```

  ```bash CLI highlight={5} wrap theme={null}
  courier send message \
    --api-key "$COURIER_API_KEY" \
    --message.to '{"pusherBeams": {"interests": ["interest-1"], "mode": ["fcm"]}}' \
    --message.template nt_01kx4h2jdafq8bk9aftxak4b40 \
    --message.providers '{"pusher-beams": {"override": {"config": {"instanceId": "RUNTIME_INSTANCE_ID", "secretKey": "RUNTIME_SECRET_KEY"}}}}'
  ```

  ```text MCP theme={null}
  With Courier MCP, send my template to these Pusher Beams interests with a different instance id.
  ```
</CodeGroup>

## Provider details

```text theme={null}
pusher-beams
```

Courier recommends routing to the channel. Naming this key in `routing.channels` instead is supported, and sends through just this provider.

<Card title="Send to a specific provider" icon="bullseye-arrow" href="/docs/send/send-to-a-provider" horizontal arrow="true">
  When that is worth doing, and what you give up: failover, channel priority, and providers you add later.
</Card>
