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

# Workspaces and environments

> Production and Test environments with separate API keys, templates, and logs, and moving assets.

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

A workspace is the top-level container for everything in Courier.

It holds brands, providers, templates, API keys, user profiles, and analytics. Nothing leaks between workspaces. Environments inside it separate configuration and data, so you build and test without touching live traffic. Most teams run one workspace with its two default environments.

## Environments and API keys

Every workspace starts with two isolated environments, **Production** and **Test**. You can add more, and rename any environment except Production. Each has its own templates, brands, tags, subscription topics, integrations, journeys, API keys, and logs. A change in one never affects another until you migrate it. Switch environments from the dropdown at the top of the dashboard. Switching only changes your view and never affects live notifications.

Courier has no separate "test mode" flag. **Test is an environment**, and a Test key is what puts you in it.

API keys are scoped to one environment and one permission level. The prefix tells you both:

| Key       | Prefix                    | What it does                                                                                                              |
| :-------- | :------------------------ | :------------------------------------------------------------------------------------------------------------------------ |
| Published | `pk_…`                    | Sends live traffic through that environment's own integrations                                                            |
| Draft     | `dk_test_…` / `dk_prod_…` | Renders unpublished template changes against real payloads, so you catch a rendering bug before publishing                |
| Mock      | Enterprise plan           | Simulates the full lifecycle without calling the downstream provider, so you see the flow through Courier at no send cost |

A mock send lands on the <Doc href="/docs/send/statuses">`SIMULATED`</Doc> status. It went through routing and rendering, and no provider was contacted.

### Email in the Test environment

A new workspace's Test environment arrives with a testing email provider already configured, so you can send before connecting anything of your own.

That provider **only delivers to the address you signed up with**. It is a guardrail, not a bug. You can develop against real sends without any chance of reaching a real customer, which also makes a Test key the right one to hand an <Guide href="/docs/guides/send-from-an-ai-agent">AI agent</Guide>.

To reach other addresses from Test, connect your own email provider to that environment, such as a sandbox SendGrid key. Integrations are per environment, so it does not touch Production.

Create separate keys per service so you can rotate or revoke them independently. Keep published Production keys out of client-side code, and use Test keys during development. Find keys in your workspace settings.

## Migrate assets between environments

Promote work with the **Migrate assets** flow, in the ellipsis menu on a template in the templates page. Courier copies the template and its dependencies: brands, tags, subscription topics, test events, and event maps. The template keeps working in the destination. On later migrations, you can overwrite a copied dependency or keep the existing asset. Pick a destination workspace to migrate across workspaces.

**Provider and channel integrations are not copied.** They are per environment, so a migrated template arrives with content and no way to deliver it. Nothing fails at migrate time. You find out on the first send, when the template renders and goes nowhere. Configure each provider in the destination environment, which can hold different credentials from the source, such as a sandbox SendGrid key in Test.

## Logs and billing by environment

Logs and metrics are environment-specific. A Test-key send appears only in the Test dashboard, and a Production-key send only in Production. Billing counts sends across all environments.

### What counts as a billable event

Courier bills on **send attempts, not deliveries**. A billable event happens every time Courier processes a message toward a provider:

* **One unit per recipient, not per channel.** Sending to one user across email, SMS, and push is a single unit.
* **Success does not matter.** If Courier reaches a downstream provider, it bills.
* **Test messages are billable**, as are undeliverable messages and messages blocked by preferences.

| Scenario                                                | Billable units |
| ------------------------------------------------------- | -------------- |
| One email to Sarah Bennett                              | 1              |
| Email, push, and Slack to Sarah Bennett via one profile | 1              |
| One send to a list of 100 users                         | 100            |
| One send addressed to three different emails            | 3              |

<Warning>
  Channels listed as separate entries in a `to` array bill once per entry, so one person sent as three recipients bills three times. Send to a `user_id`, or one object holding every channel, so Courier consolidates them:

  ```javascript theme={null}
  // 1 unit: one profile, many channels
  to: { email: "sarah@acme-corp.com", phone_number: "+15555550100" }

  // 3 units: treated as three recipients
  to: [{ email: "sarah@acme-corp.com" }, { phone_number: "+15555550100" }, { slack: { … } }]
  ```
</Warning>

## Workspace patterns

* **Single workspace (most teams).** Production and Test cover most cases. Use environments, roles, and key scoping for control.
* **Separate workspaces per product.** Keep each product's notification stack isolated.
* **Separate workspaces for data residency.** Use an EU workspace for customers who require EU data residency, and a US workspace for everyone else. See the <Doc href="/docs/workspaces/security#regions-and-data-residency">EU region</Doc>.

Workspace creation is not supported in the EU region (`eu-west-1`), though an existing EU workspace and the tenants inside it work normally. <Doc href="/docs/workspaces/security">EU datacenter</Doc> has the details.

### Workspace, environment, or tenant

Three separate isolation layers. They stack: a workspace contains environments, and within an environment you send to tenants.

Reach for the one whose boundary you actually need. A workspace is a hard wall you rarely cross, an environment is the same product at a different stage of release, and a tenant is one of your customers inside a running environment. Picking a workspace where you needed a tenant means maintaining two of every template.

| Layer           | What it isolates                                                         | Use it when                                                                        | ID                  |
| --------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- | ------------------- |
| **Workspace**   | Everything: brands, providers, templates, API keys, users, analytics     | You need separate billing, data residency, or a hard boundary between products     | `wrk_`              |
| **Environment** | Config and data within a workspace (templates, integrations, keys, logs) | You want test and production (or staging) separated in one account                 | `env_`              |
| **Tenant**      | A recipient segment's brand, default preferences, and templates          | You serve multiple customer organizations (B2B SaaS, white-label) from one account | a string you choose |

For what tenants are used for, see <Doc href="/docs/tenants/overview">Tenants</Doc>.

## Email open and click tracking

Enable open and click tracking for email in <AppLink href="https://app.courier.com/settings/general">Settings → Tracking</AppLink>. The setting is global and applies to all environments.

**Hyperlinks and CTAs must use absolute URLs.** A relative URL gets no tracking link attached and raises nothing, so the email sends and the clicks never appear in your metrics.

You can still turn tracking off for one link. in Design Studio, open the action block or hyperlink settings and toggle tracking off.

## FAQ

<AccordionGroup>
  <Accordion title="Should I use separate workspaces or environments for staging?">
    Use environments. Every workspace has isolated Production and Test environments, and you can add more, such as Staging. Separate workspaces are for billing, data residency, or fully separate products, not for staging one product.
  </Accordion>

  <Accordion title="Why is my new workspace on the Developer plan?">
    A new workspace is not attached to an existing Enterprise contract or plan. If your contract covers multiple workspaces, contact your Courier account team or [support](mailto:support@courier.com) to add the new workspace to your plan.
  </Accordion>

  <Accordion title="Can I move templates between workspaces?">
    Use the Migrate assets flow and pick a destination workspace. Courier copies the template and its dependencies. Providers are per environment and are not copied.
  </Accordion>

  <Accordion title="What happens if I switch from Production to Test?">
    Switching environments only changes your dashboard view. It does not affect live notifications or data in either environment.
  </Accordion>

  <Accordion title="Why does a migrated template render but not deliver?">
    Provider integrations are per environment and are not migrated. Configure the provider in the destination environment so the template has a channel.
  </Accordion>

  <Accordion title="Are test and production data isolated?">
    Each environment is a separate partition. A Test-key send never appears in Production reads, and the reverse. Every send is attributed to the environment of the key that made it.
  </Accordion>
</AccordionGroup>
