Integrations
Composio-hosted third-party connections (Google Calendar, Slack, ...) a workspace has connected, and executing actions against them.
Third-party accounts - Google Calendar, Slack, and the rest - that a workspace has connected through Connect, and acting on them.
Three scopes, escalating: integrations:read lists what is connected, integrations:manage connects and disconnects, integrations:execute performs actions.
const { integrations } = await connect.integrations.list(workspaceId);
// Connecting is a redirect the *user* completes - you cannot do it for them.
const { redirectUrl } = await connect.integrations.connect({ workspaceId, toolkit: "googlecalendar" });
await connect.integrations.execute({
workspaceId,
toolkit: "googlecalendar",
action: "create_event",
input: { summary: "Kickoff", start, end },
});integrations:execute reaches outside Connect entirely. It acts on the customer's own Slack or calendar under their authorization - the blast radius is their account, not their workspace here. Scope keys accordingly, and expect the third party's own failures (revoked grants, rate limits, expired tokens) to surface as errors on these calls.
A connection belongs to the workspace, not to your application - another application they use may have connected it.
Endpoints
GET /api/v1/application/integrations
List a workspace's integrations
Scope integrations:read · Rate limit 30 requests / min per IP, 60 requests / min per API key
The Composio-hosted toolkits this workspace can see - only ones a platform admin has enabled in Connect's own Console - each with its connection status (not_connected, pending, active, failed, disconnected, expired).
Connections are workspace-shared, not per-user: one connection per (workspace, toolkit) covers every member.
<IntegrationsModal>/useIntegrations() in @cosmoops/connect-sdk/client render this for you, through your own bridge.
Parameters
| Name | In | Required | Notes |
|---|---|---|---|
workspaceId | query | yes | The workspace to list integrations for. |
Responses
| Status | Meaning |
|---|---|
200 | Enabled toolkits and this workspace's connection status for each |
400 | validation_error - workspaceId missing |
403 | forbidden - key unknown or missing the integrations:read scope. key_revoked / key_expired if the key itself is dead |
Response body
| Field | Type | Required | Notes |
|---|---|---|---|
toolkits | array | yes |
POST /api/v1/application/integrations/connect
Connect an integration
Scope integrations:manage · Rate limit 30 requests / min per key
Starts a Composio-hosted connection for one toolkit. Returns a redirectUrl - send the workspace's admin there to complete the provider's OAuth screen; Composio bounces them back to your own returnUrl once it finishes.
The connection is not active yet when this returns. Treat the toolkit as pending until a later GET /integrations read reports active - Connect only trusts its own webhook from Composio to make that call, never the redirect itself.
Reconnecting a disconnected/failed toolkit goes through this same endpoint - there is no separate "reconnect" call.
Only ever called through the SDK bridge on behalf of a signed-in workspace admin (see createConnectHandler's fixed POST /integrations/connect route) - not meant for a bare server-to-server call with no workspace admin in the browser.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
toolkitSlug | string | yes | |
scope | shared | personal | no | |
returnUrl | uri | yes | |
connectionData | object | no |
Responses
| Status | Meaning |
|---|---|
200 | Where to send the browser to complete the connection |
400 | validation_error - toolkit not enabled, or already actively connected |
403 | forbidden - key missing integrations:manage |
Response body
| Field | Type | Required | Notes |
|---|---|---|---|
redirectUrl | string | yes | |
connectionId | string | yes |
POST /api/v1/application/integrations/disconnect
Disconnect an integration
Scope integrations:manage · Rate limit 30 requests / min per key
Ends this workspace's connection to one toolkit and deletes the underlying Composio connected account. Idempotent - disconnecting a toolkit that was never connected, or is already disconnected, is a success.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
toolkitSlug | string | yes | |
scope | shared | personal | no |
Responses
| Status | Meaning |
|---|---|
200 | Disconnected |
403 | forbidden - key missing integrations:manage |
Response body
| Field | Type | Required | Notes |
|---|---|---|---|
success | boolean | yes |
POST /api/v1/application/integrations/actions/execute
Execute an action against a connected integration
Scope integrations:execute · Rate limit 60 requests / min per key
Calls a Composio action (e.g. "list upcoming Google Calendar events") against this workspace's connected account for the named toolkit - Connect proxies the call using its own stored connection reference, so you never hold or see the underlying OAuth token.
params is passed through to Composio verbatim; its shape is defined by the toolkit's own action schema, which Connect does not model.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
toolkitSlug | string | yes | |
actionSlug | string | yes | |
onBehalfOfUserId | any | no | |
params | object | no |
Responses
| Status | Meaning |
|---|---|
200 | The action's result |
403 | forbidden - key missing integrations:execute |
404 | not_found - no active connection to this toolkit |
Response body
| Field | Type | Required | Notes |
|---|---|---|---|
data | any | yes | |
successful | boolean | yes |
POST /api/v1/application/integrations/proxy
Call a connected integration's own API
Scope integrations:execute · Rate limit 60 requests / min per key
Sends one request to the provider's own API through this workspace's connected account, for an endpoint the toolkit ships no action for - Zoho Books has no "create sales order" action, for example. Connect attaches the credential; you never hold or see it.
endpoint is a path relative to the provider's API base (/salesorders), and nothing else: an absolute URL, a query string in the path, or a dot segment is refused, because whoever chooses the host chooses where the workspace's credential is sent. Put parameters in query. Headers cannot be set.
The response always comes back 200 once Connect has relayed the request. status is the provider's own HTTP status and data its body, so a provider-side refusal is read from those rather than from Connect's status code.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
toolkitSlug | string | yes | |
onBehalfOfUserId | any | no | |
method | GET | POST | PUT | PATCH | DELETE | yes | |
endpoint | string | yes | |
query | object | no | |
body | any | no |
Responses
| Status | Meaning |
|---|---|
200 | The provider's status and body |
400 | validation_error - an endpoint that is not a relative path, or an unknown method |
403 | forbidden - key missing integrations:execute |
404 | not_found - no active connection to this toolkit |
Response body
| Field | Type | Required | Notes |
|---|---|---|---|
status | integer | yes | |
data | any | yes |