saas-gateway) 🔌#Unified SaaS integration gateway (v3.1) for autonomous agents. Powered by AISA.
One API key. Connect third-party SaaS apps and run tools through the AISA gateway ( api.aisa.one).
Works with any agentskills.io-compatible harness, including:
Requires curl and AISA_API_KEY (get one at aisa.one).
api.aisa.oneAISA_API_KEY is availableLinux / macOS:
bash
export AISA_API_KEY="your-key"
Windows (PowerShell):
powershell
$env:AISA_API_KEY = "your-key"
All requests use:
https://api.aisa.one/apis/v1/composio/... (literal AISA gateway path — do not modify)Authorization: Bearer $AISA_API_KEYWindows note: Use curl.exe instead of curl in PowerShell (the built-in curl is an alias for Invoke-WebRequest and has different syntax). Or use CMD rather than PowerShell.
Replace {param} in paths with real IDs from previous responses. Never use mock IDs like test_nanoid_001 in production.
text
"Check my AISA project session and list auth configs for GitHub"
"Create an OAuth link so user alice can connect Slack"
"Run the GitHub create-issue tool for a connected account"
"List active triggers and webhook subscriptions"
"Set up an MCP server so my agent can use GitHub tools in a session"
"Upload a file and check my project usage this month"
Map the user's request to a workflow before reading further:
User intent keywordsWorkflowconnect / authorize / OAuth / link a third-party app**→ Workflow 2run tool / execute / create issue / send email→ Workflow 3** (resolve connected_account_id first)MCP server / tool session / session-scoped access**→ Workflow 3 tool-router** or Workflow 5trigger / webhook / event subscription**→ Workflow 4usage stats / call count / billing→ Workflow 6 Usagefile upload / file list→ Workflow 6 Filesproject management / API key reset→ Workflow 6 Projectsverify session / list auth configs→ Workflow 1notion / Notion workspace / page / database / wiki / task DB→ use notion-workspace skill**
When intent is unclear, run Workflow 1 to confirm session context, then ask the user what they need.
bash
curl "https://api.aisa.one/apis/v1/composio/auth/session/info" \
-H "Authorization: Bearer $AISA_API_KEY"
Key fields: project, org_member, api_key (nested IDs may appear under api_key).
If the user also asks for auth configs (e.g. GitHub), in the same flow:
bash
curl "https://api.aisa.one/apis/v1/composio/auth_configs?toolkit_slug=github&limit=10" \
-H "Authorization: Bearer $AISA_API_KEY"
Use: items[].id as auth_config_id for OAuth linking.
Details: references/auth_and_session.md
GET /apis/v1/composio/auth_configs?toolkit_slug={slug} — find items[].id as auth_config_id
POST /apis/v1/composio/auth_configs with {"toolkit": {"slug": "{slug}"}, "auth_config": {"type": "use_composio_managed_auth"}} — use auth_config.id from response as auth_config_idPOST /apis/v1/composio/connected_accounts/link — body: auth_config_id, user_id (email or arbitrary string, e.g. alice@example.com); callback_url is optionalredirect_url from the response — the human must open this URL in a browser to complete OAuthGET /apis/v1/composio/connected_accounts?user_ids={user_id}&toolkit_slugs={slug} until status is no longer PENDING
ACTIVE (connected), PENDING (user has not completed OAuth yet), DISCONNECTED / REVOKED (link failed or expired)PENDING after 2 minutes, tell the user the link may have expired and offer to create a new linkitems[].id (nanoid) as connected_account_id for tool executionIf an ACTIVE connection already exists: If GET connected_accounts already returns an ACTIVE connection for the given user_id + toolkit_slug, reuse that connected_account_id directly — no re-OAuth needed. Only create a new link when the user explicitly requests re-authorization (the old link is not automatically removed; ask the user whether to keep it).
Details: references/connect_account.md
Direct execution (one-off tool call):
Resolve connected_account_id:
GET /apis/v1/composio/connected_accounts?toolkit_slugs={slug} (add user_ids= if multiple accounts exist) and use items[].idFind the tool slug:
GET /apis/v1/composio/tools?toolkit_slug={slug} — map user intent (e.g. "create issue") to actual items[].slug (e.g. GITHUB_CREATE_AN_ISSUE)tool_slug — always list tools first if unsureGet the tool's argument schema:
GET /apis/v1/composio/tools/{tool_slug} — inspect input_parameters.required (mandatory fields) and input_parameters.properties (all fields with types and descriptions)POST /apis/v1/composio/tools/execute/{tool_slug}/input with {"text": "Create an issue titled Hello in my-org/my-repo"} — may return error code: 1010 on restricted tiers, in which case use the schema from GET /tools/{tool_slug} insteadConfirm with user before POST /apis/v1/composio/tools/execute/{tool_slug} — body requires:
connected_account_id: from step 1entity_id: the user identifier string (same value used as user_id when linking the account, e.g. alice@example.com)arguments: matching the tool's input_parameters schemaCheck the response: successful field indicates if the tool call worked. If successful is false, inspect error or data for details and retry with corrected arguments
Tool router (session-scoped, MCP-style access):
Use tool router when you need a persistent session for multiple tool calls, or when building an MCP integration.
POST /apis/v1/composio/tool_router/session — body: {"user_id": "user-id", "toolkits": ["github"]}session_id from the responsePOST .../tool_router/session/{session_id}/search — body: {"query": "create issue"}GET .../tool_router/session/{session_id}/toolsPOST .../tool_router/session/{session_id}/execute — body: {"tool_slug": "GITHUB_CREATE_AN_ISSUE", "arguments": {...}}GET .../session/{session_id} — check session statusGET .../session/{session_id}/toolkits — list session's toolkitsPOST .../session/{session_id}/link — add a toolkit connection to the sessionPOST .../session/{session_id}/proxy_execute — raw HTTP proxy within sessionGET .../session/{session_id}/config_history — view past config changesDetails: references/execute_tools.md
GET /apis/v1/composio/trigger_instances/active — list active triggers (read-only, no confirmation needed)GET /apis/v1/composio/triggers_types — browse available trigger typesGET /apis/v1/composio/webhook_endpoints — list registered webhook URLsGET /apis/v1/composio/webhook_subscriptions — list active subscriptionsGET /apis/v1/composio/webhook_subscriptions/event_types — see available event types before creating a subscriptionDetails: references/triggers_webhooks.md
Create and manage MCP (Model Context Protocol) servers for agent tool access.
GET /apis/v1/composio/mcp/servers (optional: category, search filters)POST /apis/v1/composio/mcp/servers — body: {"app": {"slug": "github"}, "name": "My GitHub MCP"}POST /apis/v1/composio/mcp/servers/custom — body: {"apps": [{"slug": "github"}, {"slug": "slack"}], "name": "My Multi-App MCP"}POST /apis/v1/composio/mcp/servers/generate — produces a connection URL for the agentGET /apis/v1/composio/mcp/servers/{serverId}/instances, POST ... to create, DELETE .../instances/{instanceId} to removeGET/PATCH/DELETE /apis/v1/composio/mcp/{id}Details: references/endpoint_catalog.md (group: mcp)
Files:
GET /apis/v1/composio/files/list?limit=10POST /apis/v1/composio/files/upload/request — get a presigned S3 URL, then PUT the file content to that URLProjects:
GET /apis/v1/composio/org/owner/project/listPOST /apis/v1/composio/org/owner/project/newGET/DELETE /apis/v1/composio/org/owner/project/{nano_id}POST /apis/v1/composio/org/owner/project/{nano_id}/regenerate_api_keyUsage statistics:
POST /apis/v1/composio/org/usage/summary — body: {}POST /apis/v1/composio/org/usage/{entity_type} — common {entity_type} values: tool_calls, sessions; body accepts group_by, limit, order_by, order_directionPOST /apis/v1/composio/project/usage/summary — body: {}; POST /apis/v1/composio/project/usage/{entity_type} — same fields as aboveResponse: Usage summary root field is entities (contains tool_calls and sessions sub-objects); breakdown root field is groups (aggregated by the group_by dimension)
Tool execution logs:
POST /apis/v1/composio/logs/tool_execution — body: {"limit": 10}; response root field is logs (not items), pagination key is next_cursorGET /apis/v1/composio/logs/tool_execution/{id}metadata.tool.slug, metadata.user_id, metadata.connected_account_id, metrics.duration_ms, status ( success/ error)Details: references/execute_tools.md (logs section), references/mcp_projects_usage.md (usage section)
User intentRead this fileSession, auth configsreferences/auth_and_session.mdConnect accounts, OAuth linkreferences/connect_account.mdToolkits, tools, tool routerreferences/execute_tools.mdTriggers, webhooksreferences/triggers_webhooks.mdMCP servers, projects, usage, file uploadreferences/mcp_projects_usage.mdExact path or HTTP methodreferences/endpoint_catalog.md
Lookup order: intent → reference (curl examples) → endpoint_catalog.md → upstream API docs for semantics only. Request URLs must use AISA inner_uri paths.
PlaceholderExample sourceNaming note{nanoid}``items[].id from list responses (auth configs, connected accounts, webhooks)Most endpoints{nanoId}Same as {nanoid} — camelCase per API conventionconnected_accounts/{nanoId}/status only{nano_id}Same as {nanoid} — snake_casewebhook_endpoints/{nano_id}, org/owner/project/{nano_id}``{slug}``toolkits[].slug or user-stated toolkit name (e.g. github, slack){tool_slug}``tools list: items[].slug (e.g. GITHUB_CREATE_AN_ISSUE){session_id}``tool_router/session create response{serverId}MCP server list/create responsecamelCase{triggerId}``trigger_instances/active list responsecamelCase{id}Context-dependent: log ID, MCP server ID, etc.
Important: Use the exact casing shown in the endpoint path. The API is case-sensitive.
connected_accounts/link, tools/execute, tool_router/session/{id}/execute, MCP server create/delete, auth config create/update, trigger upsert/delete, webhook create/delete)redirect_url must be opened by a human in a browserSymptomAction401 + quota exhaustedRenew or replace AISA_API_KEYEmpty items on auth_configsAsk user to create auth config or verify toolkit slugEmpty items on connected_accountsRun OAuth link workflow; connection may still be PENDING404 on PATCH with path IDUse a real ID from a prior GET/POST list response; check casing ( {nanoid} vs {nanoId})500 on path with fake IDDo not use test placeholdersSSL timeout on large listsRetry with smaller limit or narrower filtersMultiple GitHub connections returnedRe-query with user_ids= filter or ask user which accountUser says "create issue" but slug unknownList tools first; never guess tool_slugTool execution returns successful: falseInspect error field; common causes: wrong connected_account_id, missing required arguments, insufficient permissions — get tool schema via GET /tools/{tool_slug} and retryError 1811: entity_id requiredAdd user_id to tools/execute body — use the same value as user_id when the account was linked. entity_id is the deprecated alias for user_idError 10400: Invalid discriminator on auth_configauth_config.type is required; use use_composio_managed_auth or use_custom_authError 1151: MCP server name already existsMCP server names must be unique per project; choose a different name``x-org-api-key required error on project listProject list requires an org-level API key, not a project-level AISA_API_KEY; use session/info to confirm which key you haveOAuth link expires before user completesCreate a new link with POST connected_accounts/linkToken refresh returns redirect_url with status INITIATEDOAuth cannot auto-refresh; user must re-authorize at the returned URLlogs/tool_execution response has no itemsResponse root field is logs (not items); pagination key is next_cursor (not cursor)429 Too Many RequestsSlow down; add delays between API calls; reduce limit parameter