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

# Tenant Templates API

> Read, write, publish, and version a tenant's templates with the endpoints Courier Create uses.

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

Courier Create reads and writes through these endpoints, so anything the editor does you can script.

```bash theme={null}
curl --request GET \
  --url https://api.courier.com/tenants/acme-corp/templates \
  --header "Authorization: Bearer $COURIER_API_KEY"
```

## Authentication

Two credentials reach these endpoints, and which one you use depends on where the code runs.

Your server uses the API key, as above. The browser uses a JWT scoped to one Tenant, which
is the same token `TemplateProvider` takes. Issue it with

<Endpoint method="POST" path="/auth/issue-token" name="Create a JWT" href="/docs/api-reference/authentication/create-a-jwt" />

and scope it as
<Doc href="/docs/design/embedded-designer/overview#scopes">Overview</Doc> lists.

**Never send the API key from a browser.** It carries the whole workspace, not one Tenant,
so a customer holding it can read and write every other customer's Templates.

## Endpoints

| Operation                 | Method and path                                                                                                                                                                                   |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| List a Tenant's Templates | <Endpoint method="GET" path="/tenants/{tenant_id}/templates" name="List Templates in Tenant" href="/docs/api-reference/tenant-templates/list-templates-in-tenant" />                                   |
| Read one Template         | <Endpoint method="GET" path="/tenants/{tenant_id}/templates/{template_id}" name="Get a Template in Tenant" href="/docs/api-reference/tenant-templates/get-a-template-in-tenant" />                     |
| Create or replace a draft | <Endpoint method="PUT" path="/tenants/{tenant_id}/templates/{template_id}" name="Create or update a Tenant Template" href="/docs/api-reference/tenant-templates/create-or-update-a-tenant-template" /> |
| Delete a Template         | <Endpoint method="DELETE" path="/tenants/{tenant_id}/templates/{template_id}" name="Delete a Tenant Template" href="/docs/api-reference/tenant-templates/delete-a-tenant-template" />                  |
| Publish the draft         | <Endpoint method="POST" path="/tenants/{tenant_id}/templates/{template_id}/publish" name="Publish a Tenant Template" href="/docs/api-reference/tenant-templates/publish-a-tenant-template" />          |
| Read one version          | <Endpoint method="GET" path="/tenants/{tenant_id}/templates/{template_id}/versions/{version}" name="Get a Template version" href="/docs/api-reference/tenant-templates/get-a-template-version" />      |

A `PUT` replaces the draft rather than merging into it, so send the whole document. Reading
first and writing back a modified copy is the safe order.

## Publishing is a separate call

A write leaves a draft. A draft does not send, so a customer who edits and closes the tab
has changed nothing a recipient will see. Publishing is what promotes it.

```bash theme={null}
curl --request POST \
  --url https://api.courier.com/tenants/acme-corp/templates/nt_01kx4h2jdafq8bk9aftxak4b40/publish \
  --header "Authorization: Bearer $COURIER_API_KEY"
```

The editor publishes for the customer through its own button, or through
`useTemplateActions` when you hide it. See
<Doc href="/docs/design/embedded-designer/template-editor#publish-from-your-own-button">Template editor</Doc>.

## Versions

Publishing keeps the previous published document, and

<Endpoint method="GET" path="/tenants/{tenant_id}/templates/{template_id}/versions/{version}" name="Get a Template version" href="/docs/api-reference/tenant-templates/get-a-template-version" />

reads one back by version. Use it to show a customer what changed, or to restore a document
by writing an older version back with a `PUT`.

## Common responses

| Status | Meaning                                                                                                    |
| ------ | ---------------------------------------------------------------------------------------------------------- |
| `200`  | The read or write succeeded.                                                                               |
| `204`  | The delete succeeded and returned no body.                                                                 |
| `400`  | The document failed validation. An Elemental document has to be wrapped in a channel element to be stored. |
| `401`  | The credential is missing, malformed, or expired.                                                          |
| `403`  | The credential is valid but its scope does not cover this Tenant or this operation.                        |
| `404`  | No Template with that id in this Tenant.                                                                   |

`401` and `403` separate cleanly, and the difference is worth reading. A `401` means fix the
token. A `403` means the token works but was scoped too narrowly, which for a JWT usually
means a `brand` scope is missing or the `tenant` in the scope is not the one in the path.

## Tenant Templates are not workspace Templates

These two live in different places and neither endpoint reaches the other.

|               | Tenant Template                      | Workspace Template                                    |
| ------------- | ------------------------------------ | ----------------------------------------------------- |
| Belongs to    | One Tenant                           | The workspace                                         |
| Path          | `/tenants/{tenant_id}/templates/...` | `/notifications/...`                                  |
| Edited by     | Your customer, in Courier Create     | Your team, in Design Studio                           |
| Documented in | This page                            | <Doc href="/docs/design/templates/api">Templates API</Doc> |

A Template your customer writes in Courier Create does not appear in the workspace Template
list, and a workspace Template is not editable through these endpoints. Sending to a Tenant
resolves that Tenant's own Template.

## Verify

List the Tenant's Templates, write a draft with a `PUT`, then read it back. Publish it and
read it again. The published document is what a send to that Tenant now resolves.

## Limits & behavior

* **A `PUT` replaces, it does not merge.** Send the whole document or read first.
* **A write is a draft.** Nothing reaches a recipient until a publish call.
* **A JWT is scoped to one Tenant.** The `tenant` in the scope has to match the `tenant_id` in the path.
* **Content needs a channel wrapper.** An Elemental document stored without one fails validation with a `400`.

## FAQ

<AccordionGroup>
  <Accordion title="Why does my edit not reach recipients?">
    A write leaves a draft. Call the publish endpoint, or publish from the editor, before a
    send resolves the new document.
  </Accordion>

  <Accordion title="What separates a 401 from a 403 here?">
    A `401` means the credential is missing, malformed, or expired. A `403` means the
    credential is valid but too narrowly scoped, usually a missing `brand` scope or a
    `tenant` scope that does not match the path.
  </Accordion>

  <Accordion title="Do these endpoints reach my workspace Templates?">
    Tenant Templates and workspace Templates are separate. Workspace Templates live under
    `/notifications` and are documented in the <Doc href="/docs/design/templates/api">Templates API</Doc>.
  </Accordion>

  <Accordion title="Can a browser call these endpoints directly?">
    A browser can call them with a Tenant-scoped JWT. The API key stays on your server,
    because it carries the whole workspace rather than one Tenant.
  </Accordion>
</AccordionGroup>
