Composio V3

Learn more about Composio's V3 SDK and how to migrate

After a few months of development, we’re excited to release the v3 overhaul of the Composio SDK and APIs! ❤️

The new API features improved usability, enhanced stability, and better scalability. The SDKs built on top of it offer improved ergonomics and more comprehensive feature sets.

Why a new version?

Over the past few months, we have observed significant growth in usage of both our APIs and SDKs. Based on extensive feedback from our user community, we identified several key areas requiring improvement:

  • More intuitive and consistent naming conventions
  • Enhanced support for LLM and agentic frameworks such as OpenAI, Vercel AI SDK, and OpenAI Agents
  • Improved type safety and developer experience

After carefully analyzing this feedback, we determined that implementing these improvements effectively required rebuilding the APIs and SDKs from the ground up.

Nomenclature

We have updated several key terms in the SDK and API to improve clarity and consistency. The following table summarizes these changes:

Previous TermCurrent TermDefinition
ActionsToolsIndividual operations or capabilities that can be performed by an LLM agent
AppsToolkitsA collection of tools grouped under a single application
IntegrationAuth ConfigConfiguration containing developer credentials and application-level settings such as scopes and API endpoints. Scoped to a toolkit.
ConnectionConnected accountsUser-linked accounts associated with a toolkit
Entity IDUser IDThe identifier of the user performing the action (UUID or email)
TriggerTriggerAn event that can be subscribed to
ToolsetsProvidersLLM or agent framework that can be used with Composio to create agents

Switch to nano IDs from UUIDs

We have transitioned from UUIDs to nano IDs throughout the platform for the following reasons:

  • Improved readability: UUIDs are lengthy and difficult to read
  • Better usability: Easier to copy with a single double-click
  • Better organization: Nano IDs allow us to distinguish between different resource types through prefixes
FeatureNano ID PrefixExample
Connected Accountca_ca_8x9w2l3k5m
Auth Configac_ac_1234567890
Triggerti_ti_So9EQf8XnAcy

Note: Nano IDs are short, unique, and prefixed to indicate the resource type.

Backward compatibility

Aka, we’re not breaking anything.

We have implemented routing from all previous API endpoints to their new v3 counterparts, ensuring backward compatibility during the transition period.

You can continue using previous APIs with the following changes:

  • Switch from UUIDs to nano IDs
  • Update any deprecated parameters or response formats

While previous SDK versions remain functional, we will deprecate support for them in two weeks.

SDK Changes

Upgrade to the latest SDK version using the appropriate package manager:

1pip install -U composio

Both SDKs now implement proper namespacing for each concept.

User ID scoping

The concept of entity_id has been expanded and renamed to user_id.

All operations are now scoped to a user ID, including:

  • Fetching tools
  • Initiating connections
  • Executing tools
  • Managing triggers

This change provides explicit specification of the user for whom the action is being performed. When a user may have multiple accounts (such as work and personal Gmail connections), you can use the more specific connected account ID.

Replacing ToolSets with Providers

We have deprecated “toolsets” in favor of “providers”. This change allows Composio to provide deeper standardization for tool implementation across different frameworks.

Previously, you needed to import and use a framework-specific ComposioToolSet class:

1from composio_openai import ComposioToolSet, Action, App
2from openai import OpenAI

The SDK structure is now framework-agnostic and includes the OpenAI provider out of the box:

1from composio import Composio
2# from composio_langchain import LangchainProvider
3
4composio = Composio()
5# composio = Composio(provider=LangchainProvider())
6
7tools = composio.tools.get(
8 user_id="0001",
9 tools=["LINEAR_CREATE_LINEAR_ISSUE", "GITHUB_CREATE_COMMIT"]
10)
11# tools returned is formatted for the provider. by default, OpenAI.

You can now use the same tools across any framework with our unified interface, or create custom toolsets for frameworks we don’t yet support.

Read more about providers in our documentation and explore the complete list of available providers.

Fetching and filtering tools

Previously, you could filter tools by:

  • Apps
  • Action names (tool names)
  • Tags

You could also specify an important flag to retrieve the most important tools:

1from composio_openai import ComposioToolSet, Action, App
2from openai import OpenAI
3
4toolset = ComposioToolSet()
5client = OpenAI()
6
7tools = toolset.get_tools(
8 actions=[Action.GITHUB_GET_THE_AUTHENTICATED_USER], check_connected_accounts=True
9)
10
11tools = toolset.get_tools(apps=[App.GITHUB, App.LINEAR, App.SLACK], check_connected_accounts=True)

You can now filter tools by:

  • Toolkits
  • Tool slugs
  • Limit parameter
  • Search query

The important flag has been removed. Instead, tools are returned in order of importance by default:

Since user_id is now explicitly required, the check_connected_accounts flag is no longer necessary.
1from composio import Composio
2
3composio = Composio()
4
5user_id = "user@acme.org"
6
7tools_1 = composio.tools.get(user_id=user_id, toolkits=["GITHUB", "LINEAR"])
8
9tools_2 = composio.tools.get(user_id=user_id, toolkits=["SLACK"], limit=5) # Default limit=20
10
11tools_3 = composio.tools.get(
12 user_id=user_id,
13 tools=["GITHUB_CREATE_AN_ISSUE", "GITHUB_CREATE_AN_ISSUE_COMMENT", "GITHUB_CREATE_A_COMMIT"],
14)
15
16tools_4 = composio.tools.get(user_id="john", search="hackernews posts")

Fetching raw tool data

To examine the raw schema definition of a tool for understanding input/output parameters or building custom logic around tool definitions, use the following methods:

1from composio import Composio

Executing tools

Tool execution remains largely unchanged, with user_id now explicitly required.

For agentic frameworks, the tool object returned from tools.get is now the respective framework’s native tool object. Tool call execution is handled by the agentic framework itself.

For non-agentic frameworks, Composio provides a helper function to execute tool calls.

1from composio import Composio
2from openai import OpenAI
3
4openai_client = OpenAI()
5composio = Composio()
6
7tools = composio.tools.get(user_id="user@acme.com",
8 toolkits=["GITHUB_GET_THE_ZEN_OF_GITHUB"])
9
10response = openai_client.chat.completions.create(
11 model="gpt-4.1",
12 messages=[{"role": "user", "content": "gimme some zen."}],
13 tools=tools,
14)
15
16result = composio.provider.handle_tool_calls(user_id="user@acme.com", response=response)
17print(result)

For more information on executing tools for different frameworks, see Replacing ToolSets with Providers.

Tool Modifiers (formerly Tool Processors)

Tool processors have been renamed to tool modifiers and now provide an improved developer experience. The implementation is now available in TypeScript too! (previously Python-only).

Python (previous)
1from composio_openai import ComposioToolSet, Action
2
3toolset = ComposioToolSet()
4
5
6def my_schema_processor(schema: dict) -> dict: ...
7def my_preprocessor(inputs: dict) -> dict: ...
8def my_postprocessor(result: dict) -> dict: ...
9
10
11# Get tools with the modified schema
12processed_tools = toolset.get_tools(
13 actions=[Action.GMAIL_SEND_EMAIL],
14 processors={
15 # Applied BEFORE the LLM sees the schema
16 "schema": {Action.SOME_ACTION: my_schema_processor},
17 # Applied BEFORE the tool executes
18 "pre": {Action.SOME_ACTION: my_preprocessor},
19 # Applied AFTER the tool executes, BEFORE the result is returned
20 "post": {Action.SOME_ACTION: my_postprocessor},
21 },
22)
PreviousCurrent
pre processorbeforeExecute modifier
post processorafterExecute modifier
schema processorschema modifier

The modifiers now leverage language-specific features to provide a more natural developer experience.

While tool processors could previously be applied during SDK initialization, tool fetching, and tool execution, we have restructured them as follows:

  • Chat Completion providers: Modifiers are specified and applied during tool execution
  • Agentic frameworks: Modifiers are specified and applied during tool fetching

Schema Modifiers

The following example demonstrates schema modifier usage, applicable across all providers:

1

Before Modifiers

The following example shows creating and using a before modifier for a Chat Completion provider. For agentic frameworks, view the complete before modifier documentation:

1

After Modifiers

The following example shows creating and using an after modifier for a Chat Completion provider. For agentic frameworks, view the complete after modifier documentation:

1

Custom Tools

The SDK continues to support custom tools. Creating tools from your methods remains possible. We recommend reviewing the detailed custom tools documentation for more information.

Due to changes in the SDK architecture, creating custom tools that use Composio’s managed authentication has been modified. In the previous SDK, you could create a custom tool as follows:

1# Python Example using execute_request
2from composio import action, ComposioToolSet
3import typing as t
4
5toolset = ComposioToolSet()
6
7@action(toolname="github") # Associate with GitHub app for auth
8def get_github_repo_topics(
9 owner: t.Annotated[str, "Repository owner username"],
10 repo: t.Annotated[str, "Repository name"],
11 execute_request: t.Callable # Injected by Composio
12) -> dict:
13 """Gets the topics associated with a specific GitHub repository."""
14 response_data = execute_request(
15 endpoint=f"/repos/{owner}/{repo}/topics", # API path relative to base URL
16 method="GET"
17 )
18 if isinstance(response_data, dict):
19 return {"topics": response_data.get("names", [])}

The execute tool request method handles injection of the appropriate base URL and authentication credentials for the tool:

1from pydantic import BaseModel, Field
2from composio import Composio
3from composio.core.models.custom_tools import ExecuteRequestFn
4
5
6composio = Composio()
7
8class GetIssueInfoInput(BaseModel):
9 issue_number: int = Field(
10 ...,
11 description="The number of the issue to get information about",
12 )
13
14# function name will be used as slug
15@composio.tools.custom_tool(toolkit="github")
16def get_issue_info(
17 request: GetIssueInfoInput,
18 execute_request: ExecuteRequestFn,
19 auth_credentials: dict,
20) -> dict:
21 """Get information about a GitHub issue."""
22 response = execute_request(
23 endpoint=f"/repos/composiohq/composio/issues/{request.issue_number}",
24 method="GET",
25 parameters=[
26 {
27 "name": "Accept",
28 "value": "application/vnd.github.v3+json",
29 "type": "header",
30 },
31 {
32 "name": "Authorization",
33 "value": f"Bearer {auth_credentials['access_token']}",
34 "type": "header",
35 },
36 ],
37 )
38 return {"data": response.data}

For more information, including executing custom tools and defining custom headers and query parameters, refer to the Custom Tools documentation.

Auth configs (formerly integrations)

Integrations are now called auth configs. While the terminology has changed, the underlying concept remains the same.

Auth configs store the configuration required for authentication with a given toolkit, including OAuth developer credentials, configurable base URLs, and scopes.

Auth configs now use nano IDs instead of UUIDs:

Previous (UUID) ExampleCurrent (Nano ID) Example
b7a9c1e2-3f4d-4a6b-8c2e-1d2f3a4b5c6dac_8x9w2l3k5m

We recommend storing auth config nano IDs in your database for connecting users to the appropriate auth configuration.

For most use cases, you will create auth configs through the dashboard, and this process remains unchanged. Read more about creating auth configs and customizing auth configs.

Creating auth configs programmatically in the previous SDK:

1from composio_openai import App, ComposioToolSet
2
3toolset = ComposioToolSet()
4
5integration = toolset.create_integration(
6 app=App.GITHUB,
7 auth_mode="OAUTH2",
8 use_composio_oauth_app=True,
9 # For use_composio_oauth_app=False, you can provide your own OAuth app credentials here
10 # auth_config={
11 # "client_id": "123456",
12 # "client_secret": "123456"
13 # }
14
15)

Creating auth configs programmatically in the current SDK:

1from composio import Composio
2
3composio = Composio()
4
5# Use composio managed auth
6auth_config = composio.auth_configs.create(
7 toolkit="notion",
8 options={
9 "type": "use_composio_managed_auth",
10 # "type": "use_custom_auth",
11 # "auth_scheme": "OAUTH2",
12 # "credentials": {
13 # "client_id": "1234567890",
14 # "client_secret": "1234567890",
15 # "oauth_redirect_uri": "https://backend.composio.dev/api/v3/toolkits/callback",

For using custom authentication credentials, refer to the Programmatic Auth Configs documentation.

The callback URL for creating custom OAuth configs is now https://backend.composio.dev/api/v3/toolkits/callback. The previous URL was https://backend.composio.dev/api/v1/auth-apps/add.

Connected accounts / User IDs

The primary change in connected accounts and user IDs is that user IDs are now a more prominent concept compared to entities in previous versions.

We have simplified the process of connecting a user to a toolkit. Instead of multiple methods and parameters for initiating a connection, both the SDK and API now require only a user_id and auth_config_id to initiate a connection.

This approach is more explicit and works well with the ability for developers to have multiple auth configs for a given toolkit.

Connected accounts now use nano IDs instead of UUIDs:

Previous (UUID) ExampleCurrent (Nano ID) Example
b7a9c1e2-3f4d-4a6b-8c2e-1d2f3a4b5c6dca_8x9w2l3k5m

Previously, you might have initiated a connection like this:

1from composio_openai import ComposioToolSet
2
3toolset = ComposioToolSet()
4user_id = "your_user_unique_id"
5google_integration_id = "0000-0000"
6
7entity = toolset.get_entity(id=user_id)
8
9try:
10 print(f"Initiating OAuth connection for entity {entity.id}...")
11 connection_request = toolset.initiate_connection(
12 integration_id=google_integration_id,
13 entity_id=user_id,
14 # Optionally add: redirect_url="https://yourapp.com/final-destination"
15 # if you want user sent somewhere specific *after* Composio finishes.
16 )
17
18 # Check if a redirect URL was provided (expected for OAuth)
19 if connection_request.redirectUrl:
20 print(f"Received redirect URL: {connection_request.redirectUrl}")
21 else:
22 print("Error: Expected a redirectUrl for OAuth flow but didn't receive one.")
23
24
25except Exception as e:
26 print(f"Error initiating connection: {e}")

The current process for initiating a connection is as follows:

1from composio import Composio
2
3linear_auth_config_id = "ac_1234"
4user_id = "user@email.com"
5composio = Composio()
6
7# Create a new connected account
8connection_request = composio.connected_accounts.initiate(
9 user_id=user_id,
10 auth_config_id=linear_auth_config_id,
11)
12print(connection_request.redirect_url)
13
14# Wait for the connection to be established
15connected_account = connection_request.wait_for_connection()

Triggers

Composio continues to support listening to application events using triggers through WebSockets and webhooks.

Creating triggers

The process for creating triggers and specifying their configuration has been redesigned for improved clarity and intuitiveness.

Some triggers require configuration, such as repository names for GitHub triggers or channel names for Slack triggers. You can view the configuration for a trigger as follows:

TypeScript (current)
1import { Composio } from "@composio/core";
2
3const composio = new Composio()
4
5composio.triggers.getType("GITHUB_STAR_ADDED_EVENT").then(triggerType => {
6 console.log(JSON.stringify(triggerType.config, null, 2))
7})
8// {
9// "properties": {
10// "owner": {
11// "description": "Owner of the repository",
12// "title": "Owner",
13// "type": "string"
14// },
15// "repo": {
16// "description": "Repository name",
17// "title": "Repo",
18// "type": "string"
19// }
20// },
21// "required": [
22// "owner",
23// "repo"
24// ],
25// "title": "WebhookConfigSchema",
26// "type": "object"
27// }

You can then create the trigger with the appropriate configuration:

TypeScript (current)
1const userId = "user@acme.com";
2const { items: connections } = await composio.connectedAccounts.list({ userIds: [userId] });
3const [{ id: connectedAccountId }] = connections;
4console.log(connectedAccountId);
5const createResponse = await composio.triggers.create("GITHUB_STAR_ADDED_EVENT", {
6 connectedAccountId,
7 triggerConfig: {
8 owner: "composiohq",
9 repo: "composio",
10 },
11});

Enabling/Disabling triggers

You can enable or disable triggers through either the SDK or the dashboard. The dashboard process remains unchanged.

Managing triggers with the SDK:

TypeScript (current)
1await composio.triggers.enable("ti_9q19nLNykmVZ")
2await composio.triggers.disable("ti_9q19nLNykmVZ")

Listening to triggers

We recommend listening to triggers through webhooks. The following are example routes for Next.js and FastAPI.

For development, you can also listen to triggers through the SDK.

1import type { NextApiRequest, NextApiResponse } from 'next';
2
3export default async function handler(req: NextApiRequest, res: NextApiResponse) {
4 // Only allow POST requests
5 if (req.method !== 'POST') {
6 return res.status(405).json({
7 status: 'error',
8 message: 'Method not allowed. Only POST requests are accepted.'
9 });
10 }
11
12 try {
13 const payload = req.body;
14
15 console.log('Received webhook payload:');
16 console.log(JSON.stringify(payload, null, 2));
17
18 // Process your webhook payload here
19 // Add your webhook handling logic
20
21 res.status(200).json({
22 status: 'success',
23 message: 'Webhook received and processed successfully'
24 });
25 } catch (error) {
26 console.error('Error processing webhook:', error);
27 res.status(500).json({
28 status: 'error',
29 message: 'Internal server error while processing webhook'
30 });
31 }
32}

🚧 Coming Soon

Local tools

Previously, the Python SDK included local tools. These were tools defined within the SDK and consisted of local shell and code-related tools such as “clipboard”, “sqltool”, and “shelltool”.

This feature is currently in development for both Python and TypeScript SDKs, with newly created tools built for improved agent accuracy.

Generated types

In the previous Python SDK, you could generate types for tools using the CLI:

$composio apps generate-types

This provided app slugs and tool slugs with IntelliSense support:

Python (previous)
1from composio_openai import ComposioToolSet, App, Action
2
3print(App.GITHUB)
4print(Action.GITHUB_CREATE_ISSUE)

This feature is currently in development for both Python and TypeScript SDKs.

API Endpoints

The following table lists important API endpoints that have changed. You can use this reference to quickly find the new v3 API endpoint for migration:

This list is not exhaustive. Please refer to the API Reference for the complete list of endpoints.

Toolkits (formerly Apps)

Tools (formerly Actions)

Auth Configs (formerly Integrations/Connectors)

Connected Accounts (formerly Connections)

Triggers