> ## 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.

# How to Use the Templates API

> Learn to manage workspace notification templates with the REST API: create Elemental content, publish, inspect what went live, and send to a recipient.

By the end of this walkthrough, you will know how to **create** a workspace template from code, **publish** it so recipients can see it, **confirm** the published body, and **send** a real message that uses your template and variable data. You will also see how **routing** ties a template to your delivery setup, which is required when creating templates through the API.

The example is a small **shipping update** email. For the full workspace route reference, see [Templates API](/platform/content/templates-api). For **Design Studio**-oriented API notes (routing, HTML blocks), see [Manage Templates via API](/platform/content/design-studio/manage-templates-api). For Elemental patterns beyond this walkthrough, see [How to Build Notifications with Elemental](/tutorials/content/how-to-use-elemental).

<Info>
  Authenticate with your workspace [API key](/platform/workspaces/environments-api-keys). `GET /notifications` can return both Classic and Elemental rows; inspect each item if you need a single editor type.
</Info>

## Prerequisites

* Courier [API key](/platform/workspaces/environments-api-keys)
* `curl` for the examples (the bash flow uses `jq` to read ids from JSON responses)
* A **routing strategy id** (`strategy_id` inside `routing` on a template). You can get one by listing your existing strategies (Step 1b below), creating a new one, or copying it from a template in Studio via `GET /notifications/{id}`.

Export:

```bash theme={null}
export COURIER_API_KEY="your_api_key"
export RECIPIENT_EMAIL="you@example.com"   # or use user_id in Step 5
```

Creating a template returns a Courier template id (for example `nt_...`). The steps below store that in `TEMPLATE_ID` after the create call.

## Step 1: List templates

See what is already on the workspace. The response is paginated; use `cursor` from `paging` for the next page if you need it.

```bash cURL icon="terminal" wrap theme={null}
curl -s "https://api.courier.com/notifications" \
  -H "Authorization: Bearer $COURIER_API_KEY" \
  -H "Accept: application/json" | jq .
```

## Step 1b: Get or create a routing strategy

Every template needs a routing strategy that defines which channels to deliver on and in what order. If you already have a `strategy_id` from Studio or an existing template, skip ahead to Step 2.

### List existing strategies

```bash cURL icon="terminal" wrap theme={null}
curl -s "https://api.courier.com/routing-strategies" \
  -H "Authorization: Bearer $COURIER_API_KEY" | jq '.results[] | {id, name}'
```

If you see a strategy you want to use, export its `id`:

```bash theme={null}
export ROUTING_STRATEGY_ID="rs_..."
```

### Create a new strategy

If no strategy exists or you want a fresh one, create it with a name and routing configuration. The `method` field controls delivery: `single` tries channels in order until one succeeds; `all` sends to every channel simultaneously.

<CodeGroup>
  ```bash cURL icon="terminal" wrap theme={null}
  STRATEGY_RESP=$(curl -sS -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"]
      }
    }')

  echo "$STRATEGY_RESP" | jq .
  export ROUTING_STRATEGY_ID=$(echo "$STRATEGY_RESP" | jq -r '.id')
  echo "ROUTING_STRATEGY_ID=$ROUTING_STRATEGY_ID"
  ```

  ```javascript Node.js icon="node-js" theme={null}
  import Courier from "@trycourier/courier";

  const client = new Courier();

  const strategy = await client.routingStrategies.create({
    name: "Email with SMS fallback",
    routing: { method: "single", channels: ["email", "sms"] },
  });

  console.log(`Use ROUTING_STRATEGY_ID=${strategy.id} in the next steps.`);
  ```

  ```python Python icon="python" theme={null}
  from courier import Courier

  client = Courier()

  strategy = client.routing_strategies.create(
      name="Email with SMS fallback",
      routing={"method": "single", "channels": ["email", "sms"]},
  )
  print(f"Use ROUTING_STRATEGY_ID={strategy.id} in the next steps.")
  ```
</CodeGroup>

For the full routing strategies API (update, archive, provider overrides), see [Routing Strategies](/platform/content/template-designer/routing-configuration#managing-routing-strategies-with-the-rest-api).

## Step 2: Create a draft with Elemental content

Create a new notification template with `POST /notifications`. The body is **`published`**, plus a **`notification`** object: metadata (`name`, `tags`, `brand`, `subscription`), **`routing`** with a **`strategy_id`** from your workspace, and **`content`** in the Elemental shape (`version` and `elements`). Courier returns a template id (commonly `nt_...`); use that value as `TEMPLATE_ID` in the following steps.

<Note>
  To **replace** an existing template in full, use `PUT /notifications/{id}` with the same `notification` object shape. See [Replace Notification Template](/api-reference/notification-templates/replace-notification-template). To **create** without overwriting, keep using `POST /notifications` as below. If validation fails, compare your payload to [Create Notification Template](/api-reference/notification-templates/create-notification-template).
</Note>

<CodeGroup>
  ```bash cURL icon="terminal" wrap theme={null}
  RESP=$(curl -sS -X POST "https://api.courier.com/notifications" \
    -H "Authorization: Bearer $COURIER_API_KEY" \
    -H "Content-Type: application/json" \
    -d "$(jq -n \
      --arg sid "$ROUTING_STRATEGY_ID" \
      '{
        "published": false,
        "notification": {
          "name": "Shipping Update API Tutorial",
          "tags": [],
          "brand": null,
          "subscription": null,
          "routing": { "strategy_id": $sid },
          "content": {
            "version": "2022-01-01",
            "elements": [
              { "type": "meta", "title": "Your order {{order_id}} has shipped" },
              {
                "type": "text",
                "content": "Hi {{name}}, your package is on the way. Tracking: {{tracking_url}}."
              },
              {
                "type": "action",
                "content": "Track shipment",
                "href": "{{tracking_url}}"
              }
            ]
          }
        }
      }')")

  echo "$RESP" | jq .
  export TEMPLATE_ID=$(echo "$RESP" | jq -r '.notification.id')
  echo "TEMPLATE_ID=$TEMPLATE_ID"
  ```

  ```javascript Node.js icon="node-js" theme={null}
  const res = await fetch("https://api.courier.com/notifications", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.COURIER_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      published: false,
      notification: {
        name: "Shipping Update API Tutorial",
        tags: [],
        brand: null,
        subscription: null,
        routing: { strategy_id: process.env.ROUTING_STRATEGY_ID },
        content: {
          version: "2022-01-01",
          elements: [
            { type: "meta", title: "Your order {{order_id}} has shipped" },
            {
              type: "text",
              content:
                "Hi {{name}}, your package is on the way. Tracking: {{tracking_url}}.",
            },
            {
              type: "action",
              content: "Track shipment",
              href: "{{tracking_url}}",
            },
          ],
        },
      },
    }),
  });

  const data = await res.json();
  console.log(data);
  console.log(`Use TEMPLATE_ID=${data.notification.id} in the next steps.`);
  ```

  ```python Python icon="python" theme={null}
  import json
  import os
  import urllib.request

  body = {
      "published": False,
      "notification": {
          "name": "Shipping Update API Tutorial",
          "tags": [],
          "brand": None,
          "subscription": None,
          "routing": {"strategy_id": os.environ["ROUTING_STRATEGY_ID"]},
          "content": {
              "version": "2022-01-01",
              "elements": [
                  {"type": "meta", "title": "Your order {{order_id}} has shipped"},
                  {
                      "type": "text",
                      "content": "Hi {{name}}, your package is on the way. Tracking: {{tracking_url}}.",
                  },
                  {
                      "type": "action",
                      "content": "Track shipment",
                      "href": "{{tracking_url}}",
                  },
              ],
          },
      },
  }

  req = urllib.request.Request(
      "https://api.courier.com/notifications",
      data=json.dumps(body).encode(),
      headers={
          "Authorization": f"Bearer {os.environ['COURIER_API_KEY']}",
          "Content-Type": "application/json",
      },
      method="POST",
  )
  with urllib.request.urlopen(req) as resp:
      raw = resp.read().decode()
      print(raw)
      data = json.loads(raw)
      tid = data["notification"]["id"]
      print(f"Use TEMPLATE_ID={tid} in the next steps.")
  ```
</CodeGroup>

## Step 3: Publish

Publish the current draft (or a specific version) with `POST /notifications/{id}/publish`.

```bash cURL icon="terminal" wrap theme={null}
curl -X POST "https://api.courier.com/notifications/$TEMPLATE_ID/publish" \
  -H "Authorization: Bearer $COURIER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Step 4: Read published content

Confirm what is live:

```bash cURL icon="terminal" wrap theme={null}
curl -s "https://api.courier.com/notifications/$TEMPLATE_ID/content" \
  -H "Authorization: Bearer $COURIER_API_KEY" \
  -H "Accept: application/json" | jq .
```

## Step 5: Send a message with your template

Call `POST /send` with your template id and values for the variables used in the draft (`order_id`, `name`, `tracking_url`). Put the recipient in `message.to`; the example below uses `email`. You can send to a Courier profile with `to: { "user_id": "..." }` instead. See [Send a message](/api-reference/send/send-a-message) for all `to` shapes.

<Note>
  The template must have a delivery channel and provider configured in Studio (for example email) or the send can fail routing. Use a [Test](/platform/workspaces/environments-api-keys) API key while iterating.
</Note>

<CodeGroup>
  ```bash cURL icon="terminal" wrap theme={null}
  curl -X POST "https://api.courier.com/send" \
    -H "Authorization: Bearer $COURIER_API_KEY" \
    -H "Content-Type: application/json" \
    -d @- <<EOF
  {
    "message": {
      "template": "${TEMPLATE_ID}",
      "to": { "email": "${RECIPIENT_EMAIL}" },
      "data": {
        "order_id": "ORD-1001",
        "name": "Alex",
        "tracking_url": "https://example.com/track/ORD-1001"
      }
    }
  }
  EOF
  ```

  ```javascript Node.js icon="node-js" theme={null}
  const res = await fetch("https://api.courier.com/send", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.COURIER_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      message: {
        template: process.env.TEMPLATE_ID,
        to: { email: process.env.RECIPIENT_EMAIL },
        data: {
          order_id: "ORD-1001",
          name: "Alex",
          tracking_url: "https://example.com/track/ORD-1001",
        },
      },
    }),
  });

  console.log(await res.json());
  ```

  ```python Python icon="python" theme={null}
  import json
  import os
  import urllib.request

  body = {
      "message": {
          "template": os.environ["TEMPLATE_ID"],
          "to": {"email": os.environ["RECIPIENT_EMAIL"]},
          "data": {
              "order_id": "ORD-1001",
              "name": "Alex",
              "tracking_url": "https://example.com/track/ORD-1001",
          },
      },
  }

  req = urllib.request.Request(
      "https://api.courier.com/send",
      data=json.dumps(body).encode(),
      headers={
          "Authorization": f"Bearer {os.environ['COURIER_API_KEY']}",
          "Content-Type": "application/json",
      },
      method="POST",
  )
  with urllib.request.urlopen(req) as resp:
      print(resp.read().decode())
  ```
</CodeGroup>

Check [message logs](/platform/analytics/message-logs) for delivery status.

## What you built

You listed workspace templates, created a draft with Elemental content and routing, published it, read the published blocks, and sent a message that references the returned template id.

## What's Next

<CardGroup cols={2}>
  <Card title="Templates API reference" icon="book" href="/platform/content/templates-api">
    Endpoints, scope, and links to API Reference
  </Card>

  <Card title="Routing Strategies" icon="route" href="/platform/content/template-designer/routing-configuration">
    Create and manage routing strategies in Studio or via API
  </Card>

  <Card title="How to Build Notifications with Elemental" icon="file-code" href="/tutorials/content/how-to-use-elemental">
    Patterns for `content` and channel overrides
  </Card>

  <Card title="Send API" icon="paper-plane" href="/api-reference/send/send-a-message">
    Request body, profiles, and routing
  </Card>
</CardGroup>
