Webhook Integration
Otto exposes a generic webhook endpoint that allows external systems to trigger tasks. When a webhook is received, Otto queues it for asynchronous processing, creates a task, and hands it to the AI...
Otto exposes a generic webhook endpoint that allows external systems to trigger tasks. When a webhook is received, Otto queues it for asynchronous processing, creates a task, and hands it to the AI agent.
What Webhooks Enable
Webhooks let you connect Otto to external services without building custom integrations. When an event happens in an external system -- a GitHub push, a Stripe payment, an incoming SMS -- that system sends a webhook to Otto, and Otto creates a task to handle it.
The agent receives a description of the event and decides what to do. This makes webhooks a flexible way to automate responses to external triggers.
Endpoint
| Parameter | Description |
|---|---|
webhook_type | A string identifying the source system (e.g., github, stripe, twilio, or any custom name) |
The webhook type is used to generate task titles and descriptions tailored to each source.
Request Format
Send a JSON payload in the request body. Any valid JSON is accepted:
If the body is not valid JSON, it is stored as a raw string under the raw_body key.
Response
A 200 response means the webhook was queued for processing. Task creation and agent execution happen asynchronously.
Processing Pipeline
- Receive: The webhook endpoint accepts the request and captures the payload, headers, URL, and client IP.
- Queue: The webhook data is placed in an internal message queue for asynchronous processing.
- Process: A background worker reads from the queue, creates an Otto task with a generated title and description, and submits it to an ARQ worker for agent execution.
- Execute: The AI agent works on the task, using the webhook payload as context.
- Notify: When the task completes or fails, notifications are sent through the appropriate channel (Slack thread, DM, or web UI).
Supported Webhook Types
Otto has built-in handling for several webhook types. Each type generates tailored task titles and descriptions.
GitHub (github)
Otto parses GitHub webhook payloads to extract repository names, actions, senders, PR titles, and commit counts.
| GitHub Event | Task Description |
|---|---|
| Pull request opened | "Process GitHub pull request opened by sender in repo: PR title" |
| Push | "Process GitHub push by sender to repo (N commits)" |
| Other events | "Process GitHub action event by sender in repository repo" |
Example payload from GitHub:
Stripe (stripe)
Otto extracts the event type and event ID from Stripe webhook payloads.
| Field | Used For |
|---|---|
type | Event type (e.g., payment_intent.succeeded) |
id | Event ID for tracking |
Task description: "Process Stripe event_type event (ID: event_id)"
Slack (slack)
For generic Slack events routed through the webhook system (separate from Otto's native Slack integration). Extracts channel and user information from the event payload.
Twilio (twilio)
Otto extracts the message SID, sender number, and message body from Twilio webhook payloads.
| Field | Used For |
|---|---|
From | Sender phone number |
Body | SMS message content |
MessageSid | Message tracking ID |
Task description: "Process Twilio message from from_number (SID: message_sid)"
The agent receives the full SMS content and can respond accordingly.
Generic (any other type)
For any unrecognized webhook type, Otto creates a task with: "Process webhook_type webhook event with payload containing N fields."
Use any string as the webhook type to organize your integrations:
Monitoring
Health Check
Returns the queue health status and statistics:
Statistics
Returns queue statistics and recent failed messages for debugging:
Processing Status
Returns whether the webhook background worker is running:
Security Considerations
Slack Webhooks
Slack requests include a signing secret verification header. Otto verifies the HMAC SHA256 signature using SLACK_SIGNING_SECRET and rejects requests with invalid signatures or timestamps older than 5 minutes.
GitHub Webhooks
GitHub supports webhook secrets for payload signing. To verify GitHub webhooks, configure a secret in your GitHub webhook settings and implement signature verification on your side (e.g., via a reverse proxy or middleware). Otto's generic webhook endpoint does not perform GitHub-specific signature verification out of the box.
Stripe Webhooks
Stripe provides webhook signing secrets for verifying payload integrity. Similar to GitHub, you should verify Stripe signatures at the network edge or add verification middleware if needed.
General Recommendations
- Place your Otto backend behind a reverse proxy (nginx, Cloudflare, etc.) and restrict webhook endpoint access by IP where possible.
- Use HTTPS for all webhook URLs.
- For sources that support it, configure webhook secrets and verify signatures.
- Monitor the
/webhook/statsendpoint for failed messages that could indicate unauthorized or malformed requests.
User Assignment
Webhook-created tasks are assigned to a system user (webhook@otto.local). This user is created automatically the first time a webhook is processed. If you need tasks assigned to specific users, the agent can reassign them based on the webhook payload content.
Troubleshooting
Webhooks are received but tasks are not created
- Check
/webhook/statsfor failed messages and their error details. - Verify that
REDIS_URLis set and Redis is reachable (the message queue depends on Redis). - Check backend logs for webhook processing errors.
Tasks are created but the agent does not run
- Verify that ARQ workers are running. Tasks are submitted to the
arq:interactivequeue. - Check that
DATABASE_URLandREDIS_URLare correctly configured.
External service is getting timeouts
- The webhook endpoint returns immediately after queuing. If the endpoint is unreachable, check that the backend is running and the URL is correct.
- Ensure port 8000 (or your configured port) is accessible from the external service.