PRD-53: Webhook & Trigger System
Version: 1.0 Status: 🟢 Implementation Complete — Testing Required Date: February 13, 2026 Author: Claude Code Prerequisites: PRD-37 (SaaS Foundation — Workspaces), PRD-36 (Composio Integration) Branch: trigger-testing
Executive Summary
Two clean inbound webhook paths for connecting external services (Jira, GitHub, Slack, WhatsApp, Telegram, etc.) to Automatos without requiring Composio:
Recipe Webhooks — Each recipe with trigger type gets a unique URL. External services POST to it, triggering that specific recipe.
General Workspace Webhook — Single URL per workspace. Any incoming request is routed through UniversalRouter to the right agent (chatbot-style).
Both use the URL-as-secret pattern — the URL itself contains a 128-bit random key that acts as the credential. No additional auth headers required.
Problem
The recipe trigger UI offered "Composio App" as the primary option (users don't have Composio access)
The "Custom Webhook" option generated a fake client-side URL that wasn't persisted
No general workspace webhook for chatbot-style routing from external sources
Composio triggers are useful for outbound tool execution but shouldn't be required for inbound webhooks
Solution
POST /api/webhooks/recipe/{webhook_id}
Trigger a specific recipe
URL-as-secret (webhook_id = uuid4().hex)
POST /api/webhooks/ws/{workspace_key}
Route to any agent via UniversalRouter
URL-as-secret (workspace_key = uuid4().hex)
Architecture
Request Flow — Recipe Webhook
Request Flow — Workspace Webhook
Data Model Changes
New Enum Value
Implementation Status
Part 1: Recipe Webhook UI — DONE
frontend/components/workflows/recipe-schedule-config.tsx
Removed Composio trigger UI, shows real webhook URL or "save to generate" placeholder
✅
frontend/components/workflows/create-recipe-modal.tsx
Passes webhookId prop to RecipeScheduleConfig; added webhook_id?: string to schedule_config type
✅
frontend/hooks/use-recipe-form.ts
Extracts webhook_id from API response after create/update; exposes lastSavedWebhookId
✅
orchestrator/api/workflow_recipes.py
Guarded _auto_register_trigger() — skips Composio SDK when source != 'composio'
✅
Key changes:
Removed
TRIGGER_SOURCE_OPTIONS(Composio App / Custom Webhook distinction)Removed Composio app dropdown, trigger dropdown, "Configure in Composio" button
Trigger mode now shows webhook URL prominently with copy button
Before save: shows placeholder "Save the recipe to generate a webhook URL"
After save: shows real
{API_URL}/api/webhooks/recipe/{webhook_id}with copy + usage exampletrigger_configis always sent (even empty{}) for trigger type — fixes backend validation
Part 2: General Workspace Webhook — DONE
orchestrator/core/models/routing.py
Added WEBHOOK = "webhook" to ChannelSource enum
✅
orchestrator/core/models/workspaces.py
Added webhook_key column (String(64), unique, nullable)
✅
orchestrator/alembic/versions/20260213_add_workspace_webhook_key.py
Migration: add column, backfill existing workspaces, create unique index
✅
orchestrator/core/auth/hybrid.py
Generate webhook_key = uuid4().hex during workspace provisioning
✅
orchestrator/core/routing/ingestors/webhook.py
NEW — WebhookIngestor: normalizes POST body → RequestEnvelope
✅
orchestrator/api/webhooks.py
NEW — POST /api/webhooks/ws/{workspace_key} endpoint
✅
orchestrator/main.py
Registered general_webhooks_router
✅
orchestrator/api/workspaces.py
Returns webhook_url and webhook_key in workspace response; auto-generates key if missing
✅
WebhookIngestor behavior:
Extracts content from
body.message,body.text, orbody.contentFalls back to JSON stringify of full body
body.agent_id→ Tier-0 override (routes directly to specific agent)body.source,body.channel,body.event_type,body.service→ metadata for routing rules
Part 3: Settings UI — DONE
frontend/components/settings/WebhooksSettingsTab.tsx
NEW — Shows workspace webhook URL with copy button, example POST, field docs
✅
frontend/components/settings/SettingsPanel.tsx
Added Webhooks tab (5-column layout)
✅
frontend/components/workspace-provider.tsx
Added webhookUrl and webhookKey to Workspace interface + state mapping
✅
Files Modified (Complete List)
Modified (11 files)
frontend/components/settings/SettingsPanel.tsx
+8 -6
frontend/components/workflows/create-recipe-modal.tsx
+2 -1
frontend/components/workflows/recipe-schedule-config.tsx
+130 -200 (rewrite)
frontend/components/workspace-provider.tsx
+4
frontend/hooks/use-recipe-form.ts
+15 -8
orchestrator/api/workflow_recipes.py
+10
orchestrator/api/workspaces.py
+14 -2
orchestrator/core/auth/hybrid.py
+5 -2
orchestrator/core/models/routing.py
+1
orchestrator/core/models/workspaces.py
+3
orchestrator/main.py
+2
New (4 files)
frontend/components/settings/WebhooksSettingsTab.tsx
Webhooks settings tab UI
orchestrator/alembic/versions/20260213_add_workspace_webhook_key.py
Database migration
orchestrator/api/webhooks.py
General workspace webhook endpoint
orchestrator/core/routing/ingestors/webhook.py
Webhook ingestor (BaseIngestor subclass)
API Reference
Recipe Webhook
Workspace Webhook
Security Considerations
Webhook key entropy
128-bit random hex (uuid4().hex = 32 hex chars) — brute force infeasible
Key in URL
Standard webhook pattern (GitHub, Stripe, Slack all do this). HTTPS encrypts the URL in transit.
No auth headers
By design — URL-as-secret is simpler for webhook integrations
Key rotation
Not yet implemented — would need a rotation endpoint + grace period
Rate limiting
Not yet implemented — unauthenticated endpoints should have per-key throttling
Key exposure
Only returned to authenticated workspace members via /api/workspaces/current
What's Left To Do
Pre-Release (Required)
Post-Release (Follow-up)
Test Plan
1. Recipe Webhook (Create + Trigger)
2. General Workspace Webhook (Route to Agent)
3. No Composio Errors
4. Edge Cases
Empty body:
curl -X POST {url} -d '{}'— should route with content"{}"Invalid workspace key:
curl -X POST /api/webhooks/ws/nonexistent— should return 404Invalid recipe webhook_id:
curl -X POST /api/webhooks/recipe/nonexistent— should return 404Recipe with no steps: should return gracefully (no crash)
Workspace with no agents/routes: should return
{ routed: false }
5. Migration
Relationship to Other PRDs
PRD-36 (Composio)
Composio triggers still work when source = "composio". This PRD makes Composio optional, not removed.
PRD-37 (SaaS Foundation)
Extends workspace model with webhook_key. Uses existing auth/provisioning flow.
PRD-39 (Mem0)
No direct relationship. Webhook-triggered agent executions will use memory if agent has Mem0 configured.
Last updated

