{"data":{"auth":{"boundaries":"Credential families never cross: an API key (ak_* or ww_*) never reaches a route under /v1/control; cpt_* and session cookies are control-plane only; the console's session + X-Project-Id binding is the third route.","families":[{"authorizes":"control resources only","name":"control_personal_token","transport":"Authorization: Bearer cpt_*","validation":"hash-only via ControlPlaneRepository::authenticate"},{"authorizes":"the Tools part of an API key: the tools surface, /mcp and the File routes of one project","model":"One kind of API key (issue #2257): the organization owns it, and it has a Tools part (one project), a channel part (a Warta key scope: the organization, one channel or one business address), or both. A route accepts a key that has the part it needs; a valid key without that part is 403 Auth_KeyOutOfReach. GET /v1/key answers the calling key's id, name, masked value, organization and parts. Many named keys; ANY active key authenticates. Keys are stored as SHA-256 hashes and the raw value is returned exactly once, by the mint response (POST /v1/control/organizations/{organization_id}/keys, or the older POST /v1/control/projects/{project_id}/keys). A key that a Warta key route minted starts with ww_ and is the same kind. Rotation is mint new -> migrate consumers -> revoke old; the overlap is intended and there is no atomic rotate endpoint.","name":"project_api_key","transport":"Authorization: Bearer ak_*; the x-api-key header (ak_*) is also accepted"}],"note":"org_api_key (x-org-api-key, oak_*) is RETIRED (decision #113): no organization credential exists, and the header is rejected as an invalid credential.","rule":"exactly one auth family per request; two families in one request is rejected (400 Auth_MultipleCredentials)"},"base_path":"/v1/tools","catalog":{"absolute_path":"/v1/specs/catalog","auth":"none: it needs no credential","method":"GET","query":["search","toolkit_slug","limit"],"summary":"The tool catalog, with no credential: the toolkits of this deployment and every tool with its input_parameters. Read it to choose a tool and to write its arguments before you hold a project key. It is not under base_path: send the request to absolute_path."},"envelope":{"error":{"shape":{"error":{"code":"integer","message":"string","request_id":"string","slug":"string","status":"integer","suggested_fix":"string"},"errors":["string (400 validation only)"]}},"request_id":{"auth_use":"never used for authentication","echoed":"x-request-id response header on every v1 response","inbound":"X-Request-ID header (validated: alnum + ._- , len <= 128) or generated"},"success":{"shape":{"data":"any","meta":{"request_id":"string","total":"integer (lists only)"}}}},"execute_example":{"absolute_path":"/v1/tools/{slug}/execute","auth":"project_api_key (Authorization: Bearer ak_*)","method":"POST","summary":"The tool-execute call, as the absolute path a client sends to: /v1/tools is the surface (base_path) and /{slug}/execute is the route (path). The slug comes before execute; /v1/tools/execute/{slug} is not a route and answers 404 Route_NotFound. The old path /v1/tools/tools/execute/{slug} was removed by issue #2155 and answers 404 Route_NotFound."},"key":{"absolute_path":"/v1/key","auth":"an API key (Authorization: Bearer or x-api-key), whatever its parts","method":"GET","summary":"The calling API key: {id, name, masked, organization_id, created_by, created_at, last_used_at, expires_at, revoked_at, tools: {project_id} or null, channel: {scope, channel, business_address_id, phone_number} or null}. Never the secret or its hash. A converted Warta key answers masked ww_ with no tail. Any API key calls it, whatever its parts; a caller with no API key is 401 Auth_MissingApiKey. It is not under base_path: send the request to absolute_path."},"mcp":{"application_user":"The user_id query parameter or the x-user-id header. Both with different values is 400 BadRequest. org:<organization_id> of the Organization of the key's Project acts for the Project's shared Connected accounts; any other value that starts with org: is 400 BadRequest. A Tool of a toolkit whose connection_scope is organization, which only the deployment's COMPOSIO_ORG_SHARED_TOOLKITS sets, runs as org:<organization_id> whatever the URL names. The toolkits and tools query parameters (comma-separated) narrow the tool list","auth":"project_api_key only: x-api-key (ak_*) or Authorization: Bearer ak_*. No credential is read from the URL. A session cookie or a cpt_* token is 401 Auth_MissingProjectKey, and an Origin header the deployment does not allow is 403 Mcp_OriginForbidden","docs":"/docs/mcp","endpoint":"/mcp","platform_tools":{"create_connect_link":"Creates a connect link for the URL's user id. Listed when the list holds a Tool of an offered toolkit that can get a link for that user id: a user-scope toolkit, or an organization-scope toolkit when the URL names org:<organization_id>","delete_connected_account":"Deletes one Connected account of the URL's user id, with the provider revoke rule of revoke_on_delete=true. Any other id is ActionExecute_ConnectedAccountNotFound. Listed when the list holds any Tool","list_connected_accounts":"Lists the Connected accounts of the URL's user id, every status: items of id, toolkit_slug, status, auth_config_id and created_at. Listed when the list holds any Tool","request_file_upload":"Answers s3key, upload_url and upload_url_expires_at for a File; PUT the bytes to upload_url, then pass s3key to the Tool. Listed when the list holds a Tool that takes a File","rules":"None is a Tool execution: none costs a Usage unit or writes an Execution log row. Each answers a BadRequest tool error that names user_id when the URL names no Application user"},"protocol_versions":["2024-11-05","2025-03-26","2025-06-18","2025-11-25","2026-07-28"],"transport":"Streamable HTTP. POST one JSON-RPC message and get one application/json answer. GET and DELETE answer 405. The endpoint keeps no session and never sends Mcp-Session-Id"},"path_rule":"absolute_path = base_path + path. Every route entry carries absolute_path precomputed; send requests to absolute_path, never to path alone and never to /v1 + path.","routes":[{"absolute_path":"/v1/tools","auth":"project_api_key","method":"GET","path":"","summary":"List/search the tool catalog"},{"absolute_path":"/v1/tools/{slug}","auth":"project_api_key","method":"GET","path":"/{slug}","summary":"Get a tool definition"},{"absolute_path":"/v1/tools/{slug}/execute","auth":"project_api_key","method":"POST","path":"/{slug}/execute","summary":"Execute a tool action"},{"absolute_path":"/v1/tools/intents/{intent_id}","auth":"project_api_key","method":"GET","path":"/intents/{intent_id}","summary":"Inspect one capability intent from the EMBEDDED vocabulary: every implementation, which of them this deployment serves, and the observed success statistics that ride the same round trip"},{"absolute_path":"/v1/tools/auth_configs","auth":"project_api_key","method":"POST","path":"/auth_configs","request_body":{"content_type":"application/json","fields":[{"name":"toolkit","note":"An OBJECT naming the toolkit, e.g. {\"slug\": \"gmail\"}. A bare string answers 400 BadRequest","required":true,"type":"object {slug: string}"},{"name":"type","note":"use_composio_managed_auth connects through the OAuth application this deployment holds for the toolkit's provider; use_custom_auth brings your own. Any other value answers 400 BadRequest","required":true,"type":"string","values":["use_composio_managed_auth","use_custom_auth"]},{"name":"auth_scheme","note":"use_custom_auth only; defaults to OAUTH2. A managed auth config is always OAUTH2","required":false,"type":"string"},{"name":"credentials","note":"Ignored for use_composio_managed_auth. The client_secret is encrypted at rest and never returned by any auth-config response","required":"for use_custom_auth","type":"object {client_id: string, client_secret: string, scopes?: string[]}"}]},"response":{"data":{"auth_config":{"auth_scheme":"string","id":"string (ac_...), the auth_config_id POST /connected_accounts/link takes","is_composio_managed":"boolean","restrict_to_following_tools":"array (always empty)"},"toolkit":{"slug":"string"}},"envelope":"{data, meta}","refusals":["400 Toolkit_NotConnectable: use_composio_managed_auth for a toolkit this deployment holds no OAuth application for. A toolkit whose managed_provider is null has no connect flow here","400 BadRequest: a malformed body"],"status":201},"summary":"Create an auth config (managed or custom). It belongs to the Project's Organization, so every Project of that Organization lists it and links through it"},{"absolute_path":"/v1/tools/auth_configs","auth":"project_api_key","method":"GET","path":"/auth_configs","summary":"List auth configs"},{"absolute_path":"/v1/tools/auth_configs/{id}","auth":"project_api_key","method":"GET","path":"/auth_configs/{id}","summary":"Get an auth config"},{"absolute_path":"/v1/tools/auth_configs/{id}","auth":"project_api_key only: a browser session answers 403 AuthConfig_SessionRefused","method":"PATCH","path":"/auth_configs/{id}","summary":"Update an auth config of the Organization: type custom changes name and credentials (client_id, client_secret, scopes); type default changes name and scopes. Absent fields stay. Connected accounts use a new client secret at their next refresh, with no reconnect. 409 AuthConfig_InUse when the client_id changes while connected accounts use it; 400 AuthConfig_FieldNotSupported for a field Sambungapi does not store"},{"absolute_path":"/v1/tools/auth_configs/{id}","auth":"project_api_key only: a browser session answers 403 AuthConfig_SessionRefused","method":"DELETE","path":"/auth_configs/{id}","summary":"Delete an auth config of the Organization, with the connected accounts of THIS Project that use it (?revoke_on_delete=true applies the provider revoke rule first). 409 AuthConfig_InUse when a connected account of another Project uses it; nothing is deleted then"},{"absolute_path":"/v1/tools/connected_accounts/link","auth":"project_api_key","method":"POST","path":"/connected_accounts/link","request_body":{"content_type":"application/json","fields":[{"name":"user_id","note":"The application user the account is for. The same value goes in the execute body's user_id. To share one account in the Project, send org:<organization_id>, where <organization_id> is the id of the Organization that owns the key's Project. A toolkit whose GET /v1/tools/toolkits entry says connection_scope: organization, which only the deployment's COMPOSIO_ORG_SHARED_TOOLKITS sets, takes only org:<organization_id> and answers 400 ScopePolicy_OrgShared for another value. A toolkit that is not in the tool catalog answers 400 ScopePolicy_UnsupportedPersonal. Any other value that starts with org: answers 400 ScopePolicy_OrganizationMismatch for every toolkit","required":true,"type":"string"},{"name":"auth_config_id","note":"An auth config of the Project's Organization (ac_...). Any other id answers 404 AuthConfig_NotFound","required":true,"type":"string"}],"return_url":"none: the request carries no return URL. After consent the provider returns the browser to this server's OAuth callback, which answers 303 to the deployment's configured return page with ?status=success&connected_account_id=... or ?status=error&error=..."},"response":{"data":{"connected_account_id":"string (ca_...): the new account, in status INITIALIZING until consent completes. Read it with GET /connected_accounts?user_ids=<user_id>; pass it as connected_account_id in the execute body","experimental":{"account_type":"PRIVATE"},"expires_at":"string (RFC 3339): 600 seconds after the link was created. The callback consumes the link once","link_token":"string (lk_...)","redirect_url":"string: {public_base_url}/connect/{link_token}. Send the application user's browser here; it answers 303 to the provider's consent page"},"envelope":"{data, meta}","refusals":["404 AuthConfig_NotFound","400 ScopePolicy_OrgShared","400 ScopePolicy_UnsupportedPersonal","400 ScopePolicy_OrganizationMismatch: user_id starts with org: and is not org:<organization_id> of the Project's Organization","400 BadRequest: user_id or auth_config_id absent or not a string","403 Auth_UserIdUnauthorized: user_id is the id of a principal other than the one that created the key; only that principal creates a connected account under its own id"],"status":201},"summary":"Create a connect link: a new connected account in INITIALIZING for {user_id}, and the redirect_url the application user opens to consent. The account becomes ACTIVE when the provider's callback stores the credential"},{"absolute_path":"/v1/tools/connected_accounts","auth":"project_api_key","method":"GET","path":"/connected_accounts","summary":"List connected accounts (?user_ids=...)"},{"absolute_path":"/v1/tools/connected_accounts/{id}/refresh","auth":"project_api_key","method":"POST","path":"/connected_accounts/{id}/refresh","summary":"Refresh a connected account"},{"absolute_path":"/v1/tools/connected_accounts/{id}","auth":"project_api_key","method":"DELETE","path":"/connected_accounts/{id}","summary":"Delete a connected account"},{"absolute_path":"/v1/tools/toolkits","auth":"any accepted v1 credential; NO project binding — the handler reads no project row, so this is the one route on this surface a cpt_* or a session with no X-Project-Id also reaches","method":"GET","path":"/toolkits","summary":"The toolkit catalog with per-toolkit availability for THIS deployment: static server configuration, never tenant data"},{"absolute_path":"/v1/tools/toolkits/googlesuper/status","auth":"project_api_key","method":"GET","path":"/toolkits/googlesuper/status","summary":"Which toolkits this project's unified googlesuper connection currently covers, computed with the same predicate the execute path uses. Reads the googlesuper account of the user_id, or of org:<organization_id> without one, and carries its ownership, per-member coverage with the exact missing scopes, and the excluded toolkits (gmail and googlecalendar are NOT members). Exposes no credential and not even the raw granted scope string"},{"absolute_path":"/v1/tools/files/upload/request","auth":"project_api_key","method":"POST","path":"/files/upload/request","summary":"Mint a presigned upload URL (md5 dedup)"},{"absolute_path":"/v1/tools/files/list","auth":"project_api_key","method":"GET","path":"/files/list","summary":"List uploaded files"}],"surface":"tools","version":"v1"},"meta":{"request_id":"req_kGMJso56D3fyMVqY","vocabulary_version":"584af6dde90e"}}