> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mailchannels.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Learn how to create and manage API keys for your account and sub-accounts.

## What is an API key?

An API key is a unique token that authenticates your requests to the MailChannels Email API. It serves two purposes: proving
who you are, and determining what you are allowed to do.

## Authenticating a request

Every request to the Email API must include your API key. The examples below send a minimal email and demonstrate how the
key is set.

<CodeGroup>
  ```bash cURL theme={null}
  #!/usr/bin/env bash
  set -u
  : "${MAILCHANNELS_API_KEY:?Set MAILCHANNELS_API_KEY before running}"
  : "${FROM_EMAIL:?Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)}"
  : "${TO_EMAIL:?Set TO_EMAIL}"

  curl -X POST https://api.mailchannels.net/tx/v1/send \
    -H "Content-Type: application/json" \
    -H "X-Api-Key: $MAILCHANNELS_API_KEY" \
    -d @- <<JSON
  {
    "personalizations": [
      { "to": [{ "email": "$TO_EMAIL", "name": "Recipient" }] }
    ],
    "from": {
      "email": "$FROM_EMAIL",
      "name": "Your Name"
    },
    "subject": "Hello from MailChannels",
    "content": [
      {
        "type": "text/plain",
        "value": "Hello! This is a plain-text email."
      }
    ]
  }
  JSON
  ```

  ```javascript Node.js theme={null}
  import { MailChannels } from "mailchannels-sdk";

  const { MAILCHANNELS_API_KEY, FROM_EMAIL, TO_EMAIL } = process.env;
  if (!MAILCHANNELS_API_KEY) throw new Error("Set MAILCHANNELS_API_KEY before running");
  if (!FROM_EMAIL) throw new Error("Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)");
  if (!TO_EMAIL) throw new Error("Set TO_EMAIL");

  // Pass the API key to the MailChannels constructor. The SDK attaches it as the
  // X-Api-Key header on every request.
  const mailchannels = new MailChannels(MAILCHANNELS_API_KEY);

  const { data, error } = await mailchannels.emails.send({
    from: { email: FROM_EMAIL, name: "Your Name" },
    to: { email: TO_EMAIL, name: "Recipient" },
    subject: "Hello from MailChannels",
    text: "Hello! This is a plain-text email.",
  });

  if (error) {
    console.error("Send failed:", error);
    process.exit(1);
  }
  console.log(data);
  ```

  ```python Python theme={null}
  import os
  import sys

  import mailchannels

  # The SDK reads MAILCHANNELS_API_KEY from the environment automatically. To
  # authenticate with a different key, set mailchannels.api_key before calling
  # any SDK method:
  #
  #     mailchannels.api_key = "your-key-here"
  if not os.environ.get("MAILCHANNELS_API_KEY"):
      sys.exit("Set MAILCHANNELS_API_KEY before running")

  from_email = os.environ.get("FROM_EMAIL")
  to_email = os.environ.get("TO_EMAIL")
  if not from_email:
      sys.exit("Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)")
  if not to_email:
      sys.exit("Set TO_EMAIL")

  response = mailchannels.Emails.send(
      {
          "from": {"email": from_email, "name": "Your Name"},
          "to": [{"email": to_email, "name": "Recipient"}],
          "subject": "Hello from MailChannels",
          "text": "Hello! This is a plain-text email.",
      }
  )

  print(response)
  ```

  ```php PHP theme={null}
  <?php

  require_once __DIR__ . '/vendor/autoload.php';

  use MailChannels\Client;

  $api_key    = getenv('MAILCHANNELS_API_KEY') or exit("Error: MAILCHANNELS_API_KEY is not set\n");
  $from_email = getenv('FROM_EMAIL') or exit("Error: FROM_EMAIL is not set\n");
  $to_email   = getenv('TO_EMAIL') or exit("Error: TO_EMAIL is not set\n");

  // Pass the API key to the Client constructor. The SDK attaches it as the
  // X-Api-Key header on every request.
  $client = new Client(apiKey: $api_key);

  $response = $client->emails->send([
      'from'    => ['email' => $from_email, 'name' => 'Your Name'],
      'to'      => ['email' => $to_email, 'name' => 'Recipient'],
      'subject' => 'Hello from MailChannels',
      'text'    => 'Hello! This is a plain-text email.',
  ]);

  print_r($response->toArray());
  ```
</CodeGroup>

<Warning>
  Similar to a password, an API key grants access to your account. Store it securely and never commit it to source control
  or expose it in client-side code.
</Warning>

## API key management

### Creating an API key

Visit the [API Keys page](https://dash.mailchannels.com/account/api-keys) in the Console to create a key for
your account.

1. Click **Create API Key**.
2. Add a descriptive label.
3. Set the scope to `Sending Email`.
4. Click **Create API Key** and copy the key. You won't be able to see it again.

<Warning>
  The full key is shown exactly once at the moment it is created. The redacted version is available via the Console and API,
  but never the original key. There is no way to recover a key.
</Warning>

### Scope

Scope determines what an API key is allowed to do. Scope is assigned when the key is created in the Console and
cannot be changed afterwards. The API currently supports the following scopes: `Sending Email` (api) and `Managing Inbound Filtering` (inbound).
If you create a key with `Sending Email`, you can access every endpoint specified in the
[Email API reference](/email-api/api-reference-introduction).

If you create a key with `Managing Inbound Filtering`, you have access to MailChannels Inbound Filtering.
Inbound filtering blocks unwanted mail before it reaches your infrastructure. If you would like to learn more, view the
[Inbound Filtering documentation](https://www.mailchannels.com/inbound/).

### Deleting an API key

Delete an API key in the Console by clicking the **Revoke** button next to it. In the dialog that appears, click **Revoke API Key**
to confirm. All subsequent requests that use the key will fail.

## Sub-account key management

API keys for sub-accounts can be managed via the API. The parent account can create, list, and delete keys for each sub-account
it owns.

### Creating a key

<CodeGroup>
  ```bash cURL theme={null}
  #!/usr/bin/env bash
  set -u
  : "${PARENT_API_KEY:?Set PARENT_API_KEY before running}"
  : "${SUB_ACCOUNT_HANDLE:?Set SUB_ACCOUNT_HANDLE (the sub-account to create a key for)}"

  curl -X POST \
    "https://api.mailchannels.net/tx/v1/sub-account/$SUB_ACCOUNT_HANDLE/api-key" \
    -H "X-Api-Key: $PARENT_API_KEY"
  ```

  ```javascript Node.js theme={null}
  import { MailChannels } from "mailchannels-sdk";

  const { PARENT_API_KEY, SUB_ACCOUNT_HANDLE } = process.env;
  if (!PARENT_API_KEY) throw new Error("Set PARENT_API_KEY (a parent-account API key) before running");
  if (!SUB_ACCOUNT_HANDLE) throw new Error("Set SUB_ACCOUNT_HANDLE (the sub-account to create a key for)");

  const mailchannels = new MailChannels(PARENT_API_KEY);

  const { data, error } = await mailchannels.subAccounts.createApiKey(SUB_ACCOUNT_HANDLE);

  if (error) {
    console.error("Create sub-account API key failed:", error);
    process.exit(1);
  }
  // data.key is shown only once. Store it securely.
  console.log(data);
  ```

  ```python Python theme={null}
  import os
  import sys

  import mailchannels

  parent_api_key = os.environ.get("PARENT_API_KEY")
  handle = os.environ.get("SUB_ACCOUNT_HANDLE")
  if not parent_api_key:
      sys.exit("Set PARENT_API_KEY (a parent-account API key) before running")
  if not handle:
      sys.exit("Set SUB_ACCOUNT_HANDLE (the sub-account to create a key for)")

  mailchannels.api_key = parent_api_key

  response = mailchannels.SubAccounts.ApiKeys.create(handle)

  print(response)
  ```

  ```php PHP theme={null}
  <?php

  require_once __DIR__ . '/vendor/autoload.php';

  use MailChannels\Client;

  $parent_api_key      = getenv('PARENT_API_KEY') or exit("Error: PARENT_API_KEY is not set\n");
  $sub_account_handle  = getenv('SUB_ACCOUNT_HANDLE') or exit("Error: SUB_ACCOUNT_HANDLE is not set\n");

  $client = new Client(apiKey: $parent_api_key);

  $response = $client->subAccounts->apiKeys->create($sub_account_handle);

  print_r($response->toArray());
  ```
</CodeGroup>

### Listing keys

<CodeGroup>
  ```bash cURL theme={null}
  #!/usr/bin/env bash
  set -u
  : "${PARENT_API_KEY:?Set PARENT_API_KEY before running}"
  : "${SUB_ACCOUNT_HANDLE:?Set SUB_ACCOUNT_HANDLE (the sub-account whose keys you want to list)}"

  curl "https://api.mailchannels.net/tx/v1/sub-account/$SUB_ACCOUNT_HANDLE/api-key" \
    -H "X-Api-Key: $PARENT_API_KEY"
  ```

  ```javascript Node.js theme={null}
  import { MailChannels } from "mailchannels-sdk";

  const { PARENT_API_KEY, SUB_ACCOUNT_HANDLE } = process.env;
  if (!PARENT_API_KEY) throw new Error("Set PARENT_API_KEY (a parent-account API key) before running");
  if (!SUB_ACCOUNT_HANDLE) throw new Error("Set SUB_ACCOUNT_HANDLE (the sub-account whose keys you want to list)");

  const mailchannels = new MailChannels(PARENT_API_KEY);

  const { data, error } = await mailchannels.subAccounts.listApiKeys(SUB_ACCOUNT_HANDLE);

  if (error) {
    console.error("List sub-account API keys failed:", error);
    process.exit(1);
  }
  console.log(data);
  ```

  ```python Python theme={null}
  import os
  import sys

  import mailchannels

  parent_api_key = os.environ.get("PARENT_API_KEY")
  handle = os.environ.get("SUB_ACCOUNT_HANDLE")
  if not parent_api_key:
      sys.exit("Set PARENT_API_KEY (a parent-account API key) before running")
  if not handle:
      sys.exit("Set SUB_ACCOUNT_HANDLE (the sub-account whose keys you want to list)")

  mailchannels.api_key = parent_api_key

  response = mailchannels.SubAccounts.ApiKeys.list(handle)

  print(response)
  ```

  ```php PHP theme={null}
  <?php

  require_once __DIR__ . '/vendor/autoload.php';

  use MailChannels\Client;

  $parent_api_key     = getenv('PARENT_API_KEY') or exit("Error: PARENT_API_KEY is not set\n");
  $sub_account_handle = getenv('SUB_ACCOUNT_HANDLE') or exit("Error: SUB_ACCOUNT_HANDLE is not set\n");

  $client = new Client(apiKey: $parent_api_key);

  $response = $client->subAccounts->apiKeys->list($sub_account_handle);

  print_r($response->toArray());
  ```
</CodeGroup>

### Deleting a key

<CodeGroup>
  ```bash cURL theme={null}
  #!/usr/bin/env bash
  set -u
  : "${PARENT_API_KEY:?Set PARENT_API_KEY before running}"
  : "${SUB_ACCOUNT_HANDLE:?Set SUB_ACCOUNT_HANDLE}"
  : "${API_KEY_ID:?Set API_KEY_ID (the id of the key to delete)}"

  curl -X DELETE \
    "https://api.mailchannels.net/tx/v1/sub-account/$SUB_ACCOUNT_HANDLE/api-key/$API_KEY_ID" \
    -H "X-Api-Key: $PARENT_API_KEY"
  ```

  ```javascript Node.js theme={null}
  import { MailChannels } from "mailchannels-sdk";

  const { PARENT_API_KEY, SUB_ACCOUNT_HANDLE, API_KEY_ID } = process.env;
  if (!PARENT_API_KEY) throw new Error("Set PARENT_API_KEY (a parent-account API key) before running");
  if (!SUB_ACCOUNT_HANDLE) throw new Error("Set SUB_ACCOUNT_HANDLE");
  if (!API_KEY_ID) throw new Error("Set API_KEY_ID (the ID of the key to delete)");

  const mailchannels = new MailChannels(PARENT_API_KEY);

  const { success, error } = await mailchannels.subAccounts.deleteApiKey(
    SUB_ACCOUNT_HANDLE,
    Number(API_KEY_ID),
  );

  if (!success) {
    console.error("Delete sub-account API key failed:", error);
    process.exit(1);
  }
  console.log(`Deleted API key ${API_KEY_ID} for sub-account ${SUB_ACCOUNT_HANDLE}`);
  ```

  ```python Python theme={null}
  import os
  import sys

  import mailchannels

  parent_api_key = os.environ.get("PARENT_API_KEY")
  handle = os.environ.get("SUB_ACCOUNT_HANDLE")
  key_id = os.environ.get("API_KEY_ID")
  if not parent_api_key:
      sys.exit("Set PARENT_API_KEY (a parent-account API key) before running")
  if not handle:
      sys.exit("Set SUB_ACCOUNT_HANDLE")
  if not key_id:
      sys.exit("Set API_KEY_ID (the id of the key to delete)")

  mailchannels.api_key = parent_api_key

  response = mailchannels.SubAccounts.ApiKeys.delete(handle, key_id)

  print(response)
  ```

  ```php PHP theme={null}
  <?php

  require_once __DIR__ . '/vendor/autoload.php';

  use MailChannels\Client;

  $parent_api_key     = getenv('PARENT_API_KEY') or exit("Error: PARENT_API_KEY is not set\n");
  $sub_account_handle = getenv('SUB_ACCOUNT_HANDLE') or exit("Error: SUB_ACCOUNT_HANDLE is not set\n");
  $api_key_id         = getenv('API_KEY_ID') or exit("Error: API_KEY_ID is not set\n");

  $client = new Client(apiKey: $parent_api_key);

  $response = $client->subAccounts->apiKeys->delete($sub_account_handle, $api_key_id);

  print_r($response->toArray());
  ```
</CodeGroup>

## Key limits

Each account can have 100 API keys. Each sub-account can have 100 API keys. Sub-account keys do not count towards the
parent account's limit.

Attempting to create another key past that limit returns an error. Delete an unused key before creating a new one.

## Best practices

### Storage

Use a secrets manager or environment variable to store your API key, rather than hard-coding it in source code. This
reduces the risk of accidental exposure.

### Rotation

Regularly rotate your API keys to minimize the impact of a potential compromise. To rotate a key, create a new one,
update your applications to use it, and then revoke the old key.

### One key per application

Use a unique API key for each application or service that integrates with the Email API. Then, if a key is compromised,
you can revoke it without affecting other applications.
