> ## 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 a list or audience

> Send one announcement to a saved list or audience and confirm every member got it.

export const Tags = ({items}) => {
  const routes = {
    Email: "/integrations/email/overview",
    SMS: "/integrations/sms/overview",
    Push: "/integrations/push/overview",
    Inbox: "/in-app/overview",
    Chat: "/integrations/direct-message/overview",
    Templates: "/design/templates/overview",
    Variables: "/design/templates/variables",
    Elemental: "/design/elemental/overview",
    Brands: "/design/brands",
    Translations: "/design/elemental/locales",
    Routing: "/send/routing",
    Preferences: "/recipients/preferences/overview",
    Journeys: "/journeys/overview",
    Broadcasts: "/broadcasts/overview",
    Tenants: "/tenants/overview",
    Logs: "/monitor/overview",
    Webhooks: "/monitor/webhooks/outbound",
    Lists: "/recipients/lists-and-audiences/overview",
    Users: "/recipients/overview",
    Digests: "/journeys/nodes/digest",
    Environments: "/workspaces/overview",
    MCP: "/resources/mcp"
  };
  const icons = {
    Email: "envelope",
    SMS: "comment",
    Push: "mobile",
    Inbox: "inbox",
    Chat: "comments",
    Templates: "pen-ruler",
    Variables: "pen-ruler",
    Elemental: "pen-ruler",
    Brands: "pen-ruler",
    Translations: "pen-ruler",
    Routing: "paper-plane",
    Preferences: "users",
    Journeys: "route",
    Broadcasts: "bullhorn",
    Tenants: "building",
    Logs: "chart-simple",
    Webhooks: "chart-simple",
    Lists: "users",
    Users: "users",
    Digests: "route",
    Environments: "briefcase",
    MCP: "toolbox"
  };
  const base = "https://d3gk2c5xim1je2.cloudfront.net/fontawesome/v7.2.0/regular/";
  const names = String(items || "").split(",").map(entry => entry.trim()).filter(Boolean);
  return <div className="cx-tags">
      {names.map(name => {
    const href = routes[name];
    const icon = icons[name];
    const url = icon ? "url(" + base + icon + ".svg)" : null;
    const style = url ? {
      "--cx-tag-icon": url
    } : null;
    if (!href) {
      return <span className="cx-tag" data-icon={icon} style={style} key={name}>
              {name}
            </span>;
    }
    return <a className="cx-tag" data-icon={icon} style={style} href={href} key={name}>
            {name}
          </a>;
  })}
    </div>;
};

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 Guide = ({href, children, name, bare}) => {
  const label = children || name || href;
  if (bare) {
    return <a href={href}>{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="guide" href={href}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">GUIDE</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>;
};

<Tags items="Lists, Templates" />

Send one announcement to a saved group, and confirm every member received it.

You address the group, not its people. Courier resolves membership at send time and delivers one message per member.

## Prerequisites

* <Doc href="/docs/recipients/lists-and-audiences/overview">A list or audience</Doc>
* <Doc href="/docs/design/templates/overview">A published template</Doc>
* <AppLink href="https://app.courier.com/settings/api-keys">A Courier API key</AppLink>

## Send to the group

<Steps>
  <Step title="Send to a list">
    A list is a group you curate by hand. Put its `list_id` in `to` and Courier sends to each member.

    <CodeGroup>
      ```javascript Node.js highlight={3} theme={null}
      const { requestId } = await client.send.message({
        message: {
          to: { list_id: 'acme-corp.beta-testers' },
          template: 'nt_01kx4h2jdafq8bk9aftxak4b40',
        },
      });
      ```

      ```python Python highlight={3} theme={null}
      response = client.send.message(
          message={
              "to": {"list_id": "acme-corp.beta-testers"},
              "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
          },
      )
      ```

      ```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": { "list_id": "acme-corp.beta-testers" },
            "template": "nt_01kx4h2jdafq8bk9aftxak4b40"
          }
        }'
      ```

      ```ruby Ruby highlight={3} theme={null}
      response = courier.send_.message(
        message: {
          to: { list_id: "acme-corp.beta-testers" },
          template: "nt_01kx4h2jdafq8bk9aftxak4b40"
        }
      )
      ```

      ```go Go highlight={5} theme={null}
      response, err := client.Send.Message(context.TODO(), courier.SendMessageParams{
      	Message: courier.SendMessageParamsMessage{
      		To: courier.SendMessageParamsMessageToUnion{
      			OfListRecipient: &shared.ListRecipientParam{
      				ListID: courier.String("acme-corp.beta-testers"),
      			},
      		},
      		Template: courier.String("nt_01kx4h2jdafq8bk9aftxak4b40"),
      	},
      })
      ```

      ```java Java highlight={3} theme={null}
      SendMessageParams params = SendMessageParams.builder()
          .message(SendMessageParams.Message.builder()
              .to(JsonValue.from(java.util.Map.of("list_id", "acme-corp.beta-testers")))
              .template("nt_01kx4h2jdafq8bk9aftxak4b40")
              .build())
          .build();
      client.send().message(params);
      ```

      ```php PHP highlight={3} theme={null}
      $response = $client->send->message(
        message: [
          'to' => ['listID' => 'acme-corp.beta-testers'],
          'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
        ],
      );
      ```

      ```csharp C# highlight={5} theme={null}
      SendMessageParams parameters = new()
      {
          Message = new()
          {
              To = new ListRecipient { ListID = "acme-corp.beta-testers" },
              Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
          },
      };

      await client.Send.Message(parameters);
      ```

      ```bash CLI highlight={3} theme={null}
      courier send message \
        --api-key "$COURIER_API_KEY" \
        --message '{"to":{"list_id":"acme-corp.beta-testers"},"template":"nt_01kx4h2jdafq8bk9aftxak4b40"}'
      ```

      ```text MCP theme={null}
      With Courier MCP, send my nt_01kx4h2jdafq8bk9aftxak4b40 template to the acme-corp.beta-testers list.
      ```
    </CodeGroup>
  </Step>

  <Step title="Send to an audience">
    An audience is a group Courier keeps current from rules you write. Put its `audience_id` in `to` and everyone who matches now receives the message.

    <CodeGroup>
      ```javascript Node.js highlight={3} theme={null}
      const { requestId } = await client.send.message({
        message: {
          to: { audience_id: 'active-business-users' },
          template: 'nt_01kx4h2jdafq8bk9aftxak4b40',
        },
      });
      ```

      ```python Python highlight={3} theme={null}
      response = client.send.message(
          message={
              "to": {"audience_id": "active-business-users"},
              "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
          },
      )
      ```

      ```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": { "audience_id": "active-business-users" },
            "template": "nt_01kx4h2jdafq8bk9aftxak4b40"
          }
        }'
      ```

      ```ruby Ruby highlight={3} theme={null}
      response = courier.send_.message(
        message: {
          to: { audience_id: "active-business-users" },
          template: "nt_01kx4h2jdafq8bk9aftxak4b40"
        }
      )
      ```

      ```go Go highlight={5} theme={null}
      response, err := client.Send.Message(context.TODO(), courier.SendMessageParams{
      	Message: courier.SendMessageParamsMessage{
      		To: courier.SendMessageParamsMessageToUnion{
      			OfAudienceRecipient: &shared.AudienceRecipientParam{
      				AudienceID: "active-business-users",
      			},
      		},
      		Template: courier.String("nt_01kx4h2jdafq8bk9aftxak4b40"),
      	},
      })
      ```

      ```java Java highlight={3} theme={null}
      SendMessageParams params = SendMessageParams.builder()
          .message(SendMessageParams.Message.builder()
              .to(JsonValue.from(java.util.Map.of("audience_id", "active-business-users")))
              .template("nt_01kx4h2jdafq8bk9aftxak4b40")
              .build())
          .build();
      client.send().message(params);
      ```

      ```php PHP highlight={3} theme={null}
      $response = $client->send->message(
        message: [
          'to' => ['audienceID' => 'active-business-users'],
          'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
        ],
      );
      ```

      ```csharp C# highlight={5} theme={null}
      SendMessageParams parameters = new()
      {
          Message = new()
          {
              To = new AudienceRecipient { AudienceID = "active-business-users" },
              Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
          },
      };

      await client.Send.Message(parameters);
      ```

      ```bash CLI highlight={3} theme={null}
      courier send message \
        --api-key "$COURIER_API_KEY" \
        --message '{"to":{"audience_id":"active-business-users"},"template":"nt_01kx4h2jdafq8bk9aftxak4b40"}'
      ```
    </CodeGroup>
  </Step>

  <Step title="Reach many lists at once">
    A `list_id` is a dotted namespace, so `list_pattern` targets several lists in one call. Use `*` for one part of the name, or `**` as a trailing wildcard.

    <CodeGroup>
      ```javascript Node.js highlight={4} theme={null}
      const { requestId } = await client.send.message({
        message: {
          to: {
            list_pattern: "acme-corp.*.beta-testers",
          },
          template: "nt_01kx4h2jdafq8bk9aftxak4b40",
        },
      });
      ```

      ```python Python highlight={4} theme={null}
      response = client.send.message(
          message={
              "to": {
                  "list_pattern": "acme-corp.*.beta-testers",
              },
              "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": {
              "list_pattern": "acme-corp.*.beta-testers"
            },
            "template": "nt_01kx4h2jdafq8bk9aftxak4b40"
          }
        }'
      ```

      ```ruby Ruby highlight={4} theme={null}
      response = courier.send_.message(
        message: {
          to: {
            list_pattern: "acme-corp.*.beta-testers"
          },
          template: "nt_01kx4h2jdafq8bk9aftxak4b40"
        }
      )
      ```

      ```go Go highlight={4} 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(`{
        "list_pattern": "acme-corp.*.beta-testers"
      }`))

      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={6} 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("list_pattern", JsonValue.from("acme-corp.*.beta-testers"))
                  .build())
              .template("nt_01kx4h2jdafq8bk9aftxak4b40")
              .build())
          .build();
      SendMessageResponse response = client.send().message(params);
      ```

      ```php PHP highlight={4} theme={null}
      $response = $client->send->message(
        message: [
          'to' => [
            'list_pattern' => 'acme-corp.*.beta-testers',
          ],
          'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
        ],
      );
      ```

      ```csharp C# highlight={11} 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>>(
                      """
                      {
                        "list_pattern": "acme-corp.*.beta-testers"
                      }
                      """
                  )
              ),
              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 '{"list_pattern": "acme-corp.*.beta-testers"}' \
        --message.template nt_01kx4h2jdafq8bk9aftxak4b40
      ```

      ```text MCP theme={null}
      With Courier MCP, send my nt_01kx4h2jdafq8bk9aftxak4b40 template to every beta-testers list under acme-corp.
      ```
    </CodeGroup>
  </Step>
</Steps>

## Verify

<Steps>
  <Step title="Count the messages">
    Open <AppLink href="https://app.courier.com/logs">Logs</AppLink> and confirm one message per member.
  </Step>

  <Step title="Reconcile a wrong count">
    Compare the log against the membership from the <Endpoint method="GET" path="/lists/{list_id}" name="Get a List" href="/docs/api-reference/lists/get-a-list">Lists</Endpoint> or <Endpoint method="GET" path="/audiences/{audience_id}/members" name="List Audience members" href="/docs/api-reference/audiences/list-audience-members">Audiences</Endpoint> API.
  </Step>

  <Step title="Check who was filtered out">
    Members who opted out of the template's topic show as `UNSUBSCRIBED` rather than delivered. That is preferences working, not a failed send.
  </Step>
</Steps>

<Note>
  A list or audience must exist first. For a one-off set of recipients, <Guide href="/docs/guides/send-in-bulk">send in bulk</Guide> instead.
</Note>
