# API keys and access (/api-keys)

How sign-in, API keys, permissions and connection limits decide what can be read.

Everything in EcomSquad belongs to an **organization**: your team's boundary for
membership and data. Platform also calls it a workspace. Access is always decided
by EcomSquad from your sign-in or key; you never send an organization ID.

## Ways in [#ways-in]

| Credential | Who uses it                  | Where                                                                                     |
| ---------- | ---------------------------- | ----------------------------------------------------------------------------------------- |
| Sign-in    | People                       | Platform, OneInbox, and assistants that support [MCP sign-in](/mcp#connect-with-sign-in). |
| API key    | Servers and some MCP clients | The [Context API](/reference) and [MCP](/mcp#connect-with-an-api-key).                    |

**Sign-in** uses a link sent to the email address your administrator provisioned.
Requesting a link does not create access; you must already be a member. An
assistant signed in as you uses your permissions, narrowed by what you approve.

An **API key** belongs to the organization and works until it expires or is
revoked. Keep it out of browser code, repositories, and chat messages.

## Create a key [#create-a-key]

You need permission to create API keys and the names of the mailbox and store
your integration should access.

### Name the integration [#name-the-integration]

In Platform, open **API keys → Create key**. Enter a recognizable **Name**, such
as “Support reporting”. Use a separate key for each integration.

### Choose permissions [#choose-permissions]

Choose **Custom**, keep **Support context → Read** checked, and clear the other
permissions you do not need. Custom starts from the current selection. You cannot
grant permissions your own membership does not have. The key keeps following your
role: if your role is lowered, it loses what the new role does not have, and if
you leave the organization, it stops working.

### Set expiry and connection access [#set-expiry-and-connection-access]

Choose **30 days**, **90 days**, or **1 year** under **Expires**.

Under **Account access**, choose **Only selected accounts**. Select the relevant
mailbox and Shopify store to read a ticket with its orders.

<Callout type="warn" title="Check the connection selection">
  **All accounts** includes future connections. If **Account access** is absent, the key will use
  all-connection access. Resolve the missing or unavailable connection list before creating a key
  that needs limits.
</Callout>

### Save the secret [#save-the-secret]

Choose **Create key**. Copy the secret into your integration's secret manager or
private environment configuration before choosing **Done**. The secret is shown
once; a lost secret needs a replacement key.

Send the key in the `x-api-key` header, not an OAuth bearer-token field, then
follow the [Quickstart](/quickstart) to check that it reads the intended
connections.

## Permissions [#permissions]

| Permission                                    | What it allows                                                                                                                                                                                    |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Support context → Read (`context:read`)       | Read stored tickets, messages, customers, and orders.                                                                                                                                             |
| Support context → Refresh (`context:refresh`) | Ask the store for current order information and store the results. Always includes Read.                                                                                                          |
| Inbox → Read changes (`inbox:read`)           | Poll the [Needs reply feed](/reference/needs-reply-feed). Only owners and admins can add it; no preset includes it.                                                                               |
| Inbox → Refresh mailboxes (`inbox:refresh`)   | Ask for a [mail check](/reference/mailbox-refresh) of the mailboxes the key reaches, and read its status. Always includes Read changes. Only owners and admins can add it; no preset includes it. |

When creating a key, **Read only** includes more than support context and
**Full access** includes further actions. Choose **Custom** to select only what
your integration needs.

Some keys created before the Context API existed lack `context:read`, even if they
came from the read-only preset. Replace them.

## Connection limits [#connection-limits]

Connection limits decide which sources a key can read.

* **Only selected accounts** limits the key to the mailboxes and stores you pick.
* **All accounts** includes every connection, including ones added later.

A key that can read a mailbox but not its store still reads the ticket, without
the orders in that store, and a refresh reports `not_permitted`. Scope a key to
both the mailbox and the store to read a ticket with its orders.

## Replace or revoke a key [#replace-or-revoke-a-key]

For routine replacement:

1. Create a new key with the required permissions and connections.
2. Update the integration and confirm that a read succeeds.
3. Choose **Revoke** on the old key and confirm.

For a leaked key, revoke it immediately, then configure a replacement. Revocation
stops authentication with that key without disconnecting sources or deleting data.
To change permissions or connection limits through Platform, create a replacement.

## Common problems [#common-problems]

* **Create key is unavailable:** ask an organization administrator to create a key
  with the permissions and connection limits you need.
* **The ticket loads without its orders, or a refresh reports `not_permitted`:**
  the key may include the mailbox but omit the Shopify store. Replace it with one
  scoped to both.

For authentication failures, see [API troubleshooting](/troubleshooting#api-requests-fail).
Reading documentation never grants access to an organization's data.
