> ## 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 multiple environments and each environment has its own API keys; start with Test.
> 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.

# Send notifications with Express

> Send email, SMS, push, and in-app notifications from an Express route.

The [Node.js quickstart](/docs/quickstarts/node) covers the calls themselves: create a user, send a notification, route it across channels, start a journey. This page is the Express wiring around them. Where the Courier client lives in an Express app, how a route sends, and how to keep a failed notification from failing the request it was attached to. Everything here is the same SDK, so the calls on the Node.js page drop straight into any handler.

**What you need**

* The [Node.js quickstart](/docs/quickstarts/node) done, or at least a Courier API key in `COURIER_API_KEY` and a user in Courier.
* An Express app on Node 20 or newer, with `express` and `@trycourier/courier` installed.

## 1. Create the client once

Create one `Courier` instance at startup and import it wherever you send. It is a thin HTTP client with no connection state, so a module-level instance is the right shape and a per-request one is wasted work. `new Courier()` reads `COURIER_API_KEY` from the environment, which keeps the key out of your code and out of any bundle.

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

export const courier = new Courier();
```

## 2. Send from a route

A route usually knows two things worth passing on: who the user is, and the data for this event. Name the template, name the user, and let Courier work out the channel from the template's routing and the user's preferences. The idempotency key means a client retry returns the original response instead of sending twice.

```javascript theme={null}
// routes/signup.js
import { Router } from "express";
import { courier } from "../courier.js";

export const router = Router();

router.post("/signup", async (req, res) => {
  const { userId, email, plan } = req.body;

  await courier.profiles.create(userId, { profile: { email } });

  const { requestId } = await courier.send.message(
    {
      message: {
        template: "welcome",
        to: { user_id: userId },
        data: { plan },
      },
    },
    { idempotencyKey: `welcome-${userId}` }
  );

  res.status(202).json({ userId, requestId });
});
```

## 3. Do not fail the request on a failed send

A signup that worked should not return a 500 because a welcome notification did not go out. Wrap the send, log what failed, and answer the client either way. For anything slower or noisier than one send, hand the work to a job queue and have the route only enqueue it.

```javascript theme={null}
try {
  const { requestId } = await courier.send.message({
    message: { template: "welcome", to: { user_id: userId } },
  });
  req.log?.info({ requestId }, "welcome notification queued");
} catch (error) {
  req.log?.error({ err: error }, "welcome notification failed");
}

res.status(201).json({ userId });
```

The `requestId` is worth logging. Paste it into [Message Logs](https://app.courier.com/logs) to see the channel Courier chose, the provider it used, and the delivery status.

## Next steps

* [Working example](https://github.com/trycourier/courier-samples/tree/main/server/node): a runnable Node.js server with these calls.
* [Node.js quickstart](/docs/quickstarts/node): users, channel routing, journeys, delivery status.
* [Add an in-app inbox](/docs/platform/inbox/inbox-overview): your Express app mints the token, the browser renders the feed.
* [Node.js SDK reference](/docs/sdk-libraries/node).
