1. Docs
  2. API Reference
  3. Create a new API key

Create a new API key

POST/portal/v1/accounts/{accountSlug}/applications/{appSlug}/environments/{envSlug}/api-keys

Authentication

  • Bearer Token Authorization

    JWT access token

Request body

  • namestring*

    API key name

  • descriptionstring

    API key description

  • access_modeenum: "scoped" | "full_access"*

    Required. `scoped` enforces the `scopes` array on every authorization check (deny if the requested permission isn't listed). `full_access` bypasses RBAC entirely within the key's Application — every permission is granted. Pick `scoped` whenever possible; `full_access` should be a deliberate choice (use cases: bootstrap automation, trusted backend services that legitimately need App-wide access). `scoped` requires a non-empty `scopes` array; `full_access` forbids `scopes`.

  • scopesstring[]

    Permission scopes this key is authorized for. Required and must be non-empty when `access_mode` is `scoped`. Must be omitted when `access_mode` is `full_access`.

  • expires_atstring

    Expiration date (ISO 8601). Omit for no expiration.

Code samples

cURLJavaScriptPythonGo
curl -X POST "https://api.canopy.dev/portal/v1/accounts/{accountSlug}/applications/{appSlug}/environments/{envSlug}/api-keys" \
  -H "Authorization: Bearer $CANOPY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "string",
    "description": "string",
    "access_mode": "scoped",
    "scopes": [
      "string"
    ],
    "expires_at": "string"
  }'

Responses

201 API key created — key value is only shown once
{
  "id": "string",
  "name": "string",
  "description": "string",
  "key": "string",
  "key_preview": "string",
  "access_mode": "scoped",
  "scopes": [
    "string"
  ],
  "expires_at": "2026-04-20T12:00:00.000Z",
  "created_at": "2026-04-20T12:00:00.000Z"
}

application/json

  • idstring*
  • namestring*
  • descriptionstring
  • keystring*

    Plaintext API key — shown only once

  • key_previewstring*
  • access_modeenum: "scoped" | "full_access"*

    `full_access` keys bypass RBAC entirely within the Application. `scoped` keys enforce the `scopes` array. Surface this prominently in any UI that lists keys — it's the difference between a routine integration credential and an App-wide bearer token.

  • scopesstring[]*
  • expires_atstring (date-time)
  • created_atstring (date-time)*
401 Invalid or expired token
403 This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa)

Returned object

On this page

Related endpoints

GETList API keys for Application
DELETERevoke an API key