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

# Manage API keys in the admin

> Create, copy, change and revoke your team's API keys in the Membership.io admin, with the matching API request for each.

The **API keys** page in the admin at [app.member.dev](https://app.member.dev) is where the team owner creates the keys that integrations, scripts and the `mio` CLI use to call the API. Select **Account** in the sidebar to open the account menu, then select **API keys**. In the [Account area](/guides/platform-account#the-account-area), the keys are the first group of the **Developer tools** section. On the **Getting started** page, **Create API key** opens the page with the create dialog already open.

Each action below shows what to do in the admin first, then the API request that does the same thing. The [API keys reference](/reference/api-keys) has every field and error.

A few terms first:

* A **team** is the workspace that owns your hubs, media and API keys. See [Tenancy](/concepts/tenancy).
* The **team owner** is the user who created the team. Only the owner can see and manage its keys.
* The **active team** is the team the admin is working in right now. The page shows the active team's keys. Switching team closes any open dialog.
* A **team API key** is a long-lived secret, starting with `mio_sk_live_`, that lets a program call the API for one team without a user signing in. See [Authentication](/concepts/authentication).

To follow the API steps, sign in as the team owner to get an access token, as shown in [Sign in as a creator](/guides/platform-login), and set:

```bash theme={null}
export MIO_BASE_URL="https://api.member.dev"
export MIO_ACCESS_TOKEN="<team owner's platform access token>"
export TEAM_ID="<your team id>"
```

Managing keys needs a signed-in user's token. A team API key gets `403` on every request below, so a key can never create, change or revoke keys.

## Who can use the page

Only the team owner. Anyone else who opens **API keys** sees "Only the team owner can manage API keys" and "Ask the owner of *your team* to create or manage keys for this team.", with no list and no create button.

**With the API:** every API-key request from a user who is not the owner returns `403` with "Caller is not the owner of this team."

## The key list

**In the admin:** the owner sees an **API keys** group with one row per key, newest first. Each row shows:

* The key name, with a key icon.
* A line of details separated by dots: the first 24 characters of the key followed by `…` (such as `mio_sk_live_Zx9QmT4vLp2W…`), the key's scopes (`*` for a full-access key), **last used** with the date or **never**, **created** with the date, the [permissions](#permissions) that are on (**Moderate**, **Author events**) or **None enabled**, and `Expires <date>`, `Expired <date>` or **No expiry**. On active and revoked rows, select the expiry text to see the exact time and timezone. On **Expiring soon** and **Expired** rows, the exact time is on the status pill instead.
* On the right, a status pill when the key needs attention: **Expiring soon** (it expires within seven days) or **Expired**. A revoked key shows **Revoked** instead, even if its expiry date has also passed. Active keys have no pill.
* On the right of an active row, an options button (••• , labelled `<key name> options`) with **Edit permissions** and **Revoke**. It appears on hover or focus, and is always visible on touch devices. Revoked rows have no menu.

The full key is never shown again after you create it. The first 24 characters help you match a row to the secret you stored.

A **Show revoked** switch sits above the list. Revoked keys are hidden until you turn it on. If all keys are revoked, the page says **All keys are revoked** with a **Show revoked keys** link. If all loaded keys are revoked but more pages remain, it says **No keys to show yet** and offers **Load more** and **Show revoked keys**. A team with no keys at all sees **No API keys yet** ("Keys let other apps read and change this account.") and a **Create key** button. **Load more** at the bottom loads the next page when there are more keys.

**With the API:** the list includes revoked keys, never includes the secret, and has no status filter, so filter it yourself. This shows the keys that are not revoked:

```bash theme={null}
curl -s "$MIO_BASE_URL/api/v1/teams/$TEAM_ID/api-keys?page%5Bsize%5D=20" \
  -H "Authorization: Bearer $MIO_ACCESS_TOKEN" \
  -H "Accept: application/vnd.api+json" \
  | jq '.data[] | select(.attributes.revoked_at == null) | {id, name: .attributes.name, key_prefix: .attributes.key_prefix, last_used_at: .attributes.last_used_at}'
```

A key is expired when `expires_at` is in the past. When more keys remain, follow `links.next` for the next page. See [List keys](/reference/api-keys#list-keys).

Reference: [List Api Keys](/api-reference/api-keys/list-api-keys)

## Create a key

**In the admin:** select **Create key** in the page header (**Create API key** when the page is opened on its own). The **Create API key** dialog says "Create a key for *team name*. Integrations use it to call the platform." and asks for:

| Field | What to enter |
| - | - |
| Name | Required, up to 100 characters (the placeholder is `Zapier`). Name it after where it will be used, such as `CI deploy`, so you know which key to revoke later. |
| Expiry | **Never** (the default), **30 days**, **90 days** or **1 year**, counted from the moment you create the key. |
| What it can do | Two checkboxes, both unchecked by default: **Can moderate** and **Can author events**. |

Select **Create key** (or **Cancel**). The admin gives every key full access to the team (`scopes: ["*"]`); there is no scopes field to fill in.

### Permissions

A key can already call the team's routes without either permission. Turn a permission on only for a key that needs it:

* **Can moderate** ("Lets this key use the hub moderation tools.") lets the key work the hub moderation tools: the moderation queue, reports, removing and restoring content, and warning or banning members.
* **Can author events** ("Lets this key create and manage hub events.") lets the key create, update and cancel hub events.

You can change both later. The name and expiry cannot be changed after the key is created.

**With the API:** send the same fields. `expires_at` is a date-time; leave it out for a key that never expires.

```bash theme={null}
curl -s -X POST "$MIO_BASE_URL/api/v1/teams/$TEAM_ID/api-keys" \
  -H "Authorization: Bearer $MIO_ACCESS_TOKEN" \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -d '{
    "name": "CI deploy",
    "expires_at": "2027-09-25T12:00:00Z",
    "can_moderate": false,
    "can_author_events": false
  }'
```

Success is `201` with the new key. See [Create a key](/reference/api-keys#create-a-key) for every field and the JSON:API envelope form.

Reference: [Mint Api Key](/api-reference/api-keys/mint-api-key)

## Copy the secret

The secret is the full key. You see it once, right after you create the key.

**In the admin:** the dialog changes to **API key created** with a read-only **Secret key** field and the warning "Copy it now. It won't be shown again." Copy the secret with the copy button next to it (**Copy API key**), or select the field and copy it yourself, then store it in your secret manager or CI secrets. Select **Done** when you have it.

After that the admin never shows the secret again. The list shows only the first 24 characters. The secret is also dropped if you close the dialog, switch team, or your session ends before you copy it.

<Warning>
  If you lose the secret, you cannot get it back. [Revoke the key](#revoke-a-key) and create a new one.
</Warning>

**With the API:** the secret is in `data.attributes.secret` of the `201` response, and in no other response. To create a key and keep the secret in your shell in one step:

```bash theme={null}
export MIO_API_KEY=$(
  curl -s -X POST "$MIO_BASE_URL/api/v1/teams/$TEAM_ID/api-keys" \
    -H "Authorization: Bearer $MIO_ACCESS_TOKEN" \
    -H "Content-Type: application/vnd.api+json" \
    -H "Accept: application/vnd.api+json" \
    -d '{"name": "CI deploy"}' \
    | jq -r '.data.attributes.secret'
)
```

## Change permissions

**In the admin:** open the row's options button (•••) and select **Edit permissions**. The **Edit permissions** dialog says "What “*key name*” may do beyond the API." Check or uncheck **Can moderate** or **Can author events**, then select **Save**. **Save** stays disabled until you change something. The admin confirms with "Permissions updated for “*key name*”". The change applies to the key's next request, so the program using it does not need a new secret.

The dialog shows the same permission checkboxes as the create dialog. It has no name or expiry fields because those cannot change. To rename a key or change its expiry, create a new key, move your integration to it, and revoke the old one. Revoked keys have no menu.

**With the API:** send only the flags you want to change. A flag you leave out keeps its value, and a body with neither flag returns `422`.

```bash theme={null}
curl -s -X PATCH "$MIO_BASE_URL/api/v1/teams/$TEAM_ID/api-keys/$KEY_ID" \
  -H "Authorization: Bearer $MIO_ACCESS_TOKEN" \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -d '{
    "can_moderate": true
  }'
```

Success is `200` with the updated key. See [Change permissions](/reference/api-keys#change-permissions).

Reference: [Update Api Key](/api-reference/api-keys/update-api-key)

## Revoke a key

Revoke a key when you no longer need it, or when it may have leaked.

**In the admin:** open the row's options button (•••) and select **Revoke**. The dialog asks `Revoke '<key name>'?` and says "Integrations using this key will stop working immediately. This cannot be undone." Select **Revoke key** (or **Cancel**). The admin confirms with "Revoked “*key name*”", and the row's status changes to **Revoked** once the API has confirmed it. The row then drops out of the list unless **Show revoked** is on.

There is no undo. Requests made with a revoked key fail from that moment with `401` and the code `api_key_revoked`.

**With the API:**

```bash theme={null}
curl -s -X DELETE "$MIO_BASE_URL/api/v1/teams/$TEAM_ID/api-keys/$KEY_ID" \
  -H "Authorization: Bearer $MIO_ACCESS_TOKEN"
```

Success is `204 No Content`. The key stays in the list with `revoked_at` set. Revoking it again returns `409` with the code `api_key_already_revoked`.

Reference: [Revoke Api Key](/api-reference/api-keys/revoke-api-key)

## Use the key

Send the key as a bearer token. This lists the team's hubs:

```bash theme={null}
export MIO_BASE_URL="https://api.member.dev"
export TEAM_ID="<your team id>"
export MIO_API_KEY="<the secret you copied>"

curl -s "$MIO_BASE_URL/api/v1/teams/$TEAM_ID/hubs/" \
  -H "Authorization: Bearer $MIO_API_KEY" \
  -H "Accept: application/vnd.api+json" | jq
```

Keep the trailing slash on `/hubs/`. Without it the API answers with a `307` redirect and an empty body.

The `mio` CLI reads the same variable, so `export MIO_API_KEY=…` is all it needs. See [Authenticate](/guides/cli#authenticate).

A key works only on its own team's routes. It cannot manage API keys or do other things that need a signed-in user, and it can only use the moderation tools or author hub events if you turned that permission on. A `401` with `api_key_invalid` means the key is wrong or has expired; `api_key_revoked` means it was revoked. See [Use a key](/reference/api-keys#use-a-key).

## Keep a way back in

Because a key cannot create keys, the team owner has to sign in to replace a lost or revoked key. Keep the owner's password safe even if your integration only ever uses keys.

<Note>
  **Alpha:** use [Forgot your password](/guides/platform-login#forgot-your-password) from the admin sign-in page to request a reset. Until MIO-4236 lands, a reset email is sent only when the account's team has at least one hub. If you have no hubs and are locked out, contact support. If your team works only through the API, keep the owner's password safe so you can create replacement keys.
</Note>

## Related

* [API keys reference](/reference/api-keys): every field, status code and error for the key endpoints.
* [Authentication](/concepts/authentication): when to use a platform access token, a contact token or a team API key.
* [Tenancy](/concepts/tenancy): how a key is bound to one team.
* [MIO CLI](/guides/cli): use a key from scripts, CI and agents, including [moderation with an API key](/guides/cli#moderation-with-an-api-key).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.