> ## Documentation Index
> Fetch the complete documentation index at: https://docs.overcut.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Events in Workflows

> Trigger workflows from a workspace Custom Event, filter on the incoming payload, and access event data in downstream steps.

Once a workspace admin has [defined a Custom Event](/docs/integrations/custom-events) and the event's allowlist includes your project, the event is available in your workflow's trigger picker exactly like any built-in trigger. This page covers the workflow-author side: picking the event, filtering on payload fields, and reading event data in agents and actions.

For setup, authentication, and the webhook contract, see [Custom Events (Integrations)](/docs/integrations/custom-events) and the [API reference](/docs/reference/custom-events-api).

## Pick a Custom Event in the trigger picker

<Steps>
  <Step title="Open a workflow" icon="diagram-project">
    Open any workflow in the current project and select its <strong>Trigger</strong> container.
  </Step>

  <Step title="Add or edit a trigger card" icon="plus">
    Click <strong>Add trigger</strong> (or select an existing trigger card) to open the Properties panel.
  </Step>

  <Step title="Choose the event" icon="list">
    Open the <strong>Trigger event</strong> dropdown. Below the built-in groups (Issue, Pull Request, CI Workflow, Mention, Channel Message, Schedule, Slash Command, Manual), Custom Events appear grouped by their <strong>Category</strong>. Pick the event slug you want (for example, <code>deployment\_completed</code> under <strong>Deployments</strong>).
  </Step>

  <Step title="Add conditions (optional)" icon="filter">
    Use the conditions builder to filter on payload fields. See <a href="#filter-on-payload-fields">Filter on payload fields</a> below.
  </Step>
</Steps>

<Note>
  Only Custom Events whose allowlist includes the current project appear in that project's picker. If you expect an event to be available and it isn't, ask a workspace admin to add the project to the event's allowlist on the [Custom Events page](/docs/integrations/custom-events#change-scope-or-rename).
</Note>

## Filter on payload fields

The webhook body and any query-string parameters are exposed to trigger conditions under `payload.*`. Use dot notation for nested keys.

<Note>
  The `payload.*` scope is specific to Custom Events. Built-in event triggers (issue, pull request, CI workflow, etc.) match on `context.*` fields like `context.actor.type` or `context.repository.name` instead. The dispatcher also mirrors the body at `context.payload.*`, so `context.payload.environment` and `payload.environment` resolve to the same value.
</Note>

For a payload like:

```json theme={null}
{
  "environment": "production",
  "status": "success",
  "service": { "name": "api", "region": "us-east-1" }
}
```

You can write conditions like:

| Field                    | Operator     | Value        | Matches                   |
| ------------------------ | ------------ | ------------ | ------------------------- |
| `payload.environment`    | `equals`     | `production` | only production           |
| `payload.status`         | `notEquals`  | `cancelled`  | anything except cancelled |
| `payload.service.name`   | `equals`     | `api`        | only the api service      |
| `payload.service.region` | `startsWith` | `us-`        | any US region             |

Combine multiple conditions with `and` / `or` groups. The four well-known meta fields (`objectName`, `objectNumber`, `objectUrl`, `actor`) are also readable from `payload.*` even though Overcut also uses them for the run-list display.

Comparisons are case-insensitive: `payload.status == "Success"` matches `"SUCCESS"` and `"success"`. Missing fields short-circuit to a non-match: a condition on `payload.service.region` against a payload that has no `service` object simply does not fire.

The full list of operators (`equals`, `notEquals`, `contains`, `notContains`, `startsWith`, `endsWith`, `matches`, `in`, `notIn`) is documented in the [Trigger Execution reference](/docs/reference/trigger-execution).

## Improve the run's appearance

Without any payload hints, a Custom Event run shows the event's slug as its label (for example, `deployment_completed`) and has no click-through link. To make runs scannable, ask the sender to include the four well-known meta fields:

| Caller field   | Sets                             | Example                        |
| -------------- | -------------------------------- | ------------------------------ |
| `objectName`   | Run label in the runs list       | `"Deploy #1234 to production"` |
| `objectNumber` | Object number badge              | `"1234"`                       |
| `objectUrl`    | Click-through link from the run  | URL back to the source system  |
| `actor`        | The run's actor (shown as a Bot) | `"deploy-bot"`                 |

These are read by Overcut **and** still available to your conditions, so a single field like `objectName: "Deploy #1234 to production"` controls both the display and any rule that filters on it. See [Improve how runs appear in Overcut](/docs/integrations/custom-events#improve-how-runs-appear-in-overcut) for the sender-side details.

## Access event data in downstream steps

Once a trigger fires, the standard `trigger.*` template variables are populated from the well-known meta fields:

```handlebars theme={null}
{{trigger.eventType}}            → "custom_event"
{{trigger.triggerObjectName}}    → "Deploy #1234 to production"
{{trigger.triggerObjectNumber}}  → "1234"
{{trigger.triggerObjectUrl}}     → "https://github.com/..."
{{trigger.actor.login}}          → "deploy-bot"
```

The full payload is available under `trigger.payload.*`:

```handlebars theme={null}
{{trigger.payload.environment}}      → "production"
{{trigger.payload.service.name}}     → "api"
```

Use these in agent prompts, action parameters, conditional steps, and step outputs exactly like any other trigger variable. See the [Event Context Reference](/docs/reference/event-context#custom-event-properties) for the full list of fields available to a Custom Event workflow.

## One event, many workflows

The same Custom Event slug can drive any number of workflows in any allowed project. Each workflow evaluates its own trigger conditions independently against the same incoming payload. This is the standard pattern: define one `deployment_completed` event in the workspace, then have a "post to Slack" workflow, an "open changelog draft" workflow, and a "run smoke tests" workflow each filter for the deployments they care about.

## Concurrency: avoid duplicate runs

By default, every webhook call produces its own workflow execution: ten POSTs in a second produce ten runs (and ten parallel queued events per matching workflow). When that is wrong, the sender can pass `?lockKey=<scope>` to serialize:

* Requests sharing the same `(event, lockKey)` run one at a time.
* Within a short dedupe window, repeats collapse into a single queued execution per workflow.
* Different `lockKey` values run in parallel.

This is configured on the **sender** side, not in the workflow. See [Serialize concurrent calls with lockKey](/docs/integrations/custom-events#serialize-concurrent-calls-with-lockkey).

## Related

<CardGroup cols={2}>
  <Card title="Custom Events setup" icon="webhook" href="/docs/integrations/custom-events">
    Create an event, get a webhook URL, pick an auth mode, and wire your third-party tools.
  </Card>

  <Card title="API reference" icon="code" href="/docs/reference/custom-events-api">
    Full request and response contract: every header, query param, error code, and limit.
  </Card>

  <Card title="Event Context Reference" icon="brackets-curly" href="/docs/reference/event-context">
    All `trigger.*` template variables, including the Custom Event fields.
  </Card>

  <Card title="Advanced Trigger Execution" icon="gears" href="/docs/reference/trigger-execution">
    Operator list, event merging, priority queuing, and the Custom Event lock-key formula.
  </Card>
</CardGroup>
