> ## 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` from the Node SDK (`@trycourier/courier` v7 and later, where the client is the default import). 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.
> To translate a template, write one locale at a time with `PUT /notifications/{id}/locales/{localeId}`, which merges into the existing translations. `PUT /notifications/{id}/content` and `PUT /notifications/{id}/elements/{elementId}` overwrite translations along with the content, so send each element's `id` and `locales` back, and first remove every `checksum` and any `locales` key that starts with an underscore.
> 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.

# Routing strategies

> Save channel order, fallback, and provider priority as a routing strategy, attach it to templates, and change delivery for all of them in one edit.

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

A routing strategy is a saved routing setup: the channels a template sends on, their fallback order, and the providers behind each one. Templates point at a strategy by ID, so one edit changes delivery for every template that uses it.

<Frame>
  <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/designer-v2-advanced-routing-modal.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=863fb1e12cb89cb16d4f4920e798e080" alt="A routing strategy in Design Studio: email always sends, then SMS, Slack, MS Teams, In-App, and push as fallbacks, with a flowchart of the route" width="1954" height="1702" data-path="assets/designer-v2-advanced-routing-modal.webp" />
</Frame>

## What a strategy holds

A strategy carries the same `routing` object you'd pass on a send, plus the per-channel and per-provider settings around it. Its ID starts with `rs_`.

| Field                 | What it sets                                                                                                                         |
| :-------------------- | :----------------------------------------------------------------------------------------------------------------------------------- |
| `name`                | The label in the routing selector                                                                                                    |
| `routing`             | The channel list and `method`, as described in <Doc href="/docs/send/routing#two-decisions-channel-then-provider">How routing works</Doc> |
| `channels`            | Per channel: `providers` in priority order, `routing_method`, an `if` condition, and an `override`                                   |
| `providers`           | Per provider: an `if` condition and an `override` that apply on every channel                                                        |
| `description`, `tags` | Your own labels for finding the strategy later                                                                                       |

## Build a strategy in Design Studio

Open a template and click the **routing selector** in the toolbar. It lists the workspace's strategies, with a pencil icon to edit each one and **Add new routing** to create one. Picking a strategy attaches it to the template.

<Frame>
  <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/designer-v2-routing-selector.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=12df464d297c11f459c5c6fb53eb72b6" alt="The routing selector open in the Design Studio toolbar, listing three strategies with edit icons and an Add new routing option" width="1498" height="636" data-path="assets/designer-v2-routing-selector.webp" />
</Frame>

Give the strategy a **Routing name**, then pick a **Routing scheme**:

* **Basic** sends on every channel you switch on, at the same time.
* **Advanced** splits channels into two lists. Everything under **Always send to the following channels (min. 1)** sends. If the last of those fails, Courier tries the channels under **If the last above fails, send to the first successful one below**, in order, until one delivers.

Drag channels to change their order. The flowchart beside the lists draws the route as you build it.

To set the provider order for a channel, click the pencil icon next to it. Under **Routing scheme**, **To the best of** tries providers in the order you drag them into, and **To all** sends through every one. **Add more integrations** puts another provider on the channel. The **Conditions** tab sets when the channel is used, on every template that shares the strategy.

Click **Create routing strategy** to save a new one, or **Save and close** after an edit. **Delete** stays disabled while any template uses the strategy, so move those templates to another strategy first.

## Manage strategies with the API

### Create a strategy

<Endpoint method="POST" path="/routing-strategies" name="Create Routing Strategy" href="/docs/api-reference/routing-strategies/create-routing-strategy" /> takes a `name` and a `routing` object. This strategy tries email, then SMS, and sends email through SendGrid with SES as the backup:

<CodeGroup>
  ```javascript Node.js highlight={5} theme={null}
  const strategy = await courier.routingStrategies.create({
    name: "Email with SMS fallback",
    routing: { method: "single", channels: ["email", "sms"] },
    channels: {
      email: { providers: ["sendgrid", "ses"] },
    },
    tags: ["production"],
  });
  ```

  ```python Python highlight={5} theme={null}
  strategy = client.routing_strategies.create(
      name="Email with SMS fallback",
      routing={"method": "single", "channels": ["email", "sms"]},
      channels={
          "email": {"providers": ["sendgrid", "ses"]},
      },
      tags=["production"],
  )
  ```

  ```bash cURL highlight={8} theme={null}
  curl -X POST https://api.courier.com/routing-strategies \
    -H "Authorization: Bearer $COURIER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Email with SMS fallback",
      "routing": { "method": "single", "channels": ["email", "sms"] },
      "channels": {
        "email": { "providers": ["sendgrid", "ses"] }
      },
      "tags": ["production"]
    }'
  ```

  ```ruby Ruby highlight={5} theme={null}
  strategy = courier.routing_strategies.create(
    name: "Email with SMS fallback",
    routing: {method: :single, channels: ["email", "sms"]},
    channels: {
      email: {providers: ["sendgrid", "ses"]}
    },
    tags: ["production"]
  )
  ```

  ```go Go highlight={12} theme={null}
  strategy, err := client.RoutingStrategies.New(context.TODO(), courier.RoutingStrategyNewParams{
  	RoutingStrategyCreateRequest: courier.RoutingStrategyCreateRequestParam{
  		Name: "Email with SMS fallback",
  		Routing: shared.MessageRoutingParam{
  			Method: shared.MessageRoutingMethodSingle,
  			Channels: []shared.MessageRoutingChannelUnionParam{
  				{OfString: courier.String("email")},
  				{OfString: courier.String("sms")},
  			},
  		},
  		Channels: shared.MessageChannelsParam{
  			"email": shared.ChannelParam{Providers: []string{"sendgrid", "ses"}},
  		},
  		Tags: []string{"production"},
  	},
  })
  ```

  ```java Java highlight={11} theme={null}
  RoutingStrategyGetResponse strategy = client.routingStrategies().create(
      RoutingStrategyCreateRequest.builder()
          .name("Email with SMS fallback")
          .routing(MessageRouting.builder()
              .method(MessageRouting.Method.SINGLE)
              .addChannel("email")
              .addChannel("sms")
              .build())
          .channels(MessageChannels.builder()
              .putAdditionalProperty("email", JsonValue.from(java.util.Map.of(
                  "providers", java.util.List.of("sendgrid", "ses"))))
              .build())
          .addTag("production")
          .build());
  ```

  ```php PHP highlight={5} theme={null}
  $strategy = $client->routingStrategies->create(
    name: 'Email with SMS fallback',
    routing: ['method' => 'single', 'channels' => ['email', 'sms']],
    channels: [
      'email' => ['providers' => ['sendgrid', 'ses']],
    ],
    tags: ['production'],
  );
  ```

  ```csharp C# highlight={7} theme={null}
  RoutingStrategyCreateParams parameters = new()
  {
      Name = "Email with SMS fallback",
      Routing = new() { Method = Method.Single, Channels = ["email", "sms"] },
      Channels = new Dictionary<string, Channel>()
      {
          { "email", new() { Providers = ["sendgrid", "ses"] } },
      },
      Tags = ["production"],
  };

  var strategy = await client.RoutingStrategies.Create(parameters);
  ```

  ```bash CLI highlight={5} theme={null}
  courier routing-strategies create \
    --api-key "$COURIER_API_KEY" \
    --name "Email with SMS fallback" \
    --routing '{"method": "single", "channels": ["email", "sms"]}' \
    --channels '{"email": {"providers": ["sendgrid", "ses"]}}' \
    --tag production
  ```

  ```text MCP theme={null}
  With Courier MCP, create a routing strategy named "Email with SMS fallback" that tries email first, then SMS, and sends email through SendGrid with SES as the backup.
  ```
</CodeGroup>

The response carries the new strategy's `id`. Set it as `routing.strategy_id` when you create or replace a template, as shown in <Doc href="/docs/design/templates/api">Manage templates with the API</Doc>.

### Switch providers on every template at once

Every template that uses a strategy picks up a change on its next send, so one edit moves all of them to a new provider. Courier reads the strategy at send time, so no template needs republishing. To see which templates a change reaches, call <Endpoint method="GET" path="/routing-strategies/{id}/notifications" name="List notifications for a Routing Strategy" href="/docs/api-reference/routing-strategies/list-notifications-for-a-routing-strategy" /> first.

<Endpoint method="PUT" path="/routing-strategies/{id}" name="Replace Routing Strategy" href="/docs/api-reference/routing-strategies/replace-routing-strategy" /> takes the complete strategy and clears any field you leave out, so send every field you want to keep. This puts SES ahead of SendGrid:

<CodeGroup>
  ```javascript Node.js highlight={5} theme={null}
  const strategy = await courier.routingStrategies.replace("rs_01kx4h2jdafq8bk9amzvy6hbv0", {
    name: "Email with SMS fallback",
    routing: { method: "single", channels: ["email", "sms"] },
    channels: {
      email: { providers: ["ses", "sendgrid"] },
    },
    tags: ["production"],
  });
  ```

  ```python Python highlight={6} theme={null}
  strategy = client.routing_strategies.replace(
      id="rs_01kx4h2jdafq8bk9amzvy6hbv0",
      name="Email with SMS fallback",
      routing={"method": "single", "channels": ["email", "sms"]},
      channels={
          "email": {"providers": ["ses", "sendgrid"]},
      },
      tags=["production"],
  )
  ```

  ```bash cURL highlight={8} theme={null}
  curl -X PUT https://api.courier.com/routing-strategies/rs_01kx4h2jdafq8bk9amzvy6hbv0 \
    -H "Authorization: Bearer $COURIER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Email with SMS fallback",
      "routing": { "method": "single", "channels": ["email", "sms"] },
      "channels": {
        "email": { "providers": ["ses", "sendgrid"] }
      },
      "tags": ["production"]
    }'
  ```

  ```ruby Ruby highlight={6} theme={null}
  strategy = courier.routing_strategies.replace(
    "rs_01kx4h2jdafq8bk9amzvy6hbv0",
    name: "Email with SMS fallback",
    routing: {method: :single, channels: ["email", "sms"]},
    channels: {
      email: {providers: ["ses", "sendgrid"]}
    },
    tags: ["production"]
  )
  ```

  ```go Go highlight={15} theme={null}
  strategy, err := client.RoutingStrategies.Replace(
  	context.TODO(),
  	"rs_01kx4h2jdafq8bk9amzvy6hbv0",
  	courier.RoutingStrategyReplaceParams{
  		RoutingStrategyReplaceRequest: courier.RoutingStrategyReplaceRequestParam{
  			Name: "Email with SMS fallback",
  			Routing: shared.MessageRoutingParam{
  				Method: shared.MessageRoutingMethodSingle,
  				Channels: []shared.MessageRoutingChannelUnionParam{
  					{OfString: courier.String("email")},
  					{OfString: courier.String("sms")},
  				},
  			},
  			Channels: shared.MessageChannelsParam{
  				"email": shared.ChannelParam{Providers: []string{"ses", "sendgrid"}},
  			},
  			Tags: []string{"production"},
  		},
  	},
  )
  ```

  ```java Java highlight={13} theme={null}
  RoutingStrategyGetResponse strategy = client.routingStrategies().replace(
      RoutingStrategyReplaceParams.builder()
          .id("rs_01kx4h2jdafq8bk9amzvy6hbv0")
          .routingStrategyReplaceRequest(RoutingStrategyReplaceRequest.builder()
              .name("Email with SMS fallback")
              .routing(MessageRouting.builder()
                  .method(MessageRouting.Method.SINGLE)
                  .addChannel("email")
                  .addChannel("sms")
                  .build())
              .channels(MessageChannels.builder()
                  .putAdditionalProperty("email", JsonValue.from(java.util.Map.of(
                      "providers", java.util.List.of("ses", "sendgrid"))))
                  .build())
              .addTag("production")
              .build())
          .build());
  ```

  ```php PHP highlight={6} theme={null}
  $strategy = $client->routingStrategies->replace(
    'rs_01kx4h2jdafq8bk9amzvy6hbv0',
    name: 'Email with SMS fallback',
    routing: ['method' => 'single', 'channels' => ['email', 'sms']],
    channels: [
      'email' => ['providers' => ['ses', 'sendgrid']],
    ],
    tags: ['production'],
  );
  ```

  ```csharp C# highlight={8} theme={null}
  RoutingStrategyReplaceParams parameters = new()
  {
      ID = "rs_01kx4h2jdafq8bk9amzvy6hbv0",
      Name = "Email with SMS fallback",
      Routing = new() { Method = Method.Single, Channels = ["email", "sms"] },
      Channels = new Dictionary<string, Channel>()
      {
          { "email", new() { Providers = ["ses", "sendgrid"] } },
      },
      Tags = ["production"],
  };

  var strategy = await client.RoutingStrategies.Replace(parameters);
  ```

  ```bash CLI highlight={6} theme={null}
  courier routing-strategies replace \
    --api-key "$COURIER_API_KEY" \
    --id rs_01kx4h2jdafq8bk9amzvy6hbv0 \
    --name "Email with SMS fallback" \
    --routing '{"method": "single", "channels": ["email", "sms"]}' \
    --channels '{"email": {"providers": ["ses", "sendgrid"]}}' \
    --tag production
  ```

  ```text MCP theme={null}
  With Courier MCP, update routing strategy rs_01kx4h2jdafq8bk9amzvy6hbv0 so email sends through SES first and SendGrid second, keeping everything else the same.
  ```
</CodeGroup>

### List and archive strategies

<Endpoint method="GET" path="/routing-strategies" name="List Routing Strategies" href="/docs/api-reference/routing-strategies/list-routing-strategies" /> returns each strategy's name and tags. <Endpoint method="GET" path="/routing-strategies/{id}" name="Get Routing Strategy" href="/docs/api-reference/routing-strategies/get-routing-strategy" /> returns its full configuration. <Endpoint method="DELETE" path="/routing-strategies/{id}" name="Archive Routing Strategy" href="/docs/api-reference/routing-strategies/archive-routing-strategy" /> returns `409` while any template still uses the strategy.

## FAQ

<AccordionGroup>
  <Accordion title="Do I need to republish templates after editing a routing strategy?">
    Templates don't need republishing after a strategy edit. A template stores only the strategy's ID, and Courier reads the strategy on every send, so the next message uses the new configuration.
  </Accordion>

  <Accordion title="Can one send use different routing from its template's strategy?">
    A send can pass its own `routing` object, which replaces the strategy's channel list and method for that message. The strategy's provider order and channel conditions still apply. See <Doc href="/docs/send/routing#where-routing-is-set">where routing is set</Doc>.
  </Accordion>
</AccordionGroup>
