Webhook triggers

You can trigger RWX runs from webhooks from third-party services. This is helpful for using RWX to run custom automation, like handling a PagerDuty or Datadog webhook.

Defining a webhook trigger

Webhook triggers are defined in the on section of your run definition. Here's an example:

on:
  webhook:
    - key: my-webhook
      init:
        headers: ${{ event.webhook.headers }}
        body: ${{ event.webhook.body }}

tasks:
  - key: verify-signature
    run: ...
    env:
      HEADERS: ${{ init.headers }}

  - key: your-automation
    after: verify-signature
    run: jq -r '.someField' < "$BODY"
    env:
      BODY: ${{ init.body }}

Key

The webhook's key is required and must be unique within your entire organization. The key will be used to construct the webhook URL and to display the webhook trigger in the Cloud UI.

The webhook URL will follow this pattern: https://cloud.rwx.com/webhooks/{org-slug}/{webhook-key}

Event context

Webhook triggers provide access to the incoming HTTP request through the event.webhook context. The event.webhook context cannot be accessed from tasks directly. You must pass the event data through as init parameters.

event.webhook.headers

A JSON string containing the HTTP headers from the incoming webhook request. RWX accepts request headers that match the pattern /\A[A-Za-z0-9-]+\z/ (alphanumeric characters and dashes only). These headers will be exposed with header names lowercased and dashes preserved.

For example, a header named X-Custom-Header will be accessible as x-custom-header upon parsing the headers JSON.

event.webhook.body

A string containing the request body from the incoming webhook request.

Title

You can override the default title of your run by specifying the title. It accepts an expression and can use the event context. For example:

on:
  webhook:
    - key: my-webhook
      init:
        headers: ${{ event.webhook.headers }}
        body: ${{ event.webhook.body }}
      title: Incident ${{ json(event.webhook.body)['incidentId'] }}

Target

If you only want to run certain tasks when the run is triggered by a webhook, you can specify a target.

on:
  webhook:
    - key: my-webhook
      init:
        headers: ${{ event.webhook.headers }}
        body: ${{ event.webhook.body }}
      target: send-notification

If you want to target multiple tasks, pass them as an array.

on:
  webhook:
    - key: my-webhook
      init:
        headers: ${{ event.webhook.headers }}
        body: ${{ event.webhook.body }}
      target: [post-to-slack, post-to-discord]

Conditional execution

You can use an if condition to control whether a webhook should trigger a run. For example, you might only want to run your automation when a specific event type is present:

on:
  webhook:
    - key: my-webhook
      if: ${{ json(event.webhook.body)['event_type'] == 'deployment' }}
      init:
        headers: ${{ event.webhook.headers }}
        body: ${{ event.webhook.body }}

You can use the json() function to parse the webhook body and access specific fields. If the condition evaluates to false, the webhook request will be acknowledged but no run will be created.

Authentication

Webhook endpoints are exposed over the public internet. To protect against random traffic and URL scanning, RWX generates a unique authentication token for each webhook trigger.

Setting up webhook authentication

  1. Define the webhook trigger in your RWX run definition and push it to your remote repository
  2. Retrieve the token from the webhooks page in RWX
  3. Configure the token in the external service where you're setting up the webhook

The token is a randomly generated hexadecimal string that must be included as the x-rwx-webhook-token header when sending requests to your webhook endpoint.

Webhook management

Webhooks can be managed from the webhooks page in RWX.

  • Multiple active tokens: You can have multiple active tokens for a single webhook trigger, which enables token rotation without downtime. This allows you to generate a new token, update your external service configuration, and then revoke the old token.
  • Token revocation: You can revoke tokens at any time. Once revoked, requests using that token will be rejected.
  • Pausing webhooks: You can pause a webhook at any time. When paused, incoming webhook requests will be acknowledged (returning a successful response), but no run will be started. This is useful for temporarily disabling a webhook without having to reconfigure the external service.

Testing

Via CLI

You can test your webhook via the command line using fixtures like so:

rwx run .rwx/my-webook.yml \
  --init "headers=$(cat headers-fixture.json)" \
  --init "body=$(cat body-fixture.json)"

Feature branches

You can test webhook triggers on feature branches before merging to your main branch. To do this, append a ref query parameter to your webhook URL:

https://cloud.rwx.com/webhooks/{org-slug}/{webhook-key}?ref={branch-name}

When invoked with a ref, RWX will look up the webhook trigger definition on the specified git ref and use that branch's configuration. If a ref isn't specified, the default branch (e.g main) on your repository will be used.

Security considerations

The event.git context reflects the git ref used to look up the webhook trigger definition. The specified ref will also be used to populate the event.git context and to unlock vaults.

When handling webhook data, be mindful of security implications:

  • Validate webhook payloads within your tasks before taking sensitive actions
  • Use locked vaults for sensitive workflows that should only be triggered from trusted branches
  • Be cautious with user-controlled data from webhook payloads, especially when using it in commands or API calls