> ## 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 to the inbox

> Route a message to the inbox channel, tag it for a tab, and scope it to a tenant.

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 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>;
};

This page assumes the setup in <Doc href="/docs/in-app/add-an-inbox">Add an inbox</Doc> and <Doc href="/docs/in-app/authenticate-users">Authenticate users</Doc>.

A message reaches the inbox when you include `inbox` in its routing channels.

The inbox is a channel like `email` or `push`, so the same <Endpoint method="POST" path="/send" name="Send a message" href="/docs/api-reference/send/send-a-message">Send API</Endpoint> call delivers to it.

<Frame caption="A message delivered to the Courier Inbox after a send.">
  <img src="https://mintcdn.com/courier-4f1f25dc/9rcgucLA9fBnJt_U/assets/inbox-delivered.webp?fit=max&auto=format&n=9rcgucLA9fBnJt_U&q=85&s=5dddc3c19bf3e5ceacc822c70a457ca3" alt="A just-delivered message in the Courier Inbox, unread and timestamped Now, with the header unread count reading 1" className="mx-auto" width="3152" height="1776" data-path="assets/inbox-delivered.webp" />
</Frame>

## Route a message to the inbox

This send references a published template with an In-App channel, so create one before you run it.

<CodeGroup>
  ```javascript Node.js theme={null}
  const response = await client.send.message({
    message: {
      to: { user_id: "user_123" },
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      data: { name: "Sarah Bennett" },
      routing: { method: "single", channels: ["inbox"] },
    },
  });

  console.log(response.requestId);
  ```

  ```python Python theme={null}
  response = client.send.message(
      message={
          "to": {"user_id": "user_123"},
          "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
          "data": {"name": "Sarah Bennett"},
          "routing": {"method": "single", "channels": ["inbox"]},
      },
  )
  ```

  ```bash cURL 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",
        "data": { "name": "Sarah Bennett" },
        "routing": { "method": "single", "channels": ["inbox"] }
      }
    }'
  ```

  ```ruby Ruby theme={null}
  response = courier.send_.message(
    message: {
      to: { user_id: "user_123" },
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      data: { name: "Sarah Bennett" },
      routing: { method: "single", channels: ["inbox"] }
    }
  )
  ```

  ```go Go 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"),
      Data: map[string]any{"name": "Sarah Bennett"},
      Routing: courier.SendMessageParamsMessageRouting{
        Method: string(shared.MessageRoutingMethodSingle),
        Channels: []shared.MessageRoutingChannelUnionParam{
          {OfString: courier.String("inbox")},
        },
      },
    },
  })
  ```

  ```java Java theme={null}
  SendMessageParams.Message message = SendMessageParams.Message.builder()
      .to(SendMessageParams.Message.To.ofUserRecipient(
          UserRecipient.builder().userId("user_123").build()))
      .template("nt_01kx4h2jdafq8bk9aftxak4b40")
      .data(SendMessageParams.Message.Data.builder()
          .putAdditionalProperty("name", JsonValue.from("Sarah Bennett"))
          .build())
      .routing(SendMessageParams.Message.Routing.builder()
          .method(SendMessageParams.Message.Routing.Method.SINGLE)
          .channels(List.of(MessageRoutingChannel.ofString("inbox")))
          .build())
      .build();

  SendMessageResponse response = client.send().message(
      SendMessageParams.builder().message(message).build());
  ```

  ```php PHP theme={null}
  $response = $client->send->message(
    message: [
      'to' => ['userID' => "user_123"],
      'template' => "nt_01kx4h2jdafq8bk9aftxak4b40",
      'data' => ['name' => "Sarah Bennett"],
      'routing' => ['method' => "single", 'channels' => ["inbox"]],
    ],
  );
  ```

  ```csharp C# theme={null}
  var response = await client.Send.Message(new SendMessageParams
  {
      Message = new Message
      {
          To = new To(new UserRecipient { UserID = "user_123" }),
          Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
          Data = new Dictionary<string, JsonElement>
          {
              { "name", JsonSerializer.SerializeToElement("Sarah Bennett") }
          },
          Routing = new Routing
          {
              Method = Method.Single,
              Channels = new List<MessageRoutingChannel> { new MessageRoutingChannel("inbox") }
          }
      }
  });
  ```

  ```bash CLI theme={null}
  courier send message --message '{
    "to": { "user_id": "user_123" },
    "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
    "data": { "name": "Sarah Bennett" },
    "routing": { "method": "single", "channels": ["inbox"] }
  }'
  ```

  ```text MCP theme={null}
  With Courier MCP, send my nt_01kx4h2jdafq8bk9aftxak4b40 template to user_123 on the inbox channel.
  ```
</CodeGroup>

The inbox shows the template's **In-App** channel, so build that channel when you <Doc href="/docs/design/templates/overview">design a template</Doc>. For the send call itself, see <Doc href="/docs/send/overview">Send a message</Doc>.

The SDK receives everything in `data` with the message. Fields your template references (like `{{ name }}`) are interpolated. The rest passes through untouched, which is useful for deep linking to a screen when the user taps a message.

Inbox messages also drive toasts. Render the toast component and a popup appears for each new message on the feed. See <Doc href="/docs/in-app/add-toasts">Add toasts</Doc>.

## Tag a message for a tab

Inbox tabs filter on tags, and a message gets its tags from `metadata.tags` on the send. A tab defined with `filter: { tags: ["order"] }` shows the messages you tag here.

<CodeGroup>
  ```javascript Node.js highlight={6} theme={null}
  const response = await client.send.message({
    message: {
      to: { user_id: "user_123" },
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      data: { name: "Sarah Bennett" },
      metadata: { tags: ["order"] },
      routing: { method: "single", channels: ["inbox"] },
    },
  });
  ```

  ```python Python highlight={6} theme={null}
  response = client.send.message(
      message={
          "to": {"user_id": "user_123"},
          "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
          "data": {"name": "Sarah Bennett"},
          "metadata": {"tags": ["order"]},
          "routing": {"method": "single", "channels": ["inbox"]},
      },
  )
  ```

  ```bash cURL highlight={8} 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",
        "metadata": { "tags": ["order"] },
        "routing": { "method": "single", "channels": ["inbox"] }
      }
    }'
  ```

  ```ruby Ruby highlight={6} theme={null}
  response = courier.send_.message(
    message: {
      to: { user_id: "user_123" },
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      data: { name: "Sarah Bennett" },
      metadata: { tags: ["order"] },
      routing: { method: "single", channels: ["inbox"] }
    }
  )
  ```

  ```go Go highlight={9-11} 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"),
      Metadata: courier.SendMessageParamsMessageMetadata{
        Tags: []string{"order"},
      },
      Routing: courier.SendMessageParamsMessageRouting{
        Method: string(shared.MessageRoutingMethodSingle),
        Channels: []shared.MessageRoutingChannelUnionParam{
          {OfString: courier.String("inbox")},
        },
      },
    },
  })
  ```

  ```java Java highlight={5-7} theme={null}
  SendMessageParams.Message message = SendMessageParams.Message.builder()
      .to(SendMessageParams.Message.To.ofUserRecipient(
          UserRecipient.builder().userId("user_123").build()))
      .template("nt_01kx4h2jdafq8bk9aftxak4b40")
      .metadata(SendMessageParams.Message.Metadata.builder()
          .tags(List.of("order"))
          .build())
      .routing(SendMessageParams.Message.Routing.builder()
          .method(SendMessageParams.Message.Routing.Method.SINGLE)
          .channels(List.of(MessageRoutingChannel.ofString("inbox")))
          .build())
      .build();

  SendMessageResponse response = client.send().message(
      SendMessageParams.builder().message(message).build());
  ```

  ```php PHP highlight={5} theme={null}
  $response = $client->send->message(
    message: [
      'to' => ['userID' => "user_123"],
      'template' => "nt_01kx4h2jdafq8bk9aftxak4b40",
      'metadata' => ['tags' => ["order"]],
      'routing' => ['method' => "single", 'channels' => ["inbox"]],
    ],
  );
  ```

  ```csharp C# highlight={7} theme={null}
  var response = await client.Send.Message(new SendMessageParams
  {
      Message = new Message
      {
          To = new To(new UserRecipient { UserID = "user_123" }),
          Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
          Metadata = new() { Tags = ["order"] },
          Routing = new Routing
          {
              Method = Method.Single,
              Channels = new List<MessageRoutingChannel> { new MessageRoutingChannel("inbox") }
          }
      }
  });
  ```

  ```bash CLI highlight={4} theme={null}
  courier send message --message '{
    "to": { "user_id": "user_123" },
    "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
    "metadata": { "tags": ["order"] },
    "routing": { "method": "single", "channels": ["inbox"] }
  }'
  ```

  ```text MCP theme={null}
  With Courier MCP, send my nt_01kx4h2jdafq8bk9aftxak4b40 template to user_123 on the inbox channel, tagged order.
  ```
</CodeGroup>

A message carries at most 9 tags, and each tag is a string of up to 30 characters. Exceeding either limit fails the send with a validation error on `metadata.tags`.

Tags reach the client on every inbox message, so a custom UI can read them too. <Doc href="/docs/in-app/tabs-and-feeds">Tabs and feeds</Doc> covers defining the tabs that filter on them.

## Scope the inbox to a tenant

To show only one <Doc href="/docs/tenants/overview">tenant</Doc>'s messages, pass `tenantId` at sign-in. You set it on the client, and it applies to every read and the realtime connection. There is no per-component tenant property.

<CodeGroup>
  ```jsx React theme={null}
  courier.shared.signIn({ userId, jwt, tenantId: "acme" });
  ```

  ```html Web Components theme={null}
  <script type="module">
    Courier.shared.signIn({ userId, jwt, tenantId: "acme" });
  </script>
  ```

  ```vue Vue theme={null}
  courier.shared.signIn({ userId, jwt, tenantId: "acme" });
  ```

  ```ts Angular theme={null}
  this.courier.signIn({ userId, jwt, tenantId: "acme" });
  ```

  ```swift iOS theme={null}
  await Courier.shared.signIn(userId: userId, tenantId: "acme", accessToken: jwt)
  ```

  ```kotlin Android theme={null}
  // signIn is a suspend function; call it from a coroutine
  lifecycleScope.launch {
    Courier.shared.signIn(userId = userId, tenantId = "acme", accessToken = jwt)
  }
  ```

  ```dart Flutter theme={null}
  await Courier.shared.signIn(accessToken: jwt, userId: userId, tenantId: "acme");
  ```

  ```jsx React Native theme={null}
  await Courier.shared.signIn({ accessToken: jwt, userId, tenantId: "acme" });
  ```
</CodeGroup>

Send to that tenant's inbox by setting `context.tenant_id` on the recipient. The message is visible only when the user signs in with the same tenant. (A bare `tenant_id` in `to`, with no `user_id`, fans out to every member of the tenant instead.)

<CodeGroup>
  ```javascript Node.js highlight={3} theme={null}
  await client.send.message({
    message: {
      to: { user_id: "user_123", context: { tenant_id: "acme" } },
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      data: { name: "Sarah Bennett" },
      routing: { method: "single", channels: ["inbox"] },
    },
  });
  ```

  ```python Python highlight={3} theme={null}
  client.send.message(
      message={
          "to": {"user_id": "user_123", "context": {"tenant_id": "acme"}},
          "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
          "data": {"name": "Sarah Bennett"},
          "routing": {"method": "single", "channels": ["inbox"]},
      },
  )
  ```

  ```bash cURL highlight={6} 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", "context": { "tenant_id": "acme" } },
        "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
        "data": { "name": "Sarah Bennett" },
        "routing": { "method": "single", "channels": ["inbox"] }
      }
    }'
  ```

  ```ruby Ruby highlight={3} theme={null}
  courier.send_.message(
    message: {
      to: { user_id: "user_123", context: { tenant_id: "acme" } },
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      data: { name: "Sarah Bennett" },
      routing: { method: "single", channels: ["inbox"] }
    }
  )
  ```

  ```go Go highlight={6} 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"),
          Context: shared.MessageContextParam{TenantID: courier.String("acme")},
        },
      },
      Template: courier.String("nt_01kx4h2jdafq8bk9aftxak4b40"),
      Data: map[string]any{"name": "Sarah Bennett"},
      Routing: courier.SendMessageParamsMessageRouting{
        Method: string(shared.MessageRoutingMethodSingle),
        Channels: []shared.MessageRoutingChannelUnionParam{
          {OfString: courier.String("inbox")},
        },
      },
    },
  })
  ```

  ```java Java highlight={5} theme={null}
  SendMessageParams.Message message = SendMessageParams.Message.builder()
      .to(SendMessageParams.Message.To.ofUserRecipient(
          UserRecipient.builder()
              .userId("user_123")
              .context(MessageContext.builder().tenantId("acme").build())
              .build()))
      .template("nt_01kx4h2jdafq8bk9aftxak4b40")
      .data(SendMessageParams.Message.Data.builder()
          .putAdditionalProperty("name", JsonValue.from("Sarah Bennett"))
          .build())
      .routing(SendMessageParams.Message.Routing.builder()
          .method(SendMessageParams.Message.Routing.Method.SINGLE)
          .channels(List.of(MessageRoutingChannel.ofString("inbox")))
          .build())
      .build();

  client.send().message(SendMessageParams.builder().message(message).build());
  ```

  ```php PHP highlight={3} theme={null}
  $client->send->message(
    message: [
      'to' => ['userID' => "user_123", 'context' => ['tenantID' => "acme"]],
      'template' => "nt_01kx4h2jdafq8bk9aftxak4b40",
      'data' => ['name' => "Sarah Bennett"],
      'routing' => ['method' => "single", 'channels' => ["inbox"]],
    ],
  );
  ```

  ```csharp C# highlight={8} theme={null}
  await client.Send.Message(new SendMessageParams
  {
      Message = new Message
      {
          To = new To(new UserRecipient
          {
              UserID = "user_123",
              Context = new MessageContext { TenantID = "acme" }
          }),
          Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
          Data = new Dictionary<string, JsonElement>
          {
              { "name", JsonSerializer.SerializeToElement("Sarah Bennett") }
          },
          Routing = new Routing
          {
              Method = Method.Single,
              Channels = new List<MessageRoutingChannel> { new MessageRoutingChannel("inbox") }
          }
      }
  });
  ```

  ```bash CLI highlight={2} theme={null}
  courier send message --message '{
    "to": { "user_id": "user_123", "context": { "tenant_id": "acme" } },
    "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
    "data": { "name": "Sarah Bennett" },
    "routing": { "method": "single", "channels": ["inbox"] }
  }'
  ```

  ```text MCP theme={null}
  With Courier MCP, send my nt_01kx4h2jdafq8bk9aftxak4b40 template to user_123 in the acme tenant's inbox.
  ```
</CodeGroup>

## FAQ

<AccordionGroup>
  <Accordion title="Why is my inbox message not arriving?">
    Confirm all three:

    * The Courier Inbox provider is added to your workspace.
    * The message routing includes `channels: ["inbox"]`.
    * The recipient `user_id` matches the `userId` you <Doc href="/docs/in-app/authenticate-users">signed in with</Doc>.
  </Accordion>

  <Accordion title="Do toasts need separate setup from the inbox?">
    Toasts read the same feed and use the same `signIn`. Render `CourierToast` (or `<courier-toast>`) anywhere in your app after sign-in. See <Doc href="/docs/in-app/add-toasts">Add toasts</Doc>.
  </Accordion>

  <Accordion title="Can one user see different inboxes per tenant?">
    Sign in with a `tenantId` to scope the inbox to that tenant. Sign in again with a different `tenantId` to switch. The scope is client-level, not per-component. See [Scope the inbox to a tenant](#scope-the-inbox-to-a-tenant).
  </Accordion>
</AccordionGroup>
