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

# Data, entries, and routing

> Connect event sources, map variables, evaluate conditions, and keep existing trigger URLs

## Entry types

| Entry | Configuration | Available data |
| - | - | - |
| Webhook | `entry: { "kind": "webhook" }` | Request body, query, and allowed headers |
| Channel | `entry: { "kind": "channel", "event": "message.status" }` or `message.inbound` | A normalized channel event |
| Schedule | `entry: { "kind": "schedule", "cron": "0 9 * * 1-5", "timezone": "America/Sao_Paulo" }` | `body:scheduledAt`, `body:cron`, `body:timezone` |

Cron uses five fields: minute, hour, day of month, month, day of week. Select the timezone explicitly. Scheduled sections do not use entry `match` rules; add If blocks to decide what to do at execution time. Pausing disables new scheduled admissions.

An automation has token-bearing direct URLs for webhook and channel delivery. Copy them from the Portal; do not construct tokens or put them in source control. The channel entry accepts supported channel envelopes, not any arbitrary JSON with a field named `status`.

## Variables and input mappings

| Selector | Reads |
| - | - |
| `body:customer.id` | A field in the webhook body |
| `query:region` | A query parameter |
| `header:x-event-id` | A request header, case-insensitively |
| `event:providerMessageId` | A field in a normalized channel event |
| `steps:lookup.customerId` | Output from a prior step keyed `lookup` |
| `steps:contacts.item.id` | The current item inside a loop keyed `contacts` |

An empty selector path, such as `body:` or `steps:prepare`, can reference a whole value. Dot paths traverse object properties and numeric array indices. Sensitive authentication headers are removed from the execution context; do not depend on reading secrets through `header:`.

In a step's `input`, a bare selector resolves its value and preserves its type:

```json theme={null}
{ "customerId": "body:customer.id", "value": "steps:prepare" }
```

In an action field, use placeholders:

```json theme={null}
{ "key": "customer-{{body:customer.id}}" }
```

A placeholder occupying the entire string, such as `"{{steps:prepare}}"`, preserves the referenced value's type. Within surrounding text it becomes a string; objects are serialized. Missing/null values embedded in text become empty strings. Validate required fields before using them in keys, URLs, or recipients.

Mapped input names can create nested objects. For example, `"body.customerId": "body:id"` creates `input.body.customerId`. Action configuration and mapped inputs are different: a bare `body:id` in an action field is not automatically a selector.

## Conditions

Section `match` is an array of conditions, all of which must pass. A step's `when` and an If block's `action.when` use a condition group:

```json theme={null}
{
  "match": "all",
  "rules": [
    { "path": "steps:lookup.enabled", "operator": "equals", "value": true },
    { "path": "body:customer.id", "operator": "exists" }
  ]
}
```

| Operators | Meaning |
| - | - |
| `equals`, `notEquals` | Compare against a value; numeric comparisons can coerce numeric strings |
| `exists`, `notExists` | Test presence of a non-null value; an empty string still exists |
| `in`, `notIn` | Compare a value against a supplied list |
| `greaterThan`, `greaterThanOrEqual`, `lessThan`, `lessThanOrEqual` | Compare numeric values |

Use a Transform for stricter validation, normalization, non-empty strings, or a rule that is not one of these operators. `all` means every rule must pass; `any` means at least one must pass.

## Keep an existing trigger URL

An existing **production HTTP trigger** can route selected requests into an automation without changing its external URL or removing its original agent destination.

```mermaid theme={null}
flowchart TD
  T[Existing HTTP trigger URL] --> R{Request kind and routing conditions}
  R -->|Matching webhook| A[Dispatch automation]
  R -->|Meta status| S[Status automation]
  R -->|User message or nonmatching request| G[Original agent destination]
```

Configure the binding in automation settings or with `set_automation_trigger_route`:

* `entryKind: "webhook"`: select `allRequests: true` **or** a condition group such as `body:event equals notification.requested`.
* `entryKind: "channel"`: route Meta status events; currently requires `allRequests: true`. This binding is for statuses, not a general inbound-message router.
* Optional `auth`: compare a body/header/query selector against a named credential, without embedding its value in the definition.

A trigger can have a webhook automation and a different status automation. There is one destination per binding kind, not an arbitrary list of automations that all receive the same event. Within the selected automation, the first matching channel/webhook section is used. Mixed channel batches separate statuses from user messages at ingress.

Keep webhook conditions narrow when user conversations must stay with the agent. Calling an Agent block and separately forwarding the same request to the agent would duplicate processing.

> [!WARNING]
>
> A route to a paused, unavailable, or failing automation is not an automatic fallback to the original agent. Admission errors must remain visible so the sender can retry. To restore the original path, remove the corresponding binding deliberately; review work already accepted separately.

Rotating the automation token changes its direct URLs, not the existing trigger URL. Removing a binding affects new requests; it does not erase execution history or cancel accepted work.

## Channel events and message correlation

A status event exposes fields such as `status`, `providerMessageId`, `phone`, `conversationId`, `at`, `reference`, `errors`, and provider metadata when present. An inbound event can expose `text` and `contextMessageId`. Fields depend on what the provider supplies.

`sent`, `delivered`, `read`, and `failed` are different lifecycle events. Send acceptance is not delivery; a user clicking a button is an inbound interaction, not a read receipt.

For a notification that continues in an agent:

1. Send the notification and obtain `providerMessageId`.
2. Store context under that ID, using a documented KV or memory contract and an expiration policy.
3. Route status events to a separate automation that looks up the context and updates the external system.
4. Keep user messages with the agent, which reads the same context when the user replies.

Status routing can receive events for messages sent by either an automation or an agent. Missing correlation must have an explicit policy: skip business callbacks, record a diagnostic, or use another verified lookup. Do not invent identifiers or attribute a message to the latest campaign merely because its context is absent. Keep a general delivery-failure diagnostic independent of business correlation when needed.

## Environment and rule ownership

Automation definitions are workspace-level resources; they do not currently have the agent's staging/promotion lifecycle. Memory blocks select their environment explicitly, connector execution currently resolves production configuration, and messaging follows the configured connection. A `config.select` value does not switch the whole platform environment.

For isolated testing, use explicitly separate resources, connections, keys, and an inactive draft. Review every external destination before activation.

Define campaign identity, eligibility, allowed overrides, callback schema, and shared-state formats once in your integration design. Test both automation outputs and agent reads against that contract. Copying a business rule into two independently edited places will not keep them synchronized automatically.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.