feat(connectors): implement GET + POST /api/connectors/actions
Summary
Implements the contract from recoupable/docs PR #167 (merged). Gives sandbox agents (open-agents) HTTP access to the connector action layer that the chat agent uses internally — sandbox curl + Bearer token can now list and execute the same connector tools (Gmail, Sheets, TikTok, etc.) the chat side has been using through lib/composio/toolRouter.
This is PR 2 of 3 — implementation. PR 3 (skills) updates recoup-api/SKILL.md to point sandbox agents at these endpoints.
Endpoints
GET /api/connectors/actions— lists every executable action across the account's supported toolkits. Each action returnsslug(UPPERCASE_SNAKE_CASE),name,description,parameters(JSON Schema),connectorSlug(parent toolkit, derived from slug prefix),isConnected(derived from parent toolkit's connection state). Optionalaccount_idquery param mirrorsGET /api/connectors.POST /api/connectors/actions— executes an action by slug with parameters. Composio validates the parameters against its cached schema and checks connection state before invoking; we surface the slug-not-found case as a typedConnectorActionNotFoundErrormapped to 404.
Both reuse validateAuthContext + checkAccountAccess — same auth pattern as the existing /api/connectors/{list,authorize,disconnect} family. No new auth surface.
Built TDD
Per api/CLAUDE.md's TDD requirement, each new file has its test written first, run failing (red), then implemented to green. 40 new tests across 8 new test files; all 113 connectors-suite tests pass.
| File | New tests |
|---|---|
validateGetConnectorActionsQuery.test.ts | 3 |
validateExecuteConnectorActionBody.test.ts | 8 |
validateGetConnectorActionsRequest.test.ts | 5 |
validateExecuteConnectorActionRequest.test.ts | 5 |
getConnectorActions.test.ts | 5 |
executeConnectorAction.test.ts | 5 |
getConnectorActionsHandler.test.ts | 4 |
executeConnectorActionHandler.test.ts | 5 |
Files
app/api/connectors/actions/
└── route.ts # Next.js route — GET + POST + OPTIONS
lib/composio/connectors/
├── getConnectorActions.ts # Composio catalog fetch
├── executeConnectorAction.ts # Composio execute + ConnectorActionNotFoundError
├── getConnectorActionsHandler.ts # GET orchestrator → { success, actions }
├── executeConnectorActionHandler.ts# POST orchestrator → { success, result, executedAt }
├── validateGetConnectorActionsQuery.ts
├── validateGetConnectorActionsRequest.ts
├── validateExecuteConnectorActionBody.ts
└── validateExecuteConnectorActionRequest.ts
Reuses SUPPORTED_TOOLKITS (googlesheets, googledrive, googledocs, tiktok, instagram) and buildAuthConfigs() from the existing connector code — same toolkit set as the chat agent.
Response shapes
Match the project's flat-response convention:
// GET response
{ "success": true, "actions": [ { "slug": "GMAIL_FETCH_EMAILS", ... } ] }
// POST success
{ "success": true, "result": { ...action's result... }, "executedAt": "2026-04-27T..." }
Error mapping
- 400 — invalid body / query (Zod validators).
- 401 — missing / invalid auth (handled by
validateAuthContext). - 403 — token valid but no access to specified
account_id(handled bycheckAccountAccess). - 404 —
actionSlugnot in the account's catalog (typedConnectorActionNotFoundError). - 500 — generic upstream / unexpected (catch-all).
The doc spec also documents 409 (not connected) and 502 (upstream failure). These currently bucket into 500 with the underlying error message — granular mapping is deferred to a follow-up once we see real Composio error shapes in QA. The contract is a superset; we never promise to emit 409 vs 500 for a given case, only that those codes mean those things if emitted.
Pre-existing typecheck noise
pnpm tsc --noEmit reports a few errors in lib/tasks/__tests__/ and lib/trigger/__tests__/ that exist on test already. The 3 mock-typing errors in my new tests match an identical pattern in the pre-existing getConnectors.test.ts (line 17) — codebase has tolerated this pattern. Tests pass; lint passes.
Test plan
-
pnpm test lib/composio/connectors/__tests__/— 113/113 pass -
pnpm lint:check— clean - Smoke test in preview deploy:
curl -H "Authorization: Bearer $TOKEN" $PREVIEW_URL/api/connectors/actionsreturns the catalog - Execute a simple action (e.g.
GMAIL_FETCH_EMAILS) end-to-end from a sandbox
Order of merge
- ✅
recoupable/docsPR #167 — contract (merged). - This PR — implementation against contract.
recoupable/skillsPR (TBD) —recoup-api/SKILL.mdadds a "Connector actions" section pointing sandbox agents at these endpoints.
🤖 Generated with Claude Code
Summary by cubic
Adds GET and POST /api/connectors/actions so sandbox agents can list and run connector actions. Execute path now uses the same merged toolkits (customer > artist > shared) as the catalog, so anything listed is runnable.
-
New Features
GET /api/connectors/actions:{ success, actions }where each action hasslug,name,description,parameters(JSON Schema),connectorSlug,isConnected. Optionalaccount_idquery. Catalog mirrors chat via merged toolkits.POST /api/connectors/actions: run byactionSlugwithparameters(optionalaccount_idin body); returns{ success, result, executedAt }. Unknown slugs → 404. Reuses existing auth + access checks; CORSOPTIONSincluded.
-
Bug Fixes
- Execute path now resolves tools via the merged catalog (
customer > artist > shared), matching GET; fixes 404s when POSTing actions returned by GET. toJsonSchemaconverts Composio toolinputSchemato JSON Schema for Zod v4 and v3 (viazod-to-json-schema) so no Zod internals leak into responses.
- Execute path now resolves tools via the merged catalog (
Summary by CodeRabbit
- New Features
- Added GET endpoint to retrieve available connector actions with their parameters and descriptions
- Added POST endpoint to execute connector actions with full authentication and authorization support
- Implemented comprehensive error handling with appropriate HTTP status codes
- Added CORS support for both new endpoints