Skip to main content
Event-based automations run when something happens, such as a webhook firing, instead of on a schedule. This is ideal for reacting to events from external services like Linear, Stripe, or Slack. This page applies to the local Agent Canvas and OpenHands Enterprise. The walkthrough starts with the local Agent Canvas.
For GitHub events such as pull requests, issues, and comments, OpenHands Enterprise has a built-in integration that needs no webhook registration. See GitHub Event Automations.

Built-In vs. Custom Integrations

Custom Webhooks

For services other than GitHub, such as Linear, Stripe, or Slack, register a custom webhook first, then create automations that use it.
Two-phase workflow for custom webhooks:
  1. Webhook registration (one-time setup): You execute the curl command yourself to register the webhook. This keeps your signing secrets secure—the agent provides the command but never handles your credentials directly.
  2. Automation creation (repeatable): Once the webhook is registered, the agent can create, update, and manage automations for that webhook source conversationally—no manual curl commands needed.

Before You Start on Agent Canvas

The external service sends events to your automation service over the internet, so a custom webhook needs a URL that the service can reach. A backend running on localhost is not reachable, so make it publicly reachable first:
  • Expose the Canvas ingress. Run Agent Canvas with --public and put a tunnel such as ngrok in front of its ingress (port 8000 by default). The bundled launcher starts both Agent Server and the Automation service behind this address. See VM / Self-Hosted Installation for the commands.
  • Use the ingress URL and its API key. Commands on this page call <Canvas ingress URL>/api/automation/v1/... with the shared key in the X-Session-API-Key header. Use the Host / Base URL from Manage Backends only if it points to this combined ingress. A standalone Agent Server does not serve /api/automation/*; its URL alone cannot receive automation webhooks.
Exposing the backend puts the whole agent server on the internet. Use a strong LOCAL_BACKEND_API_KEY, and do not share the API key or the webhook signing secret.
If you can’t expose your machine, use a cron-based automation that polls the service’s API on a schedule instead of a webhook.

Walkthrough: Linear Integration

This example sets up a Linear webhook that auto-triages new issues. The registration command has a tab for the local Agent Canvas and one for OpenHands Enterprise.

Step 1: Get Your Webhook Secret from Linear

Linear provides the webhook signing secret—you cannot configure your own.
  1. Go to Linear Settings → API → Webhooks
  2. Click New webhook
  3. Copy the signing secret that Linear displays (you’ll need this in the next step)
  4. Leave the webhook URL blank for now—you’ll get it from OpenHands

Step 2: Register the Webhook with OpenHands

The Canvas ingress serving both Agent Server and the Automation service must be reachable by the service that sends the events. Linear, Stripe, Slack, and similar services deliver webhooks from the internet, so they can’t reach localhost or a private network address. Expose the ingress with a tunnel or public URL first, as described in Before You Start on Agent Canvas, and use that public ingress URL as OPENHANDS_HOST below.
Export your public Canvas ingress URL, its shared API key, and the webhook secret from Step 1:
Then register the webhook:
Where do I find my backend API key? your-backend-api-key is the API key for your Agent Canvas backend. It is the same key that you enter in the API Key field in Manage Backends. How you find it depends on how the backend runs:
  • You set LOCAL_BACKEND_API_KEY: use that value.
  • Docker: use the LOCAL_BACKEND_API_KEY value you passed to the container. If you didn’t set one, the server generates a key. Check the container logs for it.
  • Default local backend: if Agent Canvas generated the key, it is stored in ~/.openhands/agent-canvas/api-key.txt. Run cat ~/.openhands/agent-canvas/api-key.txt to print it.
  • VM or self-hosted backend: use the LOCAL_BACKEND_API_KEY you configured on that machine. See VM / Self-Hosted Installation.
This key gives full access to the backend, so keep it private.
The webhook_url in the response is built from the automation service’s own address, so on a local backend it can start with http://localhost. External services can’t reach that address. In Step 3, keep the path (/api/automation/v1/events/<org_id>/linear) and replace the beginning with your public Canvas ingress URL.
The event_key_expr is a JMESPath expression that extracts the event type from incoming webhook payloads. This extracted value is what you match against in the automation’s on field.For example, Linear sends payloads like:
With event_key_expr: "type", the system extracts "Issue" as the event type. Then in your automation, you set on: "Issue" to match it.
If you’re integrating a service that lets you configure the signing secret (unlike Linear), you can omit webhook_secret from the request. The automation service will generate one and return it in the response—store it securely, as it’s shown only once.

Step 3: Complete the Linear Webhook Configuration

  1. Return to the Linear webhook you started in Step 1
  2. Paste the webhook_url from the previous step. On a local Agent Canvas, use the public version of the URL, as described in the note above
  3. Select which events to send (e.g., Issues, Comments)
  4. Save the webhook

Step 4: Create the Automation

Now the webhook is registered, the agent can create automations for you end-to-end. Just describe what you want. On Agent Canvas, you can do this in the setup assistant:
The agent creates the automation with:
  • Source: linear (your registered webhook)
  • Event: Issue (Linear’s event type)
  • Filter: action == 'create'

Filtering Events

Filters let you narrow which events trigger your automation. They use JMESPath expressions to match fields in the event payload—so you can trigger only on specific labels, users, branches, or other conditions.
OpenHands extends standard JMESPath with custom functions including icontains (case-insensitive string match) and glob (wildcard path matching). It also supports ! (negation), && (AND), and || (OR) as boolean operators. These extensions are not part of the JMESPath specification.
Common filter patterns:
  • contains(...) — match a specific label
  • icontains(...) — case-insensitive mention in a comment body
  • glob(...) — match repos in your org with wildcards
  • == — exact match (e.g., push to main branch only)
  • && — combine multiple conditions

Custom Webhook Parameters

When registering any custom webhook, these parameters define how OpenHands processes incoming events:

Common Services

These are example configurations for popular services. Always verify with each service’s webhook documentation, as signature headers and payload formats may change.

Next Steps

New to automations? Start with the Automations Overview for the bigger picture, including cron-based scheduling and general concepts.