---
title: "Create key"
method: POST
path: "/v1/api-keys"
tags: ["API Keys"]
---

# Create key

`POST /v1/api-keys`

Creates a new API key with an optional expiry. The full key value is only returned once in the response.

## Request body

- object
  - `name` string, required
  - `expiresIn` integer — Days until expiry
  - `scope` 'full' | 'profiles' — 'full' grants access to all profiles (default), 'profiles' restricts to specific profiles
  - `profileIds` string[] — Profile IDs this key can access. Required when scope is 'profiles'.
  - `permission` 'read-write' | 'read' — 'read-write' allows all operations (default), 'read' restricts to GET requests only
  - `disabledResourceGroups` string[] — Resource groups to DISABLE on this key (opt-out denylist). Omit for a legacy full-access key. A key with any group disabled mints with the zrk_ prefix, gets 403 with code=insufficient_permissions and required_group on operations in disabled groups (each operation's group is published as x-resource-group), and can never manage API keys, invites, or member identity. With 'messages' disabled, the key cannot read or send private messages through any API surface and cannot create or edit a webhook subscription broader than itself. Subscriptions that already exist are governed by their own `disabledResourceGroups`, not by this key's. OAuth connector tokens resolve against the same registry, but their groups are not settable yet.

## Response `201`

Created

- object
  - `message` string
  - `apiKey` ApiKey
    - `id` string
    - `name` string
    - `keyPreview` string
    - `expiresAt` string, date-time
    - `createdAt` string, date-time
    - `key` string — Returned only once, on creation
    - `scope` 'full' | 'profiles' — 'full' grants access to all profiles, 'profiles' restricts to specific profiles
    - `profileIds` object[] — Profiles this key can access (populated with name and color). Only present when scope is 'profiles'.
      - `_id` string
      - `name` string
      - `color` string
    - `permission` 'read-write' | 'read' — 'read-write' allows all operations, 'read' restricts to GET requests only
    - `disabledResourceGroups` string[] — Resource groups this key can NOT access (opt-out denylist). Absent or empty means legacy full access. A key with any group disabled is a restricted key (zrk_ prefix) and can never manage API keys, invites, or member identity. Each operation's group is published as x-resource-group. With 'messages' disabled, the key cannot read or send private messages through any API surface, and it cannot create or edit a webhook subscription broader than itself: it cannot subscribe to, test-fire, redeliver, or read delivery logs for message events. Subscriptions created earlier, from the dashboard, or with a full-access key keep delivering whatever their own `disabledResourceGroups` allows, so restricting an existing integration end to end means restricting the subscription too. OAuth connector tokens (AI assistants and MCP clients) resolve against the same registry, but their groups are not settable yet: treat an authorized connector as full access.

## Other responses

- `400` — Invalid request (missing name, invalid scope/permission, or missing profileIds when scope is 'profiles')
- `401` — Unauthorized
- `403` — The API key is a restricted key (zrk_ prefix) and may not perform this operation. Three cases. (1) The operation's resource group (see the operation's x-resource-group) is disabled on the key: fix it by creating a key with the group enabled in the dashboard API keys tab and revoking the old one. (2) The operation is admin-plane (x-resource-group admin-plane: API keys, invites, connected apps, member identity), which is never grantable to restricted keys; the error reads "Restricted API keys cannot manage API keys, invites, or member identity." and the fix is a full-access key or the dashboard, never a new restricted key. (3) On webhook subscription writes, delivery-log reads and replays, a named event maps to a resource group the key does not hold, so a restricted key can never create or edit a subscription broader than itself (a no-messages key cannot subscribe to, test-fire, redeliver or read logs for message.* events).

---

[API](https://skmtc.net/zernio/apis/zernio-api.md) · [All operations](https://skmtc.net/zernio/apis/zernio-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/zernio/zernio-api/versions/51932b099b2f/schema)
