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

# Quickstart

> Send your first notification with one API call. No dashboard setup required.

## For Developers

Send a notification in under two minutes. All you need is an API key.

<Steps>
  <Step title="Get your API key">
    Sign up or log in to [Courier](https://app.courier.com), then copy your API key from [Settings > API Keys](https://app.courier.com/settings/api-keys).
  </Step>

  <Step title="Send a message">
    One API call sends an email. Use cURL, the [CLI](/tools/cli), or any of our [server SDKs](/sdk-libraries/sdks-overview). Replace `YOUR_API_KEY` with your key and `you@example.com` with your email address.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.courier.com/send \
        -H "Authorization: Bearer YOUR_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "message": {
            "to": { "email": "you@example.com" },
            "content": {
              "title": "Hello from Courier!",
              "body": "You just sent your first notification. Nice work, {{name}}."
            },
            "data": { "name": "Developer" },
            "routing": {
              "method": "single",
              "channels": ["email"]
            }
          }
        }'
      ```

      ```bash CLI theme={null}
      # npm install -g @trycourier/cli
      export COURIER_API_KEY=YOUR_API_KEY

      courier send message \
        --message.to.email "you@example.com" \
        --message.content.title "Hello from Courier!" \
        --message.content.body "You just sent your first notification. Nice work, {{name}}." \
        --message.data '{"name": "Developer"}' \
        --message.routing.method "single" \
        --message.routing.channels '["email"]'
      ```

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

      const client = new Courier({ apiKey: "YOUR_API_KEY" });

      const response = await client.send.message({
        message: {
          to: { email: "you@example.com" },
          content: {
            title: "Hello from Courier!",
            body: "You just sent your first notification. Nice work, {{name}}.",
          },
          data: { name: "Developer" },
          routing: { method: "single", channels: ["email"] },
        },
      });

      console.log("Sent! Request ID:", response.requestId);
      ```

      ```python Python theme={null}
      # pip install trycourier
      from courier import Courier

      client = Courier(api_key="YOUR_API_KEY")

      response = client.send.message(
        message={
          "to": {"email": "you@example.com"},
          "content": {
            "title": "Hello from Courier!",
            "body": "You just sent your first notification. Nice work, {{name}}.",
          },
          "data": {"name": "Developer"},
          "routing": {"method": "single", "channels": ["email"]},
        }
      )

      print("Sent! Request ID:", response.request_id)
      ```

      ```ruby Ruby theme={null}
      # gem install trycourier
      require "trycourier"

      client = Courier::Client.new "YOUR_API_KEY"

      res = client.send({
        message: {
          to: { email: "you@example.com" },
          content: {
            title: "Hello from Courier!",
            body: "You just sent your first notification. Nice work, {{name}}.",
          },
          data: { name: "Developer" },
          routing: { method: "single", channels: ["email"] },
        },
      })
      ```

      ```go Go theme={null}
      // go get github.com/trycourier/courier-go/v2
      import (
        "context"
        "fmt"
        "github.com/trycourier/courier-go/v2"
      )

      client := courier.CreateClient("YOUR_API_KEY", nil)

      requestID, err := client.SendMessage(
        context.Background(),
        courier.SendMessageRequestBody{
          Message: map[string]interface{}{
            "to":      map[string]string{"email": "you@example.com"},
            "content": map[string]string{
              "title": "Hello from Courier!",
              "body":  "You just sent your first notification. Nice work, {{name}}.",
            },
            "data":    map[string]string{"name": "Developer"},
            "routing": map[string]interface{}{
              "method":   "single",
              "channels": []string{"email"},
            },
          },
        },
      )

      fmt.Println("Sent! Request ID:", requestID)
      ```
    </CodeGroup>

    The response includes a `requestId` you can use to track delivery:

    ```json theme={null}
    { "requestId": "1-67890abc-d1e2f3a4b5c6" }
    ```
  </Step>

  <Step title="Verify delivery">
    Open [Message Logs](https://app.courier.com/logs) in your dashboard. You should see your message with a timeline showing each stage: accepted, routed, rendered, sent, and delivered.

    If the message doesn't appear, double-check that your API key is correct and that you're viewing the right environment (Test vs Production).
  </Step>
</Steps>

That's it. One API call, one notification delivered.

***

## For AI Agents

If you're using an AI coding agent (Claude Code, Cursor, Codex, etc.), set your API key and install your tooling, then send your first message with the CLI or cURL.

<Steps>
  <Step title="Set your API key">
    ```bash theme={null}
    export COURIER_API_KEY="your-api-key"
    ```
  </Step>

  <Step title="Install your tooling">
    <Tabs>
      <Tab title="CLI">
        ```bash theme={null}
        npm install -g @trycourier/cli
        ```
      </Tab>

      <Tab title="Cursor MCP">
        Add this to your `mcp.json`:

        ```json theme={null}
        {
          "mcpServers": {
            "courier": {
              "url": "https://mcp.courier.com",
              "headers": {
                "api_key": "XXXX"
              }
            }
          }
        }
        ```
      </Tab>

      <Tab title="Claude Code MCP">
        ```bash theme={null}
        claude mcp add --transport http courier https://mcp.courier.com --header api_key:XXXX
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Send your first message">
    <CodeGroup>
      ```bash CLI theme={null}
      courier send message \
        --message.to.email "you@example.com" \
        --message.content.title "Hello" \
        --message.content.body "Sent from an agent"
      ```

      ```bash cURL theme={null}
      curl -X POST https://api.courier.com/send \
        -H "Authorization: Bearer $COURIER_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "message": {
            "to": { "email": "you@example.com" },
            "content": { "title": "Hello", "body": "Sent from an agent" },
            "routing": { "method": "single", "channels": ["email"] }
          }
        }'
      ```
    </CodeGroup>
  </Step>

  <Step title="Continue with full agent patterns">
    Use the [Agent Quickstart](/tools/agent-quickstart) for profile storage, idempotency, inbox delivery, JWT auth, and common anti-patterns.
  </Step>
</Steps>

<Note>
  Courier docs are available as machine-readable indexes for AI agents:
  [llms.txt](https://www.courier.com/docs/llms.txt) and
  [llms-full.txt](https://www.courier.com/docs/llms-full.txt).
</Note>

### Copy for Cursor / Claude

Paste one of these blocks directly into your coding agent. Each block includes setup, key API patterns, error handling, and guardrails.

<CodeGroup>
  ```javascript Node.js theme={null}
  /**
   * Courier agent quick reference (Node.js)
   *
   * Setup:
   *   npm install @trycourier/courier
   *   export COURIER_API_KEY="your-api-key"
   *
   * Core endpoints:
   *   POST /send
   *   POST /profiles/{user_id} (merge profile)
   *   PUT  /profiles/{user_id} (replace entire profile)
   *   POST /auth/issue-token
   *
   * Error/status patterns:
   *   401 Unauthorized -> invalid/missing API key
   *   UNDELIVERABLE -> invalid recipient or blocked domain
   *   UNROUTABLE -> no provider or missing profile channel data
   *   UNMAPPED -> missing template id
   *
   * Guardrails:
   *   - Use POST /profiles/{user_id} for updates; PUT replaces and can delete fields.
   *   - Use method:"single" for transactional sends (OTP/billing), method:"all" for fanout.
   *   - Pass Idempotency-Key via headers; do not rely on idempotencyKey option.
   */
  import Courier from "@trycourier/courier";

  const client = new Courier(); // Reads COURIER_API_KEY

  // 1) Merge a user profile
  await client.profiles.create("user-123", {
    profile: {
      email: "alice@example.com",
      name: "Alice",
      phone_number: "+14155550123",
    },
  });

  // 2) Send transactional email with idempotency
  const transactional = await client.send.message(
    {
      message: {
        to: { user_id: "user-123" },
        content: {
          title: "Your order shipped",
          body: "Order #{{orderId}} is on its way.",
        },
        data: { orderId: "ORD-456" },
        routing: { method: "single", channels: ["email", "sms"] },
      },
    },
    { headers: { "Idempotency-Key": "order-ORD-456-user-123" } }
  );

  // 3) Send informational fanout to email + inbox
  await client.send.message({
    message: {
      to: { user_id: "user-123" },
      content: {
        title: "New activity",
        body: "Your weekly summary is ready.",
      },
      routing: { method: "all", channels: ["email", "inbox"] },
    },
  });

  // 4) Issue JWT for Inbox client auth
  const { token } = await client.auth.issueToken({
    scope: "user_id:user-123 inbox:read:messages inbox:write:events",
    expires_in: "1 day",
  });

  console.log({ requestId: transactional.requestId, inboxJwt: token });
  ```

  ```python Python theme={null}
  """
  Courier agent quick reference (Python)

  Setup:
    pip install trycourier
    export COURIER_API_KEY="your-api-key"

  Core endpoints:
    POST /send
    POST /profiles/{user_id} (merge profile)
    PUT  /profiles/{user_id} (replace entire profile)
    POST /auth/issue-token

  Error/status patterns:
    401 Unauthorized -> invalid/missing API key
    UNDELIVERABLE -> invalid recipient or blocked domain
    UNROUTABLE -> no provider or missing profile channel data
    UNMAPPED -> missing template id

  Guardrails:
    - Use POST /profiles/{user_id} for updates; PUT replaces and can delete fields.
    - Use method:"single" for transactional sends (OTP/billing), method:"all" for fanout.
    - Include Idempotency-Key on transactional sends to avoid duplicates on retries.
  """
  from courier import Courier

  client = Courier()  # Reads COURIER_API_KEY

  # 1) Merge a user profile
  client.profiles.create(
      "user-123",
      profile={
          "email": "alice@example.com",
          "name": "Alice",
          "phone_number": "+14155550123",
      },
  )

  # 2) Send transactional email with idempotency
  transactional = client.send.message(
      message={
          "to": {"user_id": "user-123"},
          "content": {
              "title": "Your order shipped",
              "body": "Order #{{orderId}} is on its way.",
          },
          "data": {"orderId": "ORD-456"},
          "routing": {"method": "single", "channels": ["email", "sms"]},
      },
      extra_headers={"Idempotency-Key": "order-ORD-456-user-123"},
  )

  # 3) Send informational fanout to email + inbox
  client.send.message(
      message={
          "to": {"user_id": "user-123"},
          "content": {
              "title": "New activity",
              "body": "Your weekly summary is ready.",
          },
          "routing": {"method": "all", "channels": ["email", "inbox"]},
      }
  )

  # 4) Issue JWT for Inbox client auth
  auth_response = client.auth.issue_token(
      scope="user_id:user-123 inbox:read:messages inbox:write:events",
      expires_in="1 day",
  )

  print({"request_id": transactional.request_id, "inbox_jwt": auth_response.token})
  ```
</CodeGroup>

***

## FAQ

<AccordionGroup>
  <Accordion title="Do I need to configure a provider first?">
    Not necessarily. Courier includes a built-in email provider, so email works out of the box in Test mode. For production email, SMS, push, or chat you'll need to connect a provider in [Integrations](https://app.courier.com/integrations). The [Inbox](/platform/inbox/inbox-overview) and Toast channels also work without any external provider.
  </Accordion>

  <Accordion title="Can I design templates visually instead of writing content in code?">
    Yes. Courier's [Design Studio](/platform/content/design-studio/design-studio-overview) lets you build notifications visually with drag-and-drop blocks, reusable routing configurations, and version history. Reference templates by ID in your send call. You can also [manage templates programmatically](/platform/content/design-studio/manage-templates-api) via the Templates API.
  </Accordion>

  <Accordion title="How do I send to SMS, push, or multiple channels at once?">
    Add a provider for the channel you want in [Integrations](https://app.courier.com/integrations), then update the `routing` object in your send call. To send to multiple channels, set `method` to `"all"` and list the channels you want. See [How Sending Works](/platform/sending/sending-overview) for details on routing and fallback behavior.
  </Accordion>

  <Accordion title="Where do I find SDKs for other languages?">
    We have official SDKs for Node.js, Python, Ruby, Go, Java, PHP, and C#, plus mobile SDKs for iOS, Android, React Native, and Flutter. See the full list on the [SDKs overview](/sdk-libraries/sdks-overview). You can also call the [REST API](/api-reference/send/send-a-message) directly from any language.
  </Accordion>
</AccordionGroup>

## What's Next

<CardGroup cols={2}>
  <Card title="How Sending Works" href="/platform/sending/sending-overview" icon="paper-plane">
    Understand routing, channels, and the delivery pipeline
  </Card>

  <Card title="Design a Template" href="/platform/content/design-studio/design-studio-overview" icon="palette">
    Build a reusable notification in Design Studio
  </Card>

  <Card title="Add an In-App Inbox" href="/tutorials/inbox/how-to-implement-inbox" icon="inbox">
    Embed a real-time notification feed in your app; no provider needed
  </Card>

  <Card title="Build with AI" href="/tools/ai-onboarding" icon="microchip-ai">
    Connect your AI coding agent to Courier via MCP or CLI
  </Card>
</CardGroup>
