Authenticating to Composio

Overview

Every Composio API request authenticates with an API key. Send the key in a request header and Composio resolves it to your project or organization.

Composio has four kinds of API key. They share the same authentication flow and differ in what they can reach.

KeyHeaderScope
Project API keyx-api-keyFull access to a single project.
Organization API keyx-org-api-keyAccess across every project in your organization.
Scoped project API key · Newx-api-keyA chosen subset of a single project's resources.
User API keyx-user-api-keySessions and consumer routes, as a member of your organization.

Send one credential per request, in the header that matches its kind. A user API key (uak_...) sent as x-api-key gets its own 401 that names the mismatch without echoing the key.

Project API key

A project API key authenticates to one project with full access. Use it for most application code.

Get it from the dashboard: sign in to composio.dev, open Settings → Project Settings, and copy the key from the API Keys section.

For an unattended coding agent with no human available to log in, use the agent authentication guide to provision a Composio account with composio login --agent, configure a project API key, and verify a live tool call.

Send it in the x-api-key header:

curl https://backend.composio.dev/api/v3.1/tools \
  -H "x-api-key: $COMPOSIO_API_KEY"

Organization API key

An organization API key authenticates across every project in your organization. Use it for organization-level endpoints.

Get it from the dashboard: open Organization Settings → General Settings and copy a token under Organization Access Tokens.

Send it in the x-org-api-key header:

curl https://backend.composio.dev/api/v3.1/org/projects \
  -H "x-org-api-key: $COMPOSIO_ORG_API_KEY"

Scoped project API key

A scoped project API key authenticates to a single project but reaches only the resources you grant it — for example, executing tools without managing connected accounts. It uses the same x-api-key header as a default project key.

Scope a key to the least it needs, then send it like any project key:

curl https://backend.composio.dev/api/v3.1/tools/execute/HACKERNEWS_GET_USER \
  -H "x-api-key: $COMPOSIO_SCOPED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"arguments": {"username": "pg"}}'

See Scoped project API keys for the permission areas, access levels, and the routes each one covers.

User API key

A user API key authenticates you as a member of your organization instead of as one project. It starts with uak_, and composio login stores one in ~/.composio/user_data.json. Send it in the x-user-api-key header.

Every session route accepts a user API key as an alternative to a project key: create, retrieve, update, delete, attach, link, search, execute, tools, toolkits, mounts, and config history. Without a scope header the key addresses your developer project:

curl -X POST https://backend.composio.dev/api/v3.1/tool_router/session \
  -H "x-user-api-key: $COMPOSIO_USER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_id": "user_123", "toolkits": {"enable": ["gmail"]}}'

To act in your organization's consumer project, add x-org-id and x-project-id, always together and always as nano IDs (org_... and proj_..., never UUIDs). The consumer agent guide shows how to resolve those IDs first.

A user API key reaches every project its owner can reach, so it is the broader credential. Keep it server-side, and prefer a project API key for application code that only needs one project.

Scope errors

StatusMeaning
401The credential is missing or invalid, or a user key was sent as x-api-key.
400A scope header is missing or holds a UUID instead of a nano ID.
404The organization or project does not exist or is not accessible to this user. The two cases are deliberately indistinguishable.
500The scope lookup itself failed. Retry, then contact support if it persists.

Choosing the key in the SDKs

The SDKs resolve the project API key by intent, so an unexpected key never gets sent by accident.

Composio optionWhat the SDK sends
apiKey: "ak_..."That key, as x-api-key. The environment and the CLI's stored key are not consulted.
apiKey omittedCOMPOSIO_API_KEY, then the project key stored by composio login in ~/.composio/user_data.json. A stored user key (uak_...) is never sent as x-api-key; the constructor throws ComposioAPIKeyKindError with the value redacted.
apiKey: nullNo project key at all. Both fallbacks are off, and the instance authenticates with the user API key you configure instead: userApiKey, its COMPOSIO_USER_API_KEY fallback, or an x-user-api-key entry in defaultHeaders. In Python, disable_api_key=True does the same with user_api_key or COMPOSIO_USER_API_KEY.

A user-only instance sends x-user-api-key on every request and no x-api-key. Only x-user-api-key in defaultHeaders counts as a credential; every other default header passes through untouched. Clones made with createSession() keep the credentials they were resolved with instead of re-reading the environment.

import os

from composio import Composio

# Project key: pass it, or omit api_key to fall back to COMPOSIO_API_KEY.
composio = Composio(api_key=os.environ["COMPOSIO_API_KEY"])

# User key only: turn the project key off and use the user key alone.
composio = Composio(
    disable_api_key=True,
    user_api_key=os.environ["COMPOSIO_USER_API_KEY"],
)

Requires @composio/core0.19.1 (TypeScript) or composio0.22.1 (Python). In Python only an omitted api_key falls back to COMPOSIO_API_KEY; an explicit api_key=None raises ApiKeyNotProvidedError, and combining disable_api_key=True with an explicit api_key raises an error. Sessions created by a user-only SDK instance export x-user-api-key in their MCP config; see What the MCP headers carry. Raw HTTP callers send the same x-user-api-key header themselves.

Webhook secrets in responses

Project listings and GET /api/v3.1/auth/session/info return webhook_secret: null. Read a signing secret from the webhook subscription endpoints, or rotate it there.