Skip to main content

composio-client for Python

Sync and async clients for the Composio v3.1 API, with typed request fields and Pydantic responses. Python 3.10 or newer is required.

Upgrading from Stainless 1.43 requires explicit authentication and the other changes in the migration guide.

Install the client

pip install composio-client

With uv:

uv add composio-client

Quickstart

from composio_client import Composio, ProjectAuth

client = Composio(auth=ProjectAuth("ak_..."))

session = client.tool_router.session.create(user_id="user@example.com")
result = client.tool_router.session.execute(
    session.session_id,
    tool_slug="GITHUB_CREATE_ISSUE",
    arguments={"owner": "composiohq", "repo": "composio", "title": "Example"},
)

The checked-in OpenAPI snapshot supplies all 116 operations across the sync and async clients. Operations marked internal are under client._internal and carry no compatibility promise.

Authenticate and scope the client

auth is required and says which Composio credential the client sends:

auth Sends
NoAuth() No Composio credential. x-api-key and its siblings are then ordinary headers you may set
ProjectAuth(key) x-api-key on every request
UserAuth(key) x-user-api-key on every request
OrganizationAuth(key) x-org-api-key on every request
AutoAuth(project=, user=, organization=) One of the configured keys per operation, chosen from the operation's declared security schemes, falling back to the project key

A fixed mode never consults the operation table. A request carries at most one credential, and only to the configured API origin.

A credential is a key or a function returning one. The function is called once per logical call and its key is reused across that call's retries and same-origin redirects. AsyncComposio also accepts an async function:

client = Composio(auth=UserAuth(lambda: vault.read("composio-user-key")))

scope routes every request to an organization, a project, or both, sent as x-org-id and x-project-id:

from composio_client import Composio, Scope, UserAuth

client = Composio(auth=UserAuth("uak_..."), scope=Scope(organization_id="org_...", project_id="pr_..."))

A header a configured owner writes cannot also come through generic headers: with auth other than NoAuth(), x-api-key, x-user-api-key and x-org-api-key are refused in default_headers, COMPOSIO_CUSTOM_HEADERS, a raw call's headers= and request_options headers; with scope set, so are x-org-id and x-project-id. Use with_options(auth=...) or with_options(scope=...) to derive a client that sends something else. with_options re-runs every constructor check; scope=None there clears the scope.

The few operations that declare x-user-api-key or x-org-id as a parameter (for example client._internal.org.consumer.project.resolve(x_user_api_key=..., x_org_id=...)) keep their keywords. The key you pass replaces the configured auth for that call, and an x_org_id that disagrees with the configured scope fails before anything is sent.

client.auth_mode and client.scope say how a client is configured. No attribute reads a credential back; keep your own copy of a key you need.

Configure from the environment

The constructor reads nothing from the process. from_env reads the mapping you hand it:

import os

client = Composio.from_env(os.environ, environment="staging")
Variable Becomes
COMPOSIO_API_KEY, COMPOSIO_USER_API_KEY, COMPOSIO_ORG_API_KEY auth: one set is that fixed mode, several are AutoAuth, none is NoAuth()
COMPOSIO_BASE_URL base_url
COMPOSIO_CUSTOM_HEADERS default_headers, held to the reserved-header rule
COMPOSIO_ORG_ID, COMPOSIO_PROJECT_ID Not read: scope is always an explicit argument

A keyword argument replaces the whole field it names: auth=NoAuth() means no credential whatever the mapping holds, and default_headers= replaces COMPOSIO_CUSTOM_HEADERS rather than merging into it.

Identify the calling product

A product built on the client passes a ClientIdentity instead of setting headers by hand:

from composio_client import ClientIdentity, Composio, ProjectAuth

client = Composio(
    auth=ProjectAuth("ak_..."),
    identity=ClientIdentity(product="composio", version="0.9.0", source="PYTHON_SDK", framework="openai"),
)

product and version are sent as x-client-provenance and x-client-version (version also as x-sdk-version); source, framework and runtime as x-source, x-framework and x-runtime. The library headers (x-client-library, x-client-library-version, x-client-language) are the package's own and are refused in default_headers, COMPOSIO_CUSTOM_HEADERS and request_options headers; once identity is set, so is every identity header. A refused name raises ComposioError. ClientIdentity is frozen and validates that every value is non-empty printable ASCII.

Use the async client

import asyncio

from composio_client import AsyncComposio, ProjectAuth


async def main() -> None:
    async with AsyncComposio(auth=ProjectAuth("ak_...")) as client:
        session = await client.tool_router.session.create(user_id="user@example.com")
        print(session.session_id)


asyncio.run(main())

Read raw response metadata

Every released resource keeps the Stainless raw and streaming accessors:

from composio_client import Composio, ProjectAuth

client = Composio(auth=ProjectAuth("ak_..."))

response = client.tool_router.session.with_raw_response.retrieve("sess_123")
print(response.status_code)
session = response.parse()

with client.tool_router.session.with_streaming_response.retrieve("sess_123") as response:
    print(response.headers)

The async resource exposes the corresponding async response objects and context managers.

Retries and timeouts

GET, HEAD, OPTIONS, PUT and DELETE calls retry up to twice on connection errors, timeouts and retryable HTTP responses. POST and PATCH are sent once by default, including tool execution. A client-level max_retries only applies to idempotent methods. A call that is safe to repeat opts in with request_options={"max_retries": 2} (or options=RequestOptions(max_retries=2) on a raw request). An idempotency_key only sends a header; server deduplication is not guaranteed, and the header does not opt a write into retries. This applies to both sync and async clients.

Handle API errors

The exception hierarchy matches the Stainless package. Existing except blocks keep working:

from composio_client import Composio, NotFoundError, ProjectAuth

client = Composio(auth=ProjectAuth("ak_..."))

try:
    client.tool_router.session.retrieve("missing")
except NotFoundError as error:
    print(error.status_code)

Execution results

The session methods execute, execute_meta and proxy_execute return their SessionExecuteResult, SessionExecuteMetaResult and SessionProxyExecuteResult unions. Each union includes a legacy *Response class, a *BlockedResponse, and an *InputRequiredResponse. A result does not always have data: handle blocked and input-required results before reading the legacy fields.

For execute, narrow the return value with isinstance:

from composio_client.types.tool_router.session_execute_response import (
    SessionExecuteBlockedResponse,
    SessionExecuteInputRequiredResponse,
    SessionExecuteResult,
)


def summarize(result: SessionExecuteResult) -> str:
    if isinstance(result, SessionExecuteBlockedResponse):
        return result.message
    if isinstance(result, SessionExecuteInputRequiredResponse):
        return f"Input required: {', '.join(result.input_requests)}"
    return result.error or "Execution completed"

SessionExecuteResponse remains a Pydantic class for completed/failed and legacy results, so existing constructors and subclasses keep working. Its result_type may be None for a legacy fixture or response. Use SessionExecuteResult when annotating the method's whole return value. The meta and proxy methods follow the same naming rule. This distinction is part of the 2.0 public contract.

Migrate pre-release owned-client calls

Earlier owned-client builds accepted aggregate body, query, and headers values. Those calls remain valid during the transition:

client.tool_router.session.create({"user_id": "user@example.com"})
client.tool_router.session.config_history("sess_123", query={"limit": 25})

Prefer the flat Stainless form in new code:

client.tool_router.session.create(user_id="user@example.com")
client.tool_router.session.config_history("sess_123", limit=25)

See the Python migration guide for compatibility details and the stricter credential transport rules.

Develop the Python package

Generate from the repository root:

pnpm generate:python
pnpm codegen:check

Run Python checks from python/:

uv run ruff check
uv run ruff format --check
uv run mypy src scripts
uv run pytest
uv run python scripts/check_stainless_compatibility.py
uv build
uv run python scripts/check_stainless_compatibility.py --wheel dist/*.whl

The normal compatibility check is offline. It reads the committed 1.43.0 fixture and does not install or call the Stainless client.

Contributing and security

See contributor guidance and the security policy. This package is licensed under Apache-2.0.

Metadata

Release files for composio-client 2.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for composio-client 2.0.1
File Size Uploaded Provenance Actions
composio_client-2.0.1.tar.gz 591.5 kB With provenance Details for composio_client-2.0.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for composio-client 2.0.1
File Interpreter ABI Platform Actions
composio_client-2.0.1-py3-none-any.whl Python 3 none any Details for composio_client-2.0.1-py3-none-any.whl

Total release size: 1.1 MB

Release files / composio_client-2.0.1.tar.gz

Download URL composio_client-2.0.1.tar.gz
Size 591.5 kB
Tags Source
SHA-256 checksum
How to use checksums
d23d185b5a45f6628263a37db56567bd8dab6b1dabc0de899ea8ce389b29517b
BLAKE2b-256 checksum
How to use checksums
11690e6e74fcd32748c9c2f58604e92e1a9fd293033231250d61b35d6a7a93e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Release files / composio_client-2.0.1-py3-none-any.whl

Download URL composio_client-2.0.1-py3-none-any.whl
Size 477.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e9a24a0883dfa67e19c3d70e0cfe1034cf427411c70edf5e5f4925e4e4d73845
BLAKE2b-256 checksum
How to use checksums
2ed7d4ca7bbbbf4c8b3b2e232e029313a8d59a4dd2f9396683806218f0eefaae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Security for composio-client 2.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for composio_client-2.0.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

2.0.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page