Minor Changes
-
a4a40a1: Fix project API key resolution so the SDK never sends a Composio user API key (
uak_..., as stored bycomposio login) as thex-api-keyproject credential. When that stored key is the only candidate, the constructor now throws a redactedComposioAPIKeyKindErrorthat explains the mismatch instead of making requests that fail with 401.apiKey: nullnow disables project-key authentication entirely, including theCOMPOSIO_API_KEYand~/.composio/user_data.jsonfallbacks, and is accepted when the instance holds another credential:userApiKeyororgApiKey(explicit or from their environment variables), or anx-user-api-keyentry indefaultHeaders. Requests then carry only that credential. Malformed or unexpectedly shaped user config files produce a diagnostic that names the file without echoing its contents, and cloned instances keep the credential they were resolved with instead of re-reading the environment. Code that resolves the key withapiKey: process.env.COMPOSIO_API_KEY ?? null(or any expression that yieldsnullwhen the variable is unset) is affected: it used to fall back to the environment and the CLI config file and now throws unless another credential is configured; omitapiKey(or passundefined) to keep the fallbacks. WithapiKey: null, anx-api-keyentry indefaultHeadersis rejected as well, including oncreateSession()clones: pass the project key asapiKeyinstead of a raw header. -
6c56b73: Add
userApiKeyandorgApiKeytoComposioConfig. Both are forwarded to the underlying API client, which sends each one only on operations whose security scheme requires it (organization, consumer, and user-scoped endpoints reached throughgetClient()), never alongside the project key. They fall back toCOMPOSIO_USER_API_KEYandCOMPOSIO_ORG_API_KEY. A projectapiKeyis still required unless it is set tonull, which opts into user-only authentication. -
6c56b73: Expose the rest of the owned client surface on the
Composioclass:composio.webhooks.subscriptions(list,get,set,update,delete,rotateSecret,listEventTypes) andcomposio.webhooks.endpoints(list,get,create,replace,update).composio.triggers.setWebhookSubscription()now delegates to the same upsert aswebhooks.subscriptions.set(). Its behaviour for well-formed API responses is unchanged; malformed responses are now rejected with aValidationErrorinstead of being read leniently.composio.logs.search()andcomposio.logs.get()for tool-execution logs.composio.connectedAccounts.revoke(), which surfaces the API's 400/409 asComposioConnectedAccountRevocationNotSupportedError/ComposioConnectedAccountNotRevokableError.connectedAccounts.refresh()is marked@deprecated(the endpoint is deprecated upstream).composio.toolkits.getMany(slugs)andcomposio.toolkits.changelog().session.listConfigHistory()on sessions.composio.experimental.usage.summary()andcomposio.experimental.usage.breakdown()(experimental, shape may change).composio.toolkits.recommendScopes(toolkitSlug, { tools, ... })andcomposio.toolkits.listGrantContexts(toolkitSlug)for OAuth scope recommendations (the API marks both beta).composio.connectedAccounts.completeAuth({ userId, sessionUri }), which completes a deferred OAuth connection after your OAuth callback verifier has confirmed the user's identity.composio.keyring.listTransferKeys(), which returns the public JWKs of the organization's customer-managed keyring.composio.experimental.customToolkits(upsert,sync,delete) for project-owned custom toolkits (in pilot, shape may change).CIMD_OAUTHjoinsAuthSchemeTypes.triggers.listActive()returns{}forstateandtriggerConfigwhen the API sendsnull.ToolkitAuthFieldgainsuserVisible(fromuser_visible) andToolkitAuthConfigDetailsgainsrequiredScopes(fromrequired_scopes), both omitted when the API does not send them.@composio/clientmoves from the old autogenerated client to the new handrolled client. The API removedvalidate_credentialsfrom the connected-account refresh, soconnectedAccounts.refresh()now ignoresvalidateCredentialsand logs a warning when it is set.loggerandlogLeveloptions onnew Composio({...}).loggeraccepts any{ error, warn, info, debug }sink (console, pino, winston, ...) and receives the SDK's formatted, credential-redacted output;logLevel('silent' | 'error' | 'warn' | 'info' | 'debug') overridesCOMPOSIO_LOG_LEVEL. The owned client's runtime deprecation warnings (responseDeprecation/Sunsetheaders and deprecated request inputs) are now routed through that SDK logger instead ofconsole. The client's per-request lifecycle logs are emitted only at'debug'.tools.get/getRawComposioToolssend the API'squeryparameter in place of the deprecatedsearchwire parameter; the SDK's publicsearchoption is unchanged.
-
a4a40a1: Sessions now export their MCP config from the auth context the session request was actually made with: the project key as
x-api-keywhen one is configured, otherwise the user API key (userApiKeyor thex-user-api-keydefault header) asx-user-api-key, plusx-org-id/x-project-idwhen the instance is scoped. No other default header and no ambientCOMPOSIO_API_KEYis ever copied. The headers are only attached when the MCP URL shares the origin of the configured API base URL (whatever its scheme). Any other destination (a different origin, an opaque origin such as adata:URL, or a URL that does not parse) never receives them: withmcp: true,create()/use()throwComposioMCPDestinationError, which names both origins and never includes a key; withoutmcp: truethe session is returned withsession.mcp.headersempty and a warning naming both origins is logged, so native tools keep working. The SDK never connects to the MCP URL itself and does not follow redirects for it. Trigger subscriptions (Pusher channel auth) follow the same rule instead of falling back to the environment when the project key is disabled.ComposioConfiggainsorgIdandprojectId: the organization and consumer project nano IDs, sent together as thex-org-id/x-project-idheaders on every request and with the session MCP config. They may also be supplied throughdefaultHeaders; a half-configured or disagreeing scope throwsComposioScopeConfigError. Without a scope, a user API key keeps addressing the API default project.session.update()now sends the session's last observedconfigVersionas theexpected_config_versionprecondition by default and never retries that request, so a concurrent change surfaces asComposioSessionConfigConflictError(HTTP 409; re-fetch the session, then retry) while the local session object stays unchanged. PassexpectedConfigVersionto send another version orexpectedConfigVersion: falseto opt out (last writer wins). Every policy block (toolkits,tools,tags,authConfigs,connectedAccounts,preload,manageConnections,multiAccount,search,execute,experimental) acceptsnullto remove the stored override,manageConnections.callbackUrl: nullremoves only the stored callback URL,multiAccount.maxAccountsPerToolkit: nullremoves the stored maximum, and an empty toolkit allowlist (toolkits: []) is sent as-is so it denies every app toolkit. -
6c56b73: Replace the old autogenerated
@composio/clientwith the new handrolled client.