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

# Triggers

> Learn about workflow triggers in Kwala

Triggers define when and how your Kwala workflows are activated. They are the "listening" mechanism that watches for specific events, conditions, or time intervals to automatically execute your workflows. Triggers eliminate the need for manual intervention or constant polling.

## Type of triggers in Kwala workflows

Kwala supports multiple trigger types that can be used individually or combined:

* **Event-based** - React to on-chain events in real-time
* **Time-based** - Execute workflows on a schedule
* **Recurring** - Continuously monitor and respond to events
* **API-based** - Start a workflow from an inbound HTTP request

## Event-based triggers

Event-based triggers listen for specific blockchain events and execute workflows when those events occur.

### Basic event trigger

The following example demonstrates a basic event-based trigger that monitors a smart contract on Ethereum mainnet for `Transfer` events. Whenever tokens are transferred from the specified contract, this trigger will activate the workflow.

```yaml theme={null}
trigger:
  triggerChainID: 1
  triggerSourceContract: "0x742d35Cc6e9A5f1e7A0e6FD4C8b2Bc3F5d9E1234"
  triggerSourceContractABI: '[{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]'
  triggerEventName: "Transfer"
```

This trigger will activate whenever a `Transfer` event is emitted from the specified contract.

### Filtered event trigger

The following example shows how to add filters to narrow down which events trigger your workflow. This configuration only activates when transfers come from a specific address and exceed 1 token in value, reducing unnecessary executions.

```yaml theme={null}
trigger:
  triggerChainID: 1
  triggerSourceContract: "0x742d35Cc6e9A5f1e7A0e6FD4C8b2Bc3F5d9E1234"
  triggerSourceContractABI: '[...]'
  triggerEventName: "Transfer"
  triggerEventFilter:
    from: "0xSpecificAddress..."
    value: ">1000000000000000000"  # Greater than 1 token
```

**Common Filter Operators:**

* Exact match: `"0xAddress..."`
* Greater than: `">value"`
* Less than: `"<value"`
* Range: `">=value,<=value"`
* Multiple values: `["value1", "value2"]`

## Time-based triggers

Execute workflows at specific times or intervals without requiring on-chain events.

### Interval-based execution

The following example configures a time-based trigger that executes the workflow every hour (3600 seconds). This is useful for periodic tasks like checking balances, updating oracle prices, or performing maintenance operations.

```yaml theme={null}
trigger:
  repeatEvery: "3600"  # Every hour (in seconds)
  triggerChainID: 1
```

**Common Intervals:**

* Every minute: `"60"`
* Every hour: `"3600"`
* Every day: `"86400"`
* Every week: `"604800"`

### Cron-style scheduling

The following example uses cron notation to schedule workflow execution at midnight every day. Cron patterns provide more flexibility for complex scheduling needs compared to simple intervals.

```yaml theme={null}
trigger:
  repeatEvery: "0 0 * * *"  # Every day at midnight
  triggerChainID: 1
```

**Common Cron Patterns:**

* Every day at 9 AM: `"0 9 * * *"`
* Every Monday: `"0 0 * * 1"`
* Every 6 hours: `"0 */6 * * *"`
* First day of month: `"0 0 1 * *"`

### Delayed execution

The following example delays workflow execution until a specific Unix timestamp is reached. This is useful for scheduled launches, time-locked operations, or coordinated events.

```yaml theme={null}
trigger:
  executeAfter: 1735689600  # Unix timestamp
  triggerChainID: 1
```

The following example delays execution until a specific block number is reached on the blockchain. This ensures precise timing based on block production rather than real-world time.

```yaml theme={null}
trigger:
  executeAfter: "block:18000000"  # After specific block
  triggerChainID: 1
```

## Recurring triggers

Recurring triggers continuously monitor for events and re-execute the workflow each time the event occurs.

The following example creates a recurring trigger that monitors a Polygon contract for deposit events where the amount exceeds 100 million (in the token's smallest unit). It checks every 60 seconds and executes the workflow each time a matching deposit is found.

```yaml theme={null}
trigger:
  recurringChainID: 137
  recurringSourceContract: "0xPolygonContract..."
  recurringSourceContractABI: '[...]'
  recurringEventName: "Deposit"
  recurringEventFilter:
    amount: ">100000000"
  repeatEvery: "60"  # Check every minute
```

This creates a persistent listener that:

1. Checks for new events every 60 seconds
2. Executes the workflow when matching events are found
3. Continues monitoring indefinitely

You can also drive the recurring flow over HTTP by setting `RepeatEvery: api`. This exposes a second HTTP endpoint, with its own method, authentication, and schema, that re-runs the workflow each time it is called. See [API triggers](#api-triggers-web2-triggers) below.

## API triggers (Web2 triggers)

API triggers start a workflow from outside the blockchain. Instead of waiting for an on-chain event, price movement, or time interval, the workflow exposes an HTTP endpoint that any Web2 app, backend, webhook, or manual request can call. When a valid request arrives, Kwala runs the workflow's actions on-chain.

Use an API trigger to:

* Start a workflow from a web/mobile app, a backend, or a cron job
* Turn a third-party webhook into an on-chain action
* Manually trigger a workflow for testing or ops
* Bridge any external system that can send an HTTP request into your Web3 automation

> [!NOTE]
>
> An API trigger swaps on-chain listening for an HTTP endpoint. Everything downstream — actions, execution mode, on-chain settlement — works like any other Kwala workflow.

![Web2 Trigger Canvas](https://mintcdn.com/kwala-1f7da9fb/46heWmtCb7UUUzkV/images/concepts/web2-trigger/web2-trigger-empty-canvas.png?fit=max\&auto=format\&n=46heWmtCb7UUUzkV\&q=85\&s=910ff303ab59d122cdfa1a1f79259856)

### The two flows

Every API trigger exposes two independent endpoints, configured separately:

* **One-time flow** (`ExecuteAfter: api`) — the primary trigger; its endpoint starts the workflow when called.
* **Recurring flow** (`RepeatEvery: api`) — an optional secondary trigger; its endpoint can be called repeatedly to re-run the workflow.

They don't have to match — for example, `POST` with no auth for the one-time flow, `PATCH` with Basic auth for the recurring flow.

> [!NOTE]
>
> `RepeatEvery` need not be `api`; it supports any trigger type (event, price condition, or time interval). Setting `RepeatEvery: api` simply means the recurring flow is also driven by an HTTP call.

### Configuration fields

Configure an API trigger from the **Trigger** panel in the Workflow Builder. Select **API** as the trigger type, then set the following.

**API method** — the HTTP method the endpoint accepts:

| Method | Typical use |
| - | - |
| GET | Trigger with no request body |
| POST | Trigger with a request body (most common) |
| PUT | Full-resource update payload |
| PATCH | Partial-update payload |
| DELETE | Removal or teardown action |

**Authentication type** — how Kwala verifies a request is allowed to trigger the workflow:

| Type | Description |
| - | - |
| None | No auth. Anyone with the URL can trigger. |
| Basic | HTTP Basic auth (username + password). |
| Bearer | Bearer token in the `Authorization` header. |
| APIKey | A key supplied in a request header. |
| JWT | A signed JSON Web Token validated on each request. |

> [!NOTE]
>
> Use `None` only for testing or public-safe endpoints. For any production endpoint that performs on-chain actions, always use `Basic`, `Bearer`, `APIKey`, or `JWT`.

**Response code** — the HTTP status Kwala returns to the caller when the request is accepted. All standard codes are supported (`2xx` success, `3xx` redirection, `4xx` client errors, `5xx` server errors); most workflows use `200 — OK`.

**API request schema** — the JSON shape Kwala expects in the request body. Write `"string"`, `"number"`, or `"boolean"` for a blank placeholder, or a real value to send it as-is.

**API response schema** — the JSON body Kwala returns to the caller after accepting the request.

> [!NOTE]
>
> **Schema value rules.** Inside a schema, strings are quoted and everything else is not (`age: 27`, `active: true`, `middleName: null`). The words `string`, `number`, and `boolean` are type placeholders — they generate blank fields and cannot be sent as literal values. Anything else is passed through exactly as written.

![Web2 Execute After configuration](https://mintcdn.com/kwala-1f7da9fb/46heWmtCb7UUUzkV/images/concepts/web2-trigger/web2-trigger-execute-after-filled-values.png?fit=max\&auto=format\&n=46heWmtCb7UUUzkV\&q=85\&s=bbd0026e2bc8530b0b1367671d90517c)

![Web2 Repeat Every configuration](https://mintcdn.com/kwala-1f7da9fb/46heWmtCb7UUUzkV/images/concepts/web2-trigger/web-trigger-repear-every-filled-values.png?fit=max\&auto=format\&n=46heWmtCb7UUUzkV\&q=85\&s=a1eeeac80c21ea030a4f38649da0f19d)

### Method examples

Each example configures the one-time flow with a different HTTP method, paired with a different authentication type and response code, so you can see the full range.

**1. GET with no authentication** — takes no request body, open to any caller. Suitable for a public, read-safe trigger or for testing.

```yaml theme={null}
Trigger:
TriggerAPIType: GET
TriggerAPIAuthType: NONE
TriggerAPIAuthConfig: NA
TriggerAPIResponseCode: 200
TriggerAPIResponseSchema:
  status: "accepted"
ExecuteAfter: api
```

**2. POST with Basic authentication** — accepts a request body, protected by HTTP Basic authentication, returns `201 — Created`.

```yaml theme={null}
Trigger:
TriggerAPIType: POST
TriggerAPIAuthType: Basic
TriggerAPIAuthConfig:
  username: user
  password: pass
TriggerAPIResponseCode: 201
TriggerAPIRequestSchema:
  name: "string"
  email: "string"
TriggerAPIResponseSchema:
  status: "accepted"
  userId: "number"
ExecuteAfter: api
```

**3. PUT with Bearer authentication** — carries a full-resource payload, requires a bearer token in the `Authorization` header, returns `200 — OK`.

```yaml theme={null}
Trigger:
TriggerAPIType: PUT
TriggerAPIAuthType: Bearer
TriggerAPIAuthConfig:
  token: your-bearer-token
TriggerAPIResponseCode: 200
TriggerAPIRequestSchema:
  orderId: "string"
  status: "string"
TriggerAPIResponseSchema:
  status: "updated"
ExecuteAfter: api
```

**4. PATCH with APIKey authentication** — carries a partial-update payload, requires an API key in a request header, returns `202 — Accepted`.

```yaml theme={null}
Trigger:
TriggerAPIType: PATCH
TriggerAPIAuthType: APIKey
TriggerAPIAuthConfig:
  keyName: X-Api-Key
  keyValue: devtr-your-api-key
  location: header
TriggerAPIResponseCode: 202
TriggerAPIRequestSchema:
  amount: "number"
TriggerAPIResponseSchema:
  status: "queued"
ExecuteAfter: api
```

**5. DELETE with JWT authentication** — initiates a teardown or removal action, validates a signed JSON Web Token on each request, returns `200 — OK`.

```yaml theme={null}
Trigger:
TriggerAPIType: DELETE
TriggerAPIAuthType: JWT
TriggerAPIAuthConfig:
  token: your-jwt-token
TriggerAPIResponseCode: 200
TriggerAPIRequestSchema:
  subscriptionId: "string"
TriggerAPIResponseSchema:
  status: "removed"
ExecuteAfter: api
```

### Generated YAML

After you configure the trigger in the builder, switch to the **YAML** toggle at the top of the editor to review the generated workflow definition. The following example shows a workflow with a `POST` one-time flow and a `PATCH` recurring flow.

```yaml theme={null}
Name: Testing_API_Trigger

Trigger:

# One-time (ExecuteAfter) flow
TriggerAPIType: POST
TriggerAPIAuthType: NONE
TriggerAPIAuthConfig: NA
TriggerAPIResponseCode: 200
TriggerAPIRequestSchema:
  name: "string"
  amount: "number"
TriggerAPIResponseSchema:
  status: "accepted"

# Recurring (RepeatEvery) flow
RecurringAPIType: PATCH
RecurringAPIAuthType: Basic
RecurringAPIAuthConfig:
  username: user
  password: pass
RecurringAPIResponseCode: 200
RecurringAPIRequestSchema:
  amount: "number"
RecurringAPIResponseSchema:
  status: "queued"

RepeatEvery: api
```

![Deployed workflow with yaml view](https://mintcdn.com/kwala-1f7da9fb/46heWmtCb7UUUzkV/images/concepts/web2-trigger/web2-trigger-yaml-view-with-deployment-success.png?fit=max\&auto=format\&n=46heWmtCb7UUUzkV\&q=85\&s=9fbb5911e61af55b4e6122eb39866ea8)

### Using trigger data in actions

A workflow started by an API trigger can read values from the incoming request body and pass them into its actions using `re.object(\"<field>\")`, written wherever an action expects a value. Kwala substitutes the matching field at run time.

Forward fields into an outbound API action:

```yaml theme={null}
APIPayload:
  customer: "re.object(\"name\")"
  age: "re.object(\"age\")"
  source: "kwala-workflow"   # fixed values pass through as written
```

Pass fields as contract-call arguments, in the order the function expects:

```yaml theme={null}
TargetFunction: function registerUser(string name, uint256 age)
TargetParams:
  - "re.object(\"name\")"
  - "re.object(\"age\")"
  - "10000"                  # references and constants can mix
```

Good to know:

* Types survive — a number arrives as a number, a boolean as a boolean.
* Nested objects and arrays come through whole; reference them once.
* The left-hand key is yours to rename; the argument inside `re.object()` is the field in the incoming body.
* References are **not** validated before deploy — a misspelled field compiles cleanly, then resolves empty or fails at run time. Check the Console Logs after your first test run.
* `GET` and `DELETE` carry no request body, so there is nothing for `re.object()` to read.

> [!NOTE]
>
> `re.object()` reads a named field from a JSON body (what an API trigger provides). Event triggers use `re.event()` for positional event data — different helpers for different input shapes.

### Lifecycle and expiry

Saving, compiling, and deploying an API trigger follows the same order as any workflow: **Save** stores the definition; **Compile** validates it as a dry run (nothing goes on-chain, and the button resets on any edit); **Deploy** puts it live, costs `0.001 KWALA`, and stays disabled until a clean compile. A duplicate workflow name blocks all three.

The workflow key in the trigger URL is your workflow name joined to your wallet address (`<name>_<wallet>`). It is generated at compile/deploy — do not construct it by hand.

> [!NOTE]
>
> API trigger workflows are automatically set to expire **1 day** after deployment. Redeploy to keep a long-running endpoint active.

### API trigger field reference

| Field | Required | Flow | Description |
| - | - | - | - |
| **TriggerAPIType** | Required | One-time | HTTP method: `GET`, `POST`, `PUT`, `PATCH`, or `DELETE` |
| **TriggerAPIAuthType** | Required | One-time | `NONE`, `Basic`, `Bearer`, `APIKey`, or `JWT` |
| **TriggerAPIAuthConfig** | Optional | One-time | Credentials for the chosen auth type (`NA` when `NONE`) |
| **TriggerAPIResponseCode** | Required | One-time | HTTP status code returned to the caller |
| **TriggerAPIRequestSchema** | Optional | One-time | JSON shape expected in the request body |
| **TriggerAPIResponseSchema** | Optional | One-time | JSON body returned to the caller |
| **RecurringAPIType** | Optional | Recurring | HTTP method for the recurring endpoint |
| **RecurringAPIAuthType** | Optional | Recurring | Authentication type for the recurring endpoint |
| **RecurringAPIAuthConfig** | Optional | Recurring | Credentials for the recurring endpoint |
| **RecurringAPIResponseCode** | Optional | Recurring | HTTP status code returned by the recurring endpoint |
| **RecurringAPIRequestSchema** | Optional | Recurring | JSON shape expected by the recurring endpoint |
| **RecurringAPIResponseSchema** | Optional | Recurring | JSON body returned by the recurring endpoint |
| **RepeatEvery** | Optional | Recurring | Set to `api` to drive the recurring flow via HTTP |

## Trigger expiration

Set an expiration to automatically stop trigger monitoring.

The following example configures a trigger that runs every hour but automatically stops monitoring at the specified Unix timestamp. This prevents indefinite execution and helps control costs.

```yaml theme={null}
trigger:
  triggerChainID: 1
  repeatEvery: "3600"
  expiresIn: 1735689600  # Unix timestamp when trigger stops
```

The following example shows how to set expiration as a duration in seconds (30 days = 2,592,000 seconds) rather than a specific timestamp. The trigger will automatically stop 30 days after deployment.

```yaml theme={null}
trigger:
  triggerChainID: 1
  repeatEvery: "3600"
  expiresIn: "2592000"  # Expires after 30 days
```

> [!NOTE]
>
> Expired triggers will not execute workflows, even if conditions are met. You'll need to redeploy or update the workflow to reactivate it.

## Combining triggers

You can combine different trigger types for more sophisticated workflows:

### Combine event and time-based triggers

You can use triggers to monitor events on multiple blockchains. The following example combines event-based and time-based triggers in a monitoring workflow. It watches for large transfer events but only between specific dates, checking every 5 minutes during the active period.

```yaml theme={null}
trigger:
  # Event-based trigger
  triggerChainID: 1
  triggerSourceContract: "0xContract..."
  triggerEventName: "LargeTransfer"
  
  # Time-based component
  executeAfter: 1735689600  # Only start monitoring after this date
  expiresIn: 1767225600     # Stop monitoring after this date
  
  # Recurring check
  repeatEvery: "300"  # Check every 5 minutes
```

### Multi-chain monitoring

The following example demonstrates cross-chain monitoring by tracking related events on both Ethereum and Polygon. This is useful for bridge monitoring, cross-chain messaging, or coordinating actions across multiple networks.

```yaml theme={null}
trigger:
  # Primary trigger on Ethereum
  triggerChainID: 1
  triggerSourceContract: "0xEthContract..."
  triggerEventName: "Bridged"
  
  # Also monitor on Polygon
  recurringChainID: 137
  recurringSourceContract: "0xPolygonContract..."
  recurringEventName: "Received"
  repeatEvery: "120"
```

## Trigger field reference

| Field | Required | Description |
| - | - | - |
| **TriggerChainID** | Required | The chain where the triggering event will occur |
| **TriggerSourceContract** | Optional | Contract address emitting the event |
| **TriggerSourceContractABI** | Optional | ABI of the trigger contract (if event-based) |
| **TriggerEventName** | Optional | Name of the event to listen for, for example, Transfer |
| **TriggerEventFilter** | Optional | Filters for the event (indexed values, sender, etc.) |
| **RecurringChainID** | Optional | If this is a repeating event, specify the chain |
| **RecurringSourceContract** | Optional | Contract emitting the recurring event |
| **RecurringSourceContractABI** | Optional | ABI for the recurring event contract |
| **RecurringEventName** | Optional | Name of the recurring event |
| **RecurringEventFilter** | Optional | Filter for recurring events |
| **RepeatEvery** | Optional | Cron notation or number of seconds for interval-based execution |
| **ExecuteAfter** | Optional | A specific block height or timestamp after which to run |
| **ExpiresIn** | Optional | Unix timestamp or seconds until the trigger becomes invalid |
| **ActionStatusNotificationPOSTURL** | Optional | Endpoint to notify about action status |
| **ActionStatusNotificationAPIKey** | Optional | API key for secure notifications |
| **Meta** | Optional | Optional metadata |

## Webhook notifications

Get notified about workflow execution status via webhooks.

The following example configures webhook notifications to receive real-time updates about workflow execution status. The workflow sends POST requests to your endpoint with execution details, status, and metadata.

```yaml theme={null}
trigger:
  triggerChainID: 1
  triggerSourceContract: "0x..."
  triggerEventName: "Transfer"
  
  # Webhook configuration
  actionStatusNotificationPOSTURL: "https://api.example.com/webhook"
  actionStatusNotificationAPIKey: "sk_live_abc123"
  meta: "Production webhook for transfers"
```

When your workflow executes, Kwala will send a POST request to your configured webhook endpoint with detailed information about the execution. The following example shows the structure of the webhook payload you'll receive, including workflow details, execution status, action results, and metadata.

```json theme={null}
{
  "workflowName": "Token Transfer Monitor",
  "executionId": "exec_abc123",
  "status": "success",
  "timestamp": 1735689600,
  "actions": [
    {
      "name": "Send Alert",
      "status": "completed",
      "gasUsed": "21000"
    }
  ],
  "metadata": {
    "chainId": 1,
    "triggerEvent": "Transfer"
  }
}
```

## Best practices

* **Choose the right trigger type**
  * Use **event-based** triggers for real-time reactions to on-chain events
  * Use **time-based** triggers for scheduled maintenance or batch processing
  * Use **recurring** triggers for continuous monitoring
  * Use **API-based** triggers to start workflows from external Web2 systems
* **Optimize check intervals** - Balance responsiveness with cost:
  * Critical monitoring: 30-60 seconds
  * Regular monitoring: 5-15 minutes
  * Batch processing: hourly or daily
  * More frequent checks consume more credits
* **Use filters effectively** - Add filters to reduce unnecessary workflow executions:
  * Filter by specific addresses
  * Filter by value thresholds
  * Filter by indexed event parameters
* **Set appropriate expirations** - Always set expiration dates to:
  * Prevent runaway costs
  * Ensure workflows don't run indefinitely
  * Allow for workflow updates and maintenance
* **Test triggers thoroughly**
  * Start with shorter intervals during testing
  * Verify filters match expected events
  * Confirm webhook notifications work correctly
* **Monitor webhook endpoints** - Ensure webhook endpoints are:
  * Always available (99.9%+ uptime)
  * Protected with API keys
  * Able to handle high request volumes
  * Responding quickly (\< 5 seconds)
* **Secure your webhooks** - Always use the `actionStatusNotificationAPIKey` field to secure webhook notifications. Never expose webhook URLs publicly without authentication:
  * Use API keys for all webhook endpoints
  * Validate webhook signatures in your backend
  * Use HTTPS for all webhook URLs
  * Implement rate limiting on webhook endpoints
  * Log all webhook calls for audit purposes
  * Set appropriate expiration dates

## Next steps

> **[Address Tracking](https://kwala.network/docs/concepts/address-tracking.md)**
>
> Monitor addresses for any on-chain activity

> **[Working with Actions](https://kwala.network/docs/concepts/actions.md)**
>
> Learn how to define workflow actions

> **[Workflow Execution](https://kwala.network/docs/concepts/workflow-execution.md)**
>
> Understand workflow execution flow

> **[Use Cases](https://kwala.network/docs/use-cases/low-wallet-balance-notifier.md)**
>
> See triggers in real-world scenarios


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