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

# API keys and permissions

> Create workspace API keys, limit them to the permissions they need, set an expiry date, and revoke them.

An API key lets an external application, such as your website backend, a script or an integration platform, call the InstantCampaign API on behalf of your workspace. Each key belongs to one workspace and can be limited to specific permissions (scopes).

<Note>
  Managing API keys needs the **API keys** permission. **Owners** and **Administrators** have it, and a [custom role](/guides/sending-and-workspace/team-and-roles#custom-roles) can grant it. Members without it do not see **API Keys** in the settings menu.
</Note>

## Create a key

<Steps>
  <Step title="Open API Keys">
    Go to **Settings → Developers → API Keys** and click **Create New Key**.
  </Step>

  <Step title="Name the key">
    Enter a **Key Name** that says where the key will be used, for example "Checkout service" or "Zapier". The name is only for you; it is how you tell keys apart in the list.
  </Step>

  <Step title="Set an expiry date (optional)">
    Pick an **Expiry Date** if the key should stop working on a given day. Leave it empty for a key that never expires.
  </Step>

  <Step title="Choose permissions">
    Under **Permissions**, tick the scopes this key needs. If you tick nothing, the key has **Full access**.
  </Step>

  <Step title="Create and copy the key">
    Click **Create Key**. The **Your New API Key** dialog shows the full key once. Click **Copy Key** and store it in your secret manager.
  </Step>
</Steps>

<Warning>
  The full key is shown only once. InstantCampaign stores only a hash, so a lost key cannot be recovered. Delete it and create a new one.
</Warning>

The dialog also shows **Your first call**, a ready-to-run request that lists your contact lists:

```bash theme={null}
curl https://instantcampaign.ai/api/v1/lists \
  -H "Authorization: Bearer ic_your_key_here"
```

## Permissions (scopes)

Give each key only the scopes it needs. A key with scopes can call only the endpoints those scopes cover. Any other call returns `403` with `code: "insufficient_scope"`. Most endpoints also name the missing scope in `requiredScope`. Transactional send and validate, public events and the MCP server don't, so check `code`.

| Permission in the app    | Scope                 | Allows                                                                                                                     |
| ------------------------ | --------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| **Contacts — read**      | `contacts:read`       | List and search contacts and lists.                                                                                        |
| **Contacts — write**     | `contacts:write`      | Create/update contacts, subscribe and unsubscribe them.                                                                    |
| **Events — write**       | `events:write`        | Record custom events and goals (including bulk event import and the public events endpoint when called with an `ic_` key). |
| **Transactional — send** | `transactional:write` | Send transactional email, and validate a transactional email without sending it.                                           |
| **Transactional — read** | `transactional:read`  | Read message status and history.                                                                                           |
| **Webhooks — manage**    | `webhooks:manage`     | Register and remove REST hook subscriptions (Zapier, Make), and read the webhook event catalog.                            |
| **AI assistant (MCP)**   | `mcp`                 | Use the [MCP server](/guides/developers/mcp-server) with this key.                                                         |

<Tip>
  A key for a checkout service that only sends receipts needs just **Transactional — send**. If that key leaks, it cannot read or export your contacts.
</Tip>

<Note>
  Keys created before scopes existed have no scopes and keep full access. They show a **Full access** badge in the list.
</Note>

## The key list

Each key shows its **Name** with its scopes (or **Full access**), the **Prefix** (the first characters of the key, so you can match it to your config), when it was **Created**, when it was **Last Used**, and when it **Expires**. An expired key has an **Expired** badge and is refused by the API.

## Revoke a key

Click the delete icon on the key's row, then **Delete Key** in the **Delete API Key** dialog. Any application using the key stops working immediately.

To rotate a key without downtime, create the new key first, deploy it, check that the old key's **Last Used** date stops changing, then delete the old key.

## Changing a key's permissions

You cannot edit a key's scopes in the app. To change them, create a new key with the scopes you want and delete the old one.

## Troubleshooting

| Response                                                                                       | Cause                                                                                               | Fix                                                                   |
| ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `401 Invalid or missing API key` (`Invalid or expired API key` on the transactional endpoints) | The header is missing, is not `Authorization: Bearer ic_…`, or the key was deleted or has expired   | Check the header format and the key's **Expires** date                |
| `403` with `insufficient_scope`                                                                | The key lacks a scope the endpoint needs (named in `requiredScope`, where the endpoint includes it) | Create a key with that scope                                          |
| `403` with the workspace-suspended code                                                        | The workspace is suspended                                                                          | Contact support                                                       |
| `429 Rate limit exceeded`                                                                      | Too many calls from this workspace in one minute                                                    | Slow down and retry; limits are per workspace, so all keys share them |
