chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:38:34 +08:00
commit 0549b088a4
2405 changed files with 810255 additions and 0 deletions
@@ -0,0 +1,12 @@
---
title: API Keys
description: "API key management"
---
{/* Auto-generated from OpenAPI spec. Do not edit directly. */}
API key management
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"POST","pathV31":"/api/v3.1/api_key_revocation","pathV3":"/api/v3/api_key_revocation","summary":"Publicly revoke leaked Composio API keys","href":"/reference/api-reference/api-keys/postApiKeyRevocation"}]} />
@@ -0,0 +1,37 @@
---
title: Auth Configs
description: "Authentication configuration management"
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/auth-configs.mdx, not this file. */}
An auth config is a blueprint that defines how a toolkit authenticates across all your users. It specifies the authentication method, the scopes your tools can request, and which credentials Composio uses to run the OAuth or token flow.
A single auth config applies to every user who connects that toolkit. When a user authenticates against it, Composio creates a [connected account](/reference/api-reference/connected-accounts) that stores their tokens and links them to your user ID.
Each auth config defines:
- **Auth scheme**: OAuth2, API key, Bearer token, or Basic Auth
- **Scopes**: what your tools are allowed to do on the user's behalf
- **Credentials**: Composio's managed app, or your own OAuth client and secrets
Reach for a custom auth config when you need your own branding on consent screens, custom scopes, a dedicated rate-limit quota, or a custom toolkit instance. See [managed vs custom auth](/docs/custom-app-vs-managed-app) for the decision and [how Composio handles authentication](/docs/authentication) for the full picture.
## Auth schemes
The `auth_scheme` on an auth config determines how users authenticate to the toolkit. Composio supports four. The schemes available for a given toolkit come from the toolkit itself.
| Scheme | What it is | When it's used |
|---|---|---|
| `OAUTH2` | OAuth 2.0 authorization-code flow. The user authorizes through a hosted consent screen, and Composio stores and automatically refreshes the access and refresh tokens. | Most apps with user accounts (Gmail, GitHub, Slack, Notion, and so on). Uses Composio's managed OAuth app by default; bring your own for custom branding or scopes. |
| `API_KEY` | A static API key the user provides. There's no OAuth flow: the key is stored on the connected account and sent on each request. | Services that authenticate with a key, such as SendGrid, Tavily, or PostHog. |
| `BEARER_TOKEN` | A bearer access token you already hold (for example, from your own OAuth flow). Composio sends it as `Authorization: Bearer <token>` and does not refresh it, so you keep it current. | Bringing an existing OAuth or server-to-server token into Composio, or apps that issue long-lived tokens. |
| `BASIC` | HTTP Basic authentication with a username and password. | Services that use Basic Auth. |
Most OAuth toolkits work out of the box with Composio managed auth. For the others you supply the credential fields. To choose or customize the scheme, see [managed vs custom auth](/docs/custom-app-vs-managed-app).
These endpoints use your project API key in the `x-api-key` header. Each auth config is addressed by its `nanoid`, and you can enable or disable one without deleting it.
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"POST","pathV31":"/api/v3.1/auth_configs","pathV3":"/api/v3/auth_configs","summary":"Create new authentication configuration","href":"/reference/api-reference/auth-configs/postAuthConfigs"},{"method":"GET","pathV31":"/api/v3.1/auth_configs","pathV3":"/api/v3/auth_configs","summary":"List authentication configurations with optional filters","href":"/reference/api-reference/auth-configs/getAuthConfigs"},{"method":"GET","pathV31":"/api/v3.1/auth_configs/{nanoid}","pathV3":"/api/v3/auth_configs/{nanoid}","summary":"Get single authentication configuration by ID","href":"/reference/api-reference/auth-configs/getAuthConfigsByNanoid"},{"method":"PATCH","pathV31":"/api/v3.1/auth_configs/{nanoid}","pathV3":"/api/v3/auth_configs/{nanoid}","summary":"Update an authentication configuration","href":"/reference/api-reference/auth-configs/patchAuthConfigsByNanoid"},{"method":"DELETE","pathV31":"/api/v3.1/auth_configs/{nanoid}","pathV3":"/api/v3/auth_configs/{nanoid}","summary":"Delete an authentication configuration","href":"/reference/api-reference/auth-configs/deleteAuthConfigsByNanoid"},{"method":"PATCH","pathV31":"/api/v3.1/auth_configs/{nanoid}/{status}","pathV3":"/api/v3/auth_configs/{nanoid}/{status}","summary":"Enable or disable an authentication configuration","href":"/reference/api-reference/auth-configs/patchAuthConfigsByNanoidByStatus"}]} />
@@ -0,0 +1,33 @@
---
title: Connected Accounts
description: "Connected account management"
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/connected-accounts.mdx, not this file. */}
A connected account is a single user's authorized connection to a toolkit. It stores their credentials (OAuth tokens or API keys) and links them to your user ID, so your tools can act on that user's behalf.
Composio creates a connected account when a user completes the flow defined by an [auth config](/reference/api-reference/auth-configs). From there you manage its full lifecycle:
- **Create or link**: start a new connection, or generate an auth link session for the user to authorize. See [manually authenticating users](/docs/manually-authenticating).
- **Refresh**: renew authentication for an account whose tokens have expired.
- **Enable, disable, or update**: change an account's status or metadata without removing it.
- **Revoke or delete**: revoke the grant at the provider, or remove the account from Composio.
Each account is addressed by its `nanoid`. List endpoints accept filters so you can find accounts by user, toolkit, or auth config.
## Link auth (Composio Connect Links)
A Composio Connect Link is a hosted, secure sign-in page. You create one with the create auth link session endpoint, redirect the user to the returned URL, and Composio handles the rest: the user signs in, Composio creates the connected account, and Composio stores and refreshes its tokens. Credentials never pass through your app. This works for all Composio managed connections, with no OAuth credentials to set up.
By default a connected account is `PRIVATE` and usable only by its owning user. Mark one `SHARED` to let other users reach it through a per-connection access control list. See [shared connections](/docs/shared-connections).
These endpoints use your project API key in the `x-api-key` header.
<Callout type="warning">
Shared-connection ACL fields are experimental and nested under an `experimental` block on the wire. Pin a specific SDK version if you depend on the current shape.
</Callout>
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"POST","pathV31":"/api/v3.1/connected_accounts/{nanoid}/revoke","pathV3":"/api/v3/connected_accounts/{nanoid}/revoke","summary":"Revoke a connected account at the provider","href":"/reference/api-reference/connected-accounts/postConnectedAccountsByNanoidRevoke"},{"method":"GET","pathV31":"/api/v3.1/connected_accounts","pathV3":"/api/v3/connected_accounts","summary":"List connected accounts with optional filters","href":"/reference/api-reference/connected-accounts/getConnectedAccounts"},{"method":"POST","pathV31":"/api/v3.1/connected_accounts","pathV3":"/api/v3/connected_accounts","summary":"Create a new connected account","href":"/reference/api-reference/connected-accounts/postConnectedAccounts"},{"method":"GET","pathV31":"/api/v3.1/connected_accounts/{nanoid}","pathV3":"/api/v3/connected_accounts/{nanoid}","summary":"Get connected account details by ID","href":"/reference/api-reference/connected-accounts/getConnectedAccountsByNanoid"},{"method":"DELETE","pathV31":"/api/v3.1/connected_accounts/{nanoid}","pathV3":"/api/v3/connected_accounts/{nanoid}","summary":"Delete a connected account","href":"/reference/api-reference/connected-accounts/deleteConnectedAccountsByNanoid"},{"method":"PATCH","pathV31":"/api/v3.1/connected_accounts/{nanoid}","pathV3":"/api/v3/connected_accounts/{nanoid}","summary":"Update a connected account","href":"/reference/api-reference/connected-accounts/patchConnectedAccountsByNanoid"},{"method":"PATCH","pathV31":"/api/v3.1/connected_accounts/{nanoId}/status","pathV3":"/api/v3/connected_accounts/{nanoId}/status","summary":"Enable or disable a connected account","href":"/reference/api-reference/connected-accounts/patchConnectedAccountsByNanoIdStatus"},{"method":"POST","pathV31":"/api/v3.1/connected_accounts/{nanoid}/refresh","pathV3":"/api/v3/connected_accounts/{nanoid}/refresh","summary":"Refresh authentication for a connected account","href":"/reference/api-reference/connected-accounts/postConnectedAccountsByNanoidRefresh"},{"method":"POST","pathV31":"/api/v3.1/connected_accounts/link","pathV3":"/api/v3/connected_accounts/link","summary":"Create a new auth link session","href":"/reference/api-reference/connected-accounts/postConnectedAccountsLink"}]} />
@@ -0,0 +1,27 @@
---
title: Files
description: "File management"
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/files.mdx, not this file. */}
These endpoints handle files that tools read and write during execution. When a tool produces or consumes a file, Composio stores it in object storage and exchanges it through presigned URLs rather than streaming bytes through the API.
You reach for these endpoints to:
- **List files** that tools have generated, optionally filtered by app and action.
- **Request an upload**: get a presigned S3 URL, `PUT` your file to it, then pass the returned reference into a tool's input.
This keeps large payloads out of request bodies. Tools receive a file reference and resolve the underlying object on their side.
<Callout type="info">
File uploads are a two-step flow. Call the upload-request endpoint to mint a presigned URL, then upload the file contents directly to that URL. The API never receives the raw bytes.
</Callout>
If your agent works with files inside a session, prefer the session file mount, where the sandbox exposes uploaded files to running code. See the [remote sandbox](/docs/sandbox/remote) for the sandbox helpers (`upload_local_file`, `smart_file_extract`) that build on this storage.
These endpoints use your project API key in the `x-api-key` header.
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"GET","pathV31":"/api/v3.1/files/list","pathV3":"/api/v3/files/list","summary":"List files with optional app and action filters (DEPRECATED)","href":"/reference/api-reference/files/getFilesList"},{"method":"POST","pathV31":"/api/v3.1/files/upload/request","pathV3":"/api/v3/files/upload/request","summary":"Create presigned URL for request file upload to S3","href":"/reference/api-reference/files/postFilesUploadRequest"}]} />
@@ -0,0 +1,150 @@
---
title: Logs
description: "Logging and monitoring"
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/logs.mdx, not this file. */}
The Logs API returns **individual tool execution events**, one record per tool call. Use it to debug failures, inspect request/response payloads, and trace specific user activity. For aggregated counts (how many tool calls happened), use the [Usage API](/reference/api-reference/organization) instead.
All endpoints in this section require a **project API key** (`x-api-key`) or a valid session cookie.
## List logs
```bash
curl -X POST https://backend.composio.dev/api/v3.1/logs/tool_execution \
-H "x-api-key: YOUR_PROJECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"limit": 20,
"time_range": {
"from": 1744848000000,
"to": 1744934400000
},
"filters": [
{ "field": "toolkit_slug", "operator": "==", "value": "gmail" },
{ "field": "status", "operator": "==", "value": "failed" }
]
}'
```
The response contains a page of log entries and a `next_cursor`:
```json
{
"logs": [
{
"id": "log_-jRTWClpBoVo",
"timestamp": "2026-04-17T10:25:00.000Z",
"type": "tool.execution",
"status": "failed",
"level": "error",
"message": "GMAIL_SEND_EMAIL failed: invalid recipient",
"metadata": { /* tool, toolkit, user_id, connected_account_id, ... */ },
"metrics": { "duration_ms": 202 },
"parent": null
}
],
"next_cursor": "eyJwYWdlIjoyfQ=="
}
```
Pass `next_cursor` back as `cursor` on the next request to paginate. When `next_cursor` is `null`, you've reached the end.
### Filter fields
Pass one or more filters in the `filters` array. Filters are **AND**-combined.
| Field | What it matches |
|---|---|
| `tool_slug` | The specific tool that was called (e.g. `GMAIL_SEND_EMAIL`) |
| `toolkit_slug` | The toolkit (e.g. `gmail`, `slack`, `github`) |
| `connected_account_id` | The connected account used for the call |
| `auth_config_id` | The auth config (integration) behind the connected account |
| `status` | `success` or `failed` |
| `user_id` | Entity that initiated the call |
| `session_id` | Tool router session, if routed through a session |
| `sandbox_id` | Sandbox the call ran in, if applicable |
| `request_id` | Request ID (useful for correlating with your own logs) |
| `log_id` | Exact log ID (equivalent to the detail endpoint) |
### Operators
| Operator | Meaning |
|---|---|
| `==` | Exact match |
| `!=` | Not equal |
| `contains` | Substring match |
| `not_contains` | Substring does not match |
### Parameters
| Field | Type | Default | Notes |
|---|---|---|---|
| `limit` | number | `20` | Max 100 |
| `cursor` | string \| null | `null` | Opaque pagination token from previous response |
| `filters` | array | `[]` | AND-combined |
| `time_range.from` | number | — | Epoch milliseconds |
| `time_range.to` | number | — | Epoch milliseconds |
## Get a single log
Fetch one log by ID to get the **full** payload, including request/response bodies, timing breakdowns, and source metadata:
```bash
curl https://backend.composio.dev/api/v3.1/logs/tool_execution/log_-jRTWClpBoVo \
-H "x-api-key: YOUR_PROJECT_API_KEY"
```
The detail response includes everything from the list shape plus:
- `timings`: `start_time` and `end_time` in epoch ms
- `context`: `session_id`, `trace_id`, `request_id`
- `source`: `host` (e.g. `mcp`, `sdk`, `api`), `framework`, `language`
- `data`: the full request payload and response body
This is the endpoint to call when you need to reconstruct *exactly* what happened, for example when debugging a 500 from a user report.
## Recipes
### Find failed Gmail tool calls in the last hour
```bash
NOW=$(date +%s)000
HOUR_AGO=$(( $(date +%s) - 3600 ))000
curl -X POST https://backend.composio.dev/api/v3.1/logs/tool_execution \
-H "x-api-key: YOUR_PROJECT_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"time_range\": { \"from\": ${HOUR_AGO}, \"to\": ${NOW} },
\"filters\": [
{ \"field\": \"toolkit_slug\", \"operator\": \"==\", \"value\": \"gmail\" },
{ \"field\": \"status\", \"operator\": \"==\", \"value\": \"failed\" }
]
}"
```
### Get failures for a specific user
```bash
curl -X POST https://backend.composio.dev/api/v3.1/logs/tool_execution \
-H "x-api-key: YOUR_PROJECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filters": [
{ "field": "user_id", "operator": "==", "value": "user_abc123" },
{ "field": "status", "operator": "==", "value": "failed" }
]
}'
```
### Fetch a single log's full request/response
```bash
curl https://backend.composio.dev/api/v3.1/logs/tool_execution/log_-jRTWClpBoVo \
-H "x-api-key: YOUR_PROJECT_API_KEY"
```
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"POST","pathV31":"/api/v3.1/logs/tool_execution","pathV3":"/api/v3/logs/tool_execution","summary":"Search and retrieve tool execution logs","href":"/reference/api-reference/logs/postLogsToolExecution"},{"method":"GET","pathV31":"/api/v3.1/logs/tool_execution/{id}","pathV3":"/api/v3/logs/tool_execution/{id}","summary":"Get log details by ID","href":"/reference/api-reference/logs/getLogsToolExecutionById"}]} />
@@ -0,0 +1,20 @@
---
title: MCP
description: "MCP server management"
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/mcp.mdx, not this file. */}
<Callout type="warning">
This API is deprecated. Use a session's MCP endpoint instead. Create a session with `composio.create(userId, { mcp: true })`, then read the hosted URL off `session.mcp.url`. See [Using sessions via MCP](/docs/sessions-via-mcp) and [migrating MCP servers to sessions](/docs/migration-guide/mcp-servers-to-sessions).
</Callout>
The MCP API is the standalone, hosted [Model Context Protocol](https://modelcontextprotocol.io) server-management surface. It let you stand up and manage a separate server config per toolkit, then mint a per-user MCP URL that any MCP-compatible client could connect to.
These endpoints create, list, update, and delete MCP servers, including custom servers spanning multiple apps, generate per-user MCP URLs, and manage per-user server instances and their connected accounts.
Sessions replace this. A single `composio.create(...)` gives you the same MCP URL pattern, keyed by `user_id`, while handling tool discovery, authentication, context, and versioning for you. Your existing tools, auth configs (`ac_…`), and connected accounts carry over with no re-authentication. To pin a session to a fixed tool list the way a server did, use the direct-tools preset described in [Configuring sessions](/docs/configuring-sessions).
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"GET","pathV31":"/api/v3.1/mcp/servers","pathV3":"/api/v3/mcp/servers","summary":"List MCP servers with optional filters and pagination","href":"/reference/api-reference/mcp/getMcpServers"},{"method":"POST","pathV31":"/api/v3.1/mcp/servers","pathV3":"/api/v3/mcp/servers","summary":"Create a new MCP server","href":"/reference/api-reference/mcp/postMcpServers"},{"method":"POST","pathV31":"/api/v3.1/mcp/servers/custom","pathV3":"/api/v3/mcp/servers/custom","summary":"Create a new custom MCP server with multiple apps","href":"/reference/api-reference/mcp/postMcpServersCustom"},{"method":"POST","pathV31":"/api/v3.1/mcp/servers/generate","pathV3":"/api/v3/mcp/servers/generate","summary":"Generate MCP URL with custom parameters","href":"/reference/api-reference/mcp/postMcpServersGenerate"},{"method":"GET","pathV31":"/api/v3.1/mcp/{id}","pathV3":"/api/v3/mcp/{id}","summary":"Get MCP server details by ID","href":"/reference/api-reference/mcp/getMcpById"},{"method":"PATCH","pathV31":"/api/v3.1/mcp/{id}","pathV3":"/api/v3/mcp/{id}","summary":"Update MCP server configuration","href":"/reference/api-reference/mcp/patchMcpById"},{"method":"DELETE","pathV31":"/api/v3.1/mcp/{id}","pathV3":"/api/v3/mcp/{id}","summary":"Delete an MCP server","href":"/reference/api-reference/mcp/deleteMcpById"},{"method":"GET","pathV31":"/api/v3.1/mcp/app/{appKey}","pathV3":"/api/v3/mcp/app/{appKey}","summary":"List MCP servers for a specific app","href":"/reference/api-reference/mcp/getMcpAppByAppKey"},{"method":"GET","pathV31":"/api/v3.1/mcp/servers/{serverId}/instances","pathV3":"/api/v3/mcp/servers/{serverId}/instances","summary":"List all instances for an MCP server","href":"/reference/api-reference/mcp/getMcpServersByServerIdInstances"},{"method":"POST","pathV31":"/api/v3.1/mcp/servers/{serverId}/instances","pathV3":"/api/v3/mcp/servers/{serverId}/instances","summary":"Create a new MCP server instance","href":"/reference/api-reference/mcp/postMcpServersByServerIdInstances"},{"method":"DELETE","pathV31":"/api/v3.1/mcp/servers/{serverId}/instances/{instanceId}","pathV3":"/api/v3/mcp/servers/{serverId}/instances/{instanceId}","summary":"Delete an MCP server instance and associated connected accounts","href":"/reference/api-reference/mcp/deleteMcpServersByServerIdInstancesByInstanceId"}]} />
@@ -0,0 +1,5 @@
{
"title": "API Reference",
"defaultOpen": true,
"pages": ["..."]
}
@@ -0,0 +1,12 @@
---
title: Organization Management
description: "Organization Management API endpoints"
---
{/* Auto-generated from OpenAPI spec. Do not edit directly. */}
Organization Management API endpoints
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"GET","pathV31":"/api/v3.1/org/list","pathV3":"/api/v3/org/list","summary":"List organizations","href":"/reference/api-reference/organization-management/getOrgList"}]} />
@@ -0,0 +1,197 @@
---
title: Organization
description: "Organization management"
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/organization.mdx, not this file. */}
The Usage API returns **aggregated counts** of tool calls and sessions. Use it to power billing dashboards, customer-facing analytics, or internal utilization reports. For individual events, use the [Logs API](/reference/api-reference/logs).
There are two query shapes:
- **Summary**: totals across one or more entity types in a time window.
- **Breakdown**: one entity type, grouped by a dimension (tool, user, session, etc.).
Each shape comes in an org-scoped and a project-scoped flavor. The org-scoped endpoints are documented below; the project-scoped usage endpoints (`POST /api/v3.1/project/usage/*`) also appear on the [Projects](/reference/api-reference/projects) reference page.
## Authentication
| Endpoint | Header | Scope |
|---|---|---|
| `POST /api/v3.1/org/usage/summary` | `x-org-api-key` *(or org JWT)* | All projects in your org |
| `POST /api/v3.1/org/usage/{entity_type}` | `x-org-api-key` *(or org JWT)* | All projects in your org |
| `POST /api/v3.1/project/usage/summary` | `x-api-key` *(or cookie)* | Single project |
| `POST /api/v3.1/project/usage/{entity_type}` | `x-api-key` *(or cookie)* | Single project |
The org endpoints accept a `project_id` filter so you can slice by project without rotating keys.
## Entity types
| Entity type | What it counts |
|---|---|
| `tool_calls` | Every tool execution (successful or failed) |
| `sessions` | Sessions created |
## Summary
Totals across entity types for a time window.
```bash
curl -X POST https://backend.composio.dev/api/v3.1/project/usage/summary \
-H "x-api-key: YOUR_PROJECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": 1744848000000,
"to": 1744934400000,
"entity_types": ["tool_calls", "sessions"]
}'
```
Response:
```json
{
"entities": {
"tool_calls": { "unit": "count", "total_quantity": "142", "event_count": 142 },
"sessions": { "unit": "count", "total_quantity": "8", "event_count": 8 }
}
}
```
### Summary parameters
| Field | Type | Default | Notes |
|---|---|---|---|
| `from` | number | 30 days ago | Epoch milliseconds |
| `to` | number | now | Epoch milliseconds |
| `entity_types` | string[] | all | Subset of `tool_calls`, `sessions` |
| `filters.user_id` | string \| string[] | — | Filter events by initiating user |
| `filters.session_id` | string \| string[] | — | Filter events by session |
| `filters.project_id` | string \| string[] | — | Only meaningful on org endpoints; ignored on project endpoints |
## Breakdown
One entity type, grouped by a dimension. Useful for answering "top N" questions.
```bash
curl -X POST https://backend.composio.dev/api/v3.1/project/usage/tool_calls \
-H "x-api-key: YOUR_PROJECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": 1744848000000,
"to": 1744934400000,
"group_by": "toolkit_slug",
"order_by": "total_quantity",
"order_direction": "desc",
"limit": 10
}'
```
Response:
```json
{
"entity_type": "tool_calls",
"unit": "count",
"total_quantity": "142",
"event_count": 142,
"groups": [
{ "key": "github", "total_quantity": "80", "event_count": 80 },
{ "key": "slack", "total_quantity": "62", "event_count": 62 }
]
}
```
### Breakdown `group_by` options
| Entity | Org scope | Project scope | Default |
|---|---|---|---|
| `tool_calls` | `tool_slug`, `toolkit_slug`, `connected_account_id`, `user_id`, `session_id`, `project_id` | same minus `project_id` | `tool_slug` |
| `sessions` | `user_id`, `project_id` | `user_id` | `user_id` |
### Breakdown parameters
| Field | Type | Default | Notes |
|---|---|---|---|
| `from` | number | 30 days ago | Epoch ms |
| `to` | number | now | Epoch ms |
| `group_by` | string | see table | Dimension to group by |
| `order_by` | string | `total_quantity` | One of `key`, `total_quantity`, `event_count` |
| `order_direction` | `"asc"` \| `"desc"` | `"desc"` | |
| `limit` | number | 50 | Max groups returned |
| `filters` | object | — | See Filters below |
## Filters
Filters live in a `filters` object on the request body. Each filter value can be a **single string** or an **array of strings**:
- Within a single field, values are OR-combined (`user_id: ["a", "b"]` matches events for user *a or b*).
- Across fields, filters are AND-combined.
```json
{
"filters": {
"user_id": ["user_123", "user_456"],
"session_id": "sess_abc"
}
}
```
The `project_id` filter is only meaningful on the org-scoped endpoints. Project endpoints accept the field but ignore it (your key already pins the scope to a single project).
## Time ranges
- `from` and `to` are **epoch milliseconds**.
- `from` defaults to 30 days before `to`.
- `to` defaults to the current time.
- Maximum range: **366 days**. Longer ranges return a 400.
## Recipes
### Top 10 tools my org called last week
```bash
WEEK_AGO=$(( $(date +%s) - 604800 ))000
NOW=$(date +%s)000
curl -X POST https://backend.composio.dev/api/v3.1/org/usage/tool_calls \
-H "x-org-api-key: YOUR_ORG_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"from\": ${WEEK_AGO},
\"to\": ${NOW},
\"group_by\": \"tool_slug\",
\"limit\": 10
}"
```
### Tool call count per user for my project this month
```bash
MONTH_AGO=$(( $(date +%s) - 2592000 ))000
NOW=$(date +%s)000
curl -X POST https://backend.composio.dev/api/v3.1/project/usage/tool_calls \
-H "x-api-key: YOUR_PROJECT_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"from\": ${MONTH_AGO},
\"to\": ${NOW},
\"group_by\": \"user_id\",
\"limit\": 50
}"
```
### Which toolkits is a specific user using?
```bash
curl -X POST https://backend.composio.dev/api/v3.1/project/usage/tool_calls \
-H "x-api-key: YOUR_PROJECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"group_by": "toolkit_slug",
"filters": { "user_id": "user_abc123" }
}'
```
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"POST","pathV31":"/api/v3.1/org/usage/summary","pathV3":"/api/v3/org/usage/summary","summary":"Org usage summary","href":"/reference/api-reference/organization/postOrgUsageSummary"},{"method":"POST","pathV31":"/api/v3.1/org/usage/{entity_type}","pathV3":"/api/v3/org/usage/{entity_type}","summary":"Org usage breakdown","href":"/reference/api-reference/organization/postOrgUsageByEntityType"}]} />
@@ -0,0 +1,66 @@
---
title: Projects
description: "Projects API endpoints"
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/projects.mdx, not this file. */}
Projects are Composio's multi-tenancy primitive. Every Composio account belongs to an **organization**. Inside an organization, **projects** are isolated environments that scope your API keys, connected accounts, auth configs, and webhook configurations. Resources in one project are not accessible from another.
```mermaid
graph LR
ORG["Organization (org_xxx)"] --- P1["Project: Production (proj_xxx)"]
ORG --- P2["Project: Staging (proj_xxx)"]
ORG --- TM["Team Members"]
P1 --- A1["API Keys"]
P1 --- A2["Connected Accounts"]
P1 --- A3["Auth Configs"]
P1 --- A4["Webhook Config"]
P2 --- B1["..."]
```
Common reasons to use multiple projects:
- **Separate environments**: keep production and staging isolated
- **Separate products**: keep resources for different apps independent
- **Client isolation**: give each client their own project with separate credentials and data
## Managing projects
Manage projects from the [dashboard](https://dashboard.composio.dev/~/org/) or via the API using an **organization API key** (`x-org-api-key`).
<Callout type="info">
Project management endpoints use the `x-org-api-key` header, not the regular `x-api-key`. Find your org API key in the dashboard under **Settings > Organization**.
</Callout>
There is no limit on the number of projects per organization. Project names must be unique within the organization. Create a project with `should_create_api_key: true` to get an API key back in the response:
```bash
curl -X POST https://backend.composio.dev/api/v3.1/org/owner/project/new \
-H "x-org-api-key: YOUR_ORG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "my-staging-project",
"should_create_api_key": true
}'
```
```json
{
"id": "proj_abc123xyz456",
"name": "my-staging-project",
"api_key": "ak_abc123xyz456"
}
```
The list endpoint supports pagination with `limit` and `cursor`; getting a project by ID returns the full project object including its API keys.
## Project settings
Each project has settings that control security, logging, and display behavior. The project detail endpoints return current configuration for inspection. Use **Settings > Project Settings** in the [dashboard](https://dashboard.composio.dev/~/project/settings/general) to update project settings.
Notable security setting: `require_mcp_api_key`, when `true`, requires MCP server requests to include a valid `x-api-key` header. This defaults to `true` for organizations created on or after March 5, 2026.
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"POST","pathV31":"/api/v3.1/project/usage/summary","pathV3":"/api/v3/project/usage/summary","summary":"Project usage summary","href":"/reference/api-reference/projects/postProjectUsageSummary"},{"method":"POST","pathV31":"/api/v3.1/project/usage/{entity_type}","pathV3":"/api/v3/project/usage/{entity_type}","summary":"Project usage breakdown","href":"/reference/api-reference/projects/postProjectUsageByEntityType"},{"method":"GET","pathV31":"/api/v3.1/org/project/list","pathV3":"/api/v3/org/project/list","summary":"List all projects","href":"/reference/api-reference/projects/getOrgProjectList"},{"method":"POST","pathV31":"/api/v3.1/org/owner/project/new","pathV3":"/api/v3/org/owner/project/new","summary":"Create a new project","href":"/reference/api-reference/projects/postOrgOwnerProjectNew"},{"method":"GET","pathV31":"/api/v3.1/org/owner/project/list","pathV3":"/api/v3/org/owner/project/list","summary":"List all projects","href":"/reference/api-reference/projects/getOrgOwnerProjectList"},{"method":"GET","pathV31":"/api/v3.1/org/owner/project/{nano_id}","pathV3":"/api/v3/org/owner/project/{nano_id}","summary":"Get project details by ID With Org Api key","href":"/reference/api-reference/projects/getOrgOwnerProjectByNanoId"},{"method":"DELETE","pathV31":"/api/v3.1/org/owner/project/{nano_id}","pathV3":"/api/v3/org/owner/project/{nano_id}","summary":"Delete a project","href":"/reference/api-reference/projects/deleteOrgOwnerProjectByNanoId"},{"method":"POST","pathV31":"/api/v3.1/org/owner/project/{nano_id}/regenerate_api_key","pathV3":"/api/v3/org/owner/project/{nano_id}/regenerate_api_key","summary":"Delete and generate new API key for project","href":"/reference/api-reference/projects/postOrgOwnerProjectByNanoIdRegenerateApiKey"}]} />
@@ -0,0 +1,22 @@
---
title: Sessions (prev Tool Router)
description: "(Labs) Tool router endpoints"
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/tool-router.mdx, not this file. */}
These are Composio's session endpoints. A **session** is the runtime context your agent uses to work for one of your users: it scopes which user's connected accounts are in play, which tools are available, how authentication happens, and where execution state lives. Read [What is a session?](/docs/how-composio-works) for the full concept.
<Callout type="info">
Sessions were formerly called the "tool router", which is why these endpoints live under `tool_router`. They are the same thing.
</Callout>
In the SDK you do not call these endpoints directly. Use `composio.create(...)` to start a session and `composio.use(...)` to resume one, then call `session.tools()`, `session.execute(...)`, and `session.authorize(...)` on the returned object.
Reach for the raw API when you need lower-level control: creating and patching a session config, attaching to an existing session, searching for tools, executing tools and meta tools, opening link sessions for auth, proxying authenticated requests, and reading or writing files in a session mount.
See [Configuring sessions](/docs/configuring-sessions) for toolkits, auth configs, account selection, and presets.
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"POST","pathV31":"/api/v3.1/tool_router/session","pathV3":"/api/v3/tool_router/session","summary":"Create a new tool router session","href":"/reference/api-reference/tool-router/postToolRouterSession"},{"method":"GET","pathV31":"/api/v3.1/tool_router/session/{session_id}","pathV3":"/api/v3/tool_router/session/{session_id}","summary":"Get a tool router session by ID (v3.1)","href":"/reference/api-reference/tool-router/getToolRouterSessionBySessionId"},{"method":"PATCH","pathV31":"/api/v3.1/tool_router/session/{session_id}","pathV3":"/api/v3/tool_router/session/{session_id}","summary":"Patch a tool router session config (v3.1)","href":"/reference/api-reference/tool-router/patchToolRouterSessionBySessionId"},{"method":"DELETE","pathV31":"/api/v3.1/tool_router/session/{session_id}","pathV3":"/api/v3/tool_router/session/{session_id}","summary":"Delete a tool router session","href":"/reference/api-reference/tool-router/deleteToolRouterSessionBySessionId"},{"method":"POST","pathV31":"/api/v3.1/tool_router/session/{session_id}/attach","pathV3":"/api/v3/tool_router/session/{session_id}/attach","summary":"Attach to an existing tool router session (v3.1)","href":"/reference/api-reference/tool-router/postToolRouterSessionBySessionIdAttach"},{"method":"GET","pathV31":"/api/v3.1/tool_router/session/{session_id}/config_history","pathV3":"/api/v3/tool_router/session/{session_id}/config_history","summary":"List a tool router session config history","href":"/reference/api-reference/tool-router/getToolRouterSessionBySessionIdConfigHistory"},{"method":"POST","pathV31":"/api/v3.1/tool_router/session/{session_id}/search","pathV3":"/api/v3/tool_router/session/{session_id}/search","summary":"Search for tools using a query","href":"/reference/api-reference/tool-router/postToolRouterSessionBySessionIdSearch"},{"method":"GET","pathV31":"/api/v3.1/tool_router/session/{session_id}/tools","pathV3":"/api/v3/tool_router/session/{session_id}/tools","summary":"List tools with schemas for a tool router session (v3.1)","href":"/reference/api-reference/tool-router/getToolRouterSessionBySessionIdTools"},{"method":"POST","pathV31":"/api/v3.1/tool_router/session/{session_id}/execute","pathV3":"/api/v3/tool_router/session/{session_id}/execute","summary":"Execute a tool within a tool router session","href":"/reference/api-reference/tool-router/postToolRouterSessionBySessionIdExecute"},{"method":"POST","pathV31":"/api/v3.1/tool_router/session/{session_id}/execute_meta","pathV3":"/api/v3/tool_router/session/{session_id}/execute_meta","summary":"Execute a meta tool within a tool router session","href":"/reference/api-reference/tool-router/postToolRouterSessionBySessionIdExecuteMeta"},{"method":"POST","pathV31":"/api/v3.1/tool_router/session/{session_id}/link","pathV3":"/api/v3/tool_router/session/{session_id}/link","summary":"Create a link session for a toolkit in a tool router session","href":"/reference/api-reference/tool-router/postToolRouterSessionBySessionIdLink"},{"method":"POST","pathV31":"/api/v3.1/tool_router/session/{session_id}/proxy_execute","pathV3":"/api/v3/tool_router/session/{session_id}/proxy_execute","summary":"Execute proxy request within a tool router session","href":"/reference/api-reference/tool-router/postToolRouterSessionBySessionIdProxyExecute"},{"method":"GET","pathV31":"/api/v3.1/tool_router/session/{session_id}/toolkits","pathV3":"/api/v3/tool_router/session/{session_id}/toolkits","summary":"Get toolkits for a tool router session","href":"/reference/api-reference/tool-router/getToolRouterSessionBySessionIdToolkits"},{"method":"GET","pathV31":"/api/v3.1/tool_router/session/{session_id}/mounts/{mount_id}/items","pathV3":"/api/v3/tool_router/session/{session_id}/mounts/{mount_id}/items","summary":"List files in a session mount","href":"/reference/api-reference/tool-router/getToolRouterSessionBySessionIdMountsByMountIdItems"},{"method":"POST","pathV31":"/api/v3.1/tool_router/session/{session_id}/mounts/{mount_id}/download_url","pathV3":"/api/v3/tool_router/session/{session_id}/mounts/{mount_id}/download_url","summary":"Create a presigned download URL for a mount file","href":"/reference/api-reference/tool-router/postToolRouterSessionBySessionIdMountsByMountIdDownloadUrl"},{"method":"POST","pathV31":"/api/v3.1/tool_router/session/{session_id}/mounts/{mount_id}/upload_url","pathV3":"/api/v3/tool_router/session/{session_id}/mounts/{mount_id}/upload_url","summary":"Create a presigned upload URL for a mount file","href":"/reference/api-reference/tool-router/postToolRouterSessionBySessionIdMountsByMountIdUploadUrl"},{"method":"POST","pathV31":"/api/v3.1/tool_router/session/{session_id}/mounts/{mount_id}/delete","pathV3":"/api/v3/tool_router/session/{session_id}/mounts/{mount_id}/delete","summary":"Delete a file from a session mount","href":"/reference/api-reference/tool-router/postToolRouterSessionBySessionIdMountsByMountIdDelete"}]} />
@@ -0,0 +1,28 @@
---
title: Toolkits
description: "Toolkit and tool management"
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/toolkits.mdx, not this file. */}
A toolkit is a collection of related tools for a single app, like `gmail`, `github`, or `slack`. Each toolkit groups the actions for that service, its authentication requirements, and the trigger types it exposes.
Reach for these endpoints when you want to:
- List the toolkits in the catalog, sorted by popularity, to browse what is available before configuring a session.
- Fetch a single toolkit by `slug` for its name, logo, categories, and metadata.
- Fetch several toolkits at once with the multi endpoint.
- List the available toolkit categories to filter the catalog by use case.
- Read the toolkits changelog to track when tools or schemas change.
These endpoints authenticate with your project API key in the `x-api-key` header.
<Callout type="info">
Tools within a toolkit are versioned. When you execute a tool, resolve to a known version with `toolkit_versions=latest` or a pinned dated version. See the [toolkit versioning migration guide](/docs/migration-guide/toolkit-versioning).
</Callout>
To browse toolkits visually, see the [toolkits catalog](/toolkits). For the concepts and SDK usage, see [Tools and toolkits](/docs/how-composio-works) and [Configuring sessions](/docs/configuring-sessions).
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"GET","pathV31":"/api/v3.1/toolkits","pathV3":"/api/v3/toolkits","summary":"List available toolkits","href":"/reference/api-reference/toolkits/getToolkits"},{"method":"GET","pathV31":"/api/v3.1/toolkits/categories","pathV3":"/api/v3/toolkits/categories","summary":"List toolkit categories","href":"/reference/api-reference/toolkits/getToolkitsCategories"},{"method":"GET","pathV31":"/api/v3.1/toolkits/{slug}","pathV3":"/api/v3/toolkits/{slug}","summary":"Get toolkit by slug","href":"/reference/api-reference/toolkits/getToolkitsBySlug"},{"method":"POST","pathV31":"/api/v3.1/toolkits/multi","pathV3":"/api/v3/toolkits/multi","summary":"Fetch multiple toolkits","href":"/reference/api-reference/toolkits/postToolkitsMulti"},{"method":"GET","pathV31":"/api/v3.1/toolkits/changelog","pathV3":"/api/v3/toolkits/changelog","summary":"Get toolkits changelog","href":"/reference/api-reference/toolkits/getToolkitsChangelog"}]} />
@@ -0,0 +1,55 @@
---
title: Tools
description: "Tool execution endpoints"
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/tools.mdx, not this file. */}
Tools are the individual executable actions inside a toolkit, like `GMAIL_SEND_EMAIL` or `GITHUB_CREATE_ISSUE`. Each tool has an input schema describing its parameters and an output schema describing what it returns. Tool slugs are SCREAMING_SNAKE_CASE and follow a `{TOOLKIT}_{ACTION}` pattern.
Reach for these endpoints when you want to:
- List or search the catalog of available tools, optionally scoped to one or more toolkits.
- Fetch a single tool's input and output schema by `tool_slug` before constructing a call.
- Execute a tool on behalf of a user's connected account, or generate the inputs for an execution from natural language.
- Look up the OAuth scopes a set of tools requires, or send an authenticated proxy request to an app's underlying API.
These endpoints authenticate with your project API key in the `x-api-key` header.
<Callout type="info">
Manual tool execution requires an explicit toolkit version. Pass `toolkit_versions=latest` (or pin a dated version like `20251027_00`) so calls resolve to a known tool definition. See the [toolkit versioning migration guide](/docs/migration-guide/toolkit-versioning).
</Callout>
For the concepts behind tools, schemas, and authentication, see [Tools and toolkits](/docs/how-composio-works).
## Proxy execute
Proxy execute sends an authenticated HTTP request through a toolkit's [connected account](/docs/auth-configuration/connected-accounts) without a predefined tool, and Composio injects the OAuth token, API key, or other credentials on the server side so your code never touches raw secrets. Reach for it when you need an endpoint that Composio's predefined tools do not cover, when you need a request shape (custom query parameters, field masks, or advanced filters) that a predefined tool cannot express, or when a terminal agent would otherwise hardcode a bearer token in a `curl` call.
Call it with `composio.tools.proxyExecute()` in the TypeScript SDK, `composio.tools.proxy()` in the Python SDK, or `POST /api/v3.1/tools/execute/proxy` over HTTP. The `endpoint` can be an absolute URL (`https://api.example.com/v1/resource`) or a path relative to the toolkit's base URL (`/v1/resource`), `method` is the HTTP verb, `connectedAccountId` selects the account to authenticate as, `body` carries the JSON payload, and `parameters` adds extra headers and query parameters. The response forwards the upstream `status`, `headers`, and parsed `data` verbatim.
```typescript
// @noErrors
import { Composio } from '@composio/core';
const composio = new Composio({ apiKey: 'your_api_key' });
const { status, data } = await composio.tools.proxyExecute({
endpoint: '/repos/composiohq/composio/issues/1',
method: 'GET',
connectedAccountId: 'ca_github_user_123',
parameters: [{ name: 'Accept', value: 'application/vnd.github.v3+json', in: 'header' }],
});
console.log(status, data);
```
<Callout type="warn">
Proxy execute rejects cross-domain requests, so the `endpoint` must resolve to the same domain as the connected account's toolkit, and you should not set the `Authorization` header yourself because Composio injects the correct credential for the account's auth scheme. This is an intentional security boundary, not a quota, so it cannot be bypassed by reshaping the request.
</Callout>
Proxy execute is a form of [direct tool execution](/docs/sessions-vs-direct-execution): it bypasses session state, tool schemas, and modifiers. If you are building an agent, prefer [sessions](/docs/configuring-sessions), and use the proxy only for the specific API call that is not available as a tool. The full request and response schema lives in the [`POST /api/v3.1/tools/execute/proxy`](/reference/api-reference/tools/postToolsExecuteProxy) reference.
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"GET","pathV31":"/api/v3.1/tools","pathV3":"/api/v3/tools","summary":"List available tools","href":"/reference/api-reference/tools/getTools"},{"method":"GET","pathV31":"/api/v3.1/tools/enum","pathV3":"/api/v3/tools/enum","summary":"Get tool enum list","href":"/reference/api-reference/tools/getToolsEnum"},{"method":"GET","pathV31":"/api/v3.1/tools/{tool_slug}","pathV3":"/api/v3/tools/{tool_slug}","summary":"Get tool by slug","href":"/reference/api-reference/tools/getToolsByToolSlug"},{"method":"POST","pathV31":"/api/v3.1/tools/execute/{tool_slug}","pathV3":"/api/v3/tools/execute/{tool_slug}","summary":"Execute tool","href":"/reference/api-reference/tools/postToolsExecuteByToolSlug"},{"method":"POST","pathV31":"/api/v3.1/tools/execute/{tool_slug}/input","pathV3":"/api/v3/tools/execute/{tool_slug}/input","summary":"Generate tool inputs from natural language","href":"/reference/api-reference/tools/postToolsExecuteByToolSlugInput"},{"method":"POST","pathV31":"/api/v3.1/tools/execute/proxy","pathV3":"/api/v3/tools/execute/proxy","summary":"Execute proxy request","href":"/reference/api-reference/tools/postToolsExecuteProxy"},{"method":"POST","pathV31":"/api/v3.1/tools/scopes/required","pathV3":"/api/v3/tools/scopes/required","summary":"Get required scopes for tools","href":"/reference/api-reference/tools/postToolsScopesRequired"}]} />
@@ -0,0 +1,31 @@
---
title: Triggers
description: "Trigger management and execution"
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/triggers.mdx, not this file. */}
Triggers let you subscribe to events from a user's connected app, such as a new Gmail message, a GitHub commit, or a Slack message, and receive the event data as a structured payload at your webhook endpoint.
There are two layers to understand:
- A **trigger type** is a template that defines what event to listen for and what configuration it needs. For example, `GITHUB_COMMIT_EVENT` requires an `owner` and a `repo`. Each toolkit exposes its own trigger types.
- A **trigger instance** is a trigger type scoped to a specific user and connected account. Creating one produces an instance with its own `ti_*` ID that you can enable, disable, or delete independently.
Reach for these endpoints when you want to:
- Discover the trigger types a toolkit offers, or fetch one type by `slug` to inspect its config and payload schema.
- Create or update a trigger instance for a connected account with the upsert endpoint.
- List active trigger instances, or enable, disable, and delete an instance by `triggerId`.
These endpoints authenticate with your project API key in the `x-api-key` header.
<Callout type="info">
Creating a trigger instance only registers it. To actually receive events, set a webhook URL for your project once, then route incoming events on `metadata.trigger_slug`. See [Subscribing to events](/docs/setting-up-triggers/subscribing-to-events).
</Callout>
For the full concept overview, see [Triggers](/docs/triggers).
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"POST","pathV31":"/api/v3.1/trigger_instances/{slug}/upsert","pathV3":"/api/v3/trigger_instances/{slug}/upsert","summary":"Create or update a trigger","href":"/reference/api-reference/triggers/postTriggerInstancesBySlugUpsert"},{"method":"GET","pathV31":"/api/v3.1/trigger_instances/active","pathV3":"/api/v3/trigger_instances/active","summary":"List active triggers","href":"/reference/api-reference/triggers/getTriggerInstancesActive"},{"method":"DELETE","pathV31":"/api/v3.1/trigger_instances/manage/{triggerId}","pathV3":"/api/v3/trigger_instances/manage/{triggerId}","summary":"Delete a trigger","href":"/reference/api-reference/triggers/deleteTriggerInstancesManageByTriggerId"},{"method":"PATCH","pathV31":"/api/v3.1/trigger_instances/manage/{triggerId}","pathV3":"/api/v3/trigger_instances/manage/{triggerId}","summary":"Enable or disable a trigger","href":"/reference/api-reference/triggers/patchTriggerInstancesManageByTriggerId"},{"method":"GET","pathV31":"/api/v3.1/triggers_types/list/enum","pathV3":"/api/v3/triggers_types/list/enum","summary":"List trigger type enums","href":"/reference/api-reference/triggers/getTriggersTypesListEnum"},{"method":"GET","pathV31":"/api/v3.1/triggers_types/{slug}","pathV3":"/api/v3/triggers_types/{slug}","summary":"Get trigger type by slug","href":"/reference/api-reference/triggers/getTriggersTypesBySlug"},{"method":"GET","pathV31":"/api/v3.1/triggers_types","pathV3":"/api/v3/triggers_types","summary":"List trigger types","href":"/reference/api-reference/triggers/getTriggersTypes"}]} />
@@ -0,0 +1,18 @@
---
title: Webhook Endpoints
description: "Per-OAuth-app webhook ingress endpoints. Inbound URLs the provider posts to, plus signing secret storage and verification."
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/webhook-endpoints.mdx, not this file. */}
Webhook endpoints are per-OAuth-app webhook ingress configurations. They define the inbound URL a provider posts events to, along with the signing secret Composio stores and uses to verify those incoming payloads.
Reach for these endpoints when an OAuth app you have configured needs to deliver provider-side events into Composio. You create an endpoint, configure or update it by its `nano_id`, and store the signing secret Composio uses to authenticate inbound requests.
Each endpoint is addressed by its `nano_id`. The `POST` to `/webhook_endpoints/{nano_id}` replaces the full configuration, while `PATCH` updates it in place.
This is distinct from [webhook subscriptions](/reference/api-reference/webhook-subscriptions), which control where Composio delivers outbound trigger events. To verify the signature on payloads Composio sends you, see [Verifying signatures](/docs/setting-up-triggers/subscribing-to-events#verifying-signatures). To set up the trigger events those payloads carry, see [Triggers](/docs/triggers).
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"POST","pathV31":"/api/v3.1/webhook_endpoints","pathV3":"/api/v3/webhook_endpoints","summary":"Create webhook endpoint","href":"/reference/api-reference/webhook-endpoints/postWebhookEndpoints"},{"method":"GET","pathV31":"/api/v3.1/webhook_endpoints","pathV3":"/api/v3/webhook_endpoints","summary":"List webhook endpoints","href":"/reference/api-reference/webhook-endpoints/getWebhookEndpoints"},{"method":"GET","pathV31":"/api/v3.1/webhook_endpoints/{nano_id}","pathV3":"/api/v3/webhook_endpoints/{nano_id}","summary":"Get webhook endpoint","href":"/reference/api-reference/webhook-endpoints/getWebhookEndpointsByNanoId"},{"method":"POST","pathV31":"/api/v3.1/webhook_endpoints/{nano_id}","pathV3":"/api/v3/webhook_endpoints/{nano_id}","summary":"Put webhook endpoint configuration","href":"/reference/api-reference/webhook-endpoints/postWebhookEndpointsByNanoId"},{"method":"PATCH","pathV31":"/api/v3.1/webhook_endpoints/{nano_id}","pathV3":"/api/v3/webhook_endpoints/{nano_id}","summary":"Update webhook endpoint configuration","href":"/reference/api-reference/webhook-endpoints/patchWebhookEndpointsByNanoId"}]} />
@@ -0,0 +1,143 @@
---
title: Webhook Subscriptions
description: "Webhook delivery subscriptions. Outbound URLs Composio posts trigger events to, plus signing secret rotation and event-type filters."
---
{/* Auto-generated from OpenAPI spec. Edit the overview at api-overviews/webhook-subscriptions.mdx, not this file. */}
Webhook subscriptions are outbound delivery configurations. They define the URL Composio posts [trigger](/docs/triggers) events to, along with the signing secret and the set of event types you want to receive.
Reach for these endpoints to register where Composio should send events, to filter delivery to specific event types, and to manage the signing secret used to verify those deliveries. List the available event types with the `/webhook_subscriptions/event_types` endpoint, then create a subscription scoped to the ones you care about.
Each subscription is addressed by its `id`. You can update its URL and filters with `PATCH`, delete it, and rotate its signing secret with `/webhook_subscriptions/{id}/rotate_secret` if the secret leaks.
Every webhook request Composio sends includes `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers. Store the secret as `COMPOSIO_WEBHOOK_SECRET` and verify each payload before trusting it. See [Verifying signatures](/docs/setting-up-triggers/subscribing-to-events#verifying-signatures) for the SDK and manual verification flows.
## Event types
A subscription's `enabled_events` controls which events get delivered to its URL. Two broad families exist:
- **Trigger events** like `composio.trigger.message` — payloads emitted by [triggers](/docs/triggers) you've enabled (new email, new issue, etc.).
- **Lifecycle events** like `composio.connected_account.expired` — emitted when a [connected account](/docs/auth-configuration/connected-accounts) changes state.
List everything you can subscribe to with the `/webhook_subscriptions/event_types` endpoint, then scope a subscription to the events you handle.
## Detecting connection expiry
Composio automatically refreshes OAuth tokens before they expire. But when a refresh token is revoked or expires, the connection enters an `EXPIRED` state and the user must re-authenticate.
Subscribe to the `composio.connected_account.expired` event to detect this proactively, instead of waiting for a tool execution to fail.
<Callout>
This event is only available with [V3 webhook payloads](/docs/setting-up-triggers/subscribing-to-events#webhook-payload-versions). New organizations use V3 by default.
</Callout>
Add `composio.connected_account.expired` to the subscription's `enabled_events`:
```bash
curl -X POST https://backend.composio.dev/api/v3.1/webhook_subscriptions \
-H "X-API-KEY: <your-composio-api-key>" \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://example.com/webhook",
"enabled_events": [
"composio.trigger.message",
"composio.connected_account.expired"
]
}'
```
When a connection expires, Composio sends a webhook with the connected account details:
```json
{
"id": "evt_847cdfcd-d219-4f18-a6dd-91acd42ca94a",
"type": "composio.connected_account.expired",
"metadata": {
"project_id": "pr_your-project-id",
"org_id": "ok_your-org-id"
},
"data": {
"id": "ca_your-connected-account-id",
"toolkit": { "slug": "gmail" },
"auth_config": {
"id": "ac_your-auth-config-id",
"auth_scheme": "OAUTH2"
},
"status": "EXPIRED",
"status_reason": "OAuth refresh token expired"
},
"timestamp": "2026-02-06T12:00:00.000Z"
}
```
Route on `type` to handle expiry alongside trigger events:
<Tabs groupId="language" items={['Python', 'TypeScript']} persist>
<Tab value="Python">
```python
from composio import Composio, WebhookEventType
composio = Composio()
@app.post("/webhook")
async def webhook_handler(request: Request):
payload = await request.json()
event_type = payload.get("type")
if event_type == WebhookEventType.CONNECTION_EXPIRED:
account_id = payload["data"]["id"]
toolkit = payload["data"]["toolkit"]["slug"]
# Look up the user and send them a re-auth link
session = composio.create(user_id=lookup_user(account_id))
connection_request = session.authorize(toolkit)
notify_user(connection_request.redirect_url)
elif event_type == WebhookEventType.TRIGGER_MESSAGE:
# Handle trigger events
pass
return {"status": "ok"}
```
</Tab>
<Tab value="TypeScript">
```typescript
import { Composio } from '@composio/core';
const composio = new Composio();
type NextApiRequest = { body: any };
type NextApiResponse = { status: (code: number) => { json: (data: any) => void } };
declare function lookupUser(accountId: string): string;
declare function notifyUser(url: string): void;
// ---cut---
export default async function webhookHandler(req: NextApiRequest, res: NextApiResponse) {
const payload = req.body;
if (payload.type === 'composio.connected_account.expired') {
const accountId = payload.data.id;
const toolkit = payload.data.toolkit.slug;
// Look up the user and send them a re-auth link
const session = await composio.create(lookupUser(accountId));
const connectionRequest = await session.authorize(toolkit);
if (connectionRequest.redirectUrl) {
notifyUser(connectionRequest.redirectUrl);
}
} else if (payload.type === 'composio.trigger.message') {
// Handle trigger events
}
res.status(200).json({ status: 'ok' });
}
```
</Tab>
</Tabs>
<Callout>
Always [verify webhook signatures](/docs/setting-up-triggers/subscribing-to-events#verifying-signatures) before processing events in production.
</Callout>
## Endpoints
<ApiEndpointsTable endpoints={[{"method":"POST","pathV31":"/api/v3.1/webhook_subscriptions","pathV3":"/api/v3/webhook_subscriptions","summary":"Create webhook subscription","href":"/reference/api-reference/webhook-subscriptions/postWebhookSubscriptions"},{"method":"GET","pathV31":"/api/v3.1/webhook_subscriptions","pathV3":"/api/v3/webhook_subscriptions","summary":"List webhook subscriptions","href":"/reference/api-reference/webhook-subscriptions/getWebhookSubscriptions"},{"method":"GET","pathV31":"/api/v3.1/webhook_subscriptions/{id}","pathV3":"/api/v3/webhook_subscriptions/{id}","summary":"Get webhook subscription","href":"/reference/api-reference/webhook-subscriptions/getWebhookSubscriptionsById"},{"method":"PATCH","pathV31":"/api/v3.1/webhook_subscriptions/{id}","pathV3":"/api/v3/webhook_subscriptions/{id}","summary":"Update webhook subscription","href":"/reference/api-reference/webhook-subscriptions/patchWebhookSubscriptionsById"},{"method":"DELETE","pathV31":"/api/v3.1/webhook_subscriptions/{id}","pathV3":"/api/v3/webhook_subscriptions/{id}","summary":"Delete webhook subscription","href":"/reference/api-reference/webhook-subscriptions/deleteWebhookSubscriptionsById"},{"method":"POST","pathV31":"/api/v3.1/webhook_subscriptions/{id}/rotate_secret","pathV3":"/api/v3/webhook_subscriptions/{id}/rotate_secret","summary":"Rotate webhook secret","href":"/reference/api-reference/webhook-subscriptions/postWebhookSubscriptionsByIdRotateSecret"},{"method":"GET","pathV31":"/api/v3.1/webhook_subscriptions/event_types","pathV3":"/api/v3/webhook_subscriptions/event_types","summary":"List available event types","href":"/reference/api-reference/webhook-subscriptions/getWebhookSubscriptionsEventTypes"}]} />