Skip to main content

Overview

Workflows enable automation of actions based on triggers. A workflow consists of:
  • Trigger: What starts the workflow (e.g., an API request, a new log event, or a new autodiscovered resource)
  • Actions: What the workflow does when triggered (e.g., send a Slack message, call the Formal API)
Workflows are defined in YAML and can be managed via Terraform or the Formal API.

Triggers vs Actions

A workflow has exactly one trigger and one or more actions. Actions can be chained together using depends_on and conditionally executed using if.

Workflow Structure

depends_on - Action Chaining

The depends_on field controls the execution order of actions. Actions with empty depends_on run immediately after the trigger. Subsequent actions run after their dependencies complete.

Referencing Previous Trigger and Action Outputs

Actions can reference previous triggers and actions outputs via the following syntax in CEL expressions:
  • trigger.<output_field>: reference any output field of the trigger
  • actions.<action_name>.<output_field>: reference any output field of an action by its name
Some arguments, such as if or the api-request allow argument, take CEL expressions by default. For arguments that take strings instead, embed CEL expressions via the ${{}} syntax.

if - Conditional Execution

The if field is a CEL expression that determines whether a subsequent action should execute based on the previous actions or trigger.

Trigger Types

api-request

Triggered when a user calls the CreateWorkflowTrigger API endpoint. Useful for manually triggered workflows or integrations. Args: Outputs (available in actions): When the caller authenticates with an OIDC integration, user.oidc is also available: Example:
OIDC callers can reference verified claims directly instead of re-embedding them in payload:
Triggering via API:

new-log

Triggered when a new log event matches a specified condition. Useful for reacting to specific database queries, policy violations, or access patterns. Args: Outputs (available in actions): Example:

new-autodiscovered-resource

Triggered when a new resource is autodiscovered via cloud integration (AWS, GCP, etc.). Useful for automatically onboarding new databases. Args: None Outputs (available in actions): Example:

updated-autodiscovered-resource

Triggered when an existing autodiscovered resource is updated. Args: None Outputs (available in actions): Example:

deleted-autodiscovered-resource

Triggered when an autodiscovered resource is deleted because it no longer exists in the cloud provider. Args: None Outputs (available in actions): Example:

cron-schedule

Triggered on a recurring schedule defined by a standard 5-field cron expression (minute hour day-of-month month day-of-week). All times are evaluated in UTC. Useful for periodic checks, scheduled reports, and recurring maintenance tasks. Args: Outputs (available in actions): Example:
Recovery policy (optional): Under normal operation, cron triggers fire reliably every minute and recovery has no effect. It only matters in the unlikely event of a Formal platform outage where the workflow engine is temporarily unable to process scheduled triggers. When the platform recovers, any missed ticks are handled according to the recovery policy. If omitted, defaults to none. Missed triggers are capped at a 24-hour lookback window.
Cron schedules are always evaluated in UTC. To schedule at a local time, convert manually (e.g., 9am US Eastern = "0 14 * * *" during EDT or "0 13 * * *" during EST).

form-submission

Triggered when a user submits a Formal form via Slack. Useful for approval workflows, access requests, and other structured data collection scenarios. Args: Outputs (available in actions via trigger.form_submission): Example:
Referencing form values in actions:
See the Forms documentation for details on creating forms and the full Slack integration.

Action Types

send-slack-message

Sends a direct message to a Slack user or channel. Requires a Slack integration to be configured. Args: Outputs: Example:

ask-in-chat

Sends an interactive message with Yes/No buttons. The workflow pauses until the user responds. Args: Outputs: The user’s response triggers a webhook that continues the workflow with action-response. Example:

formal-app-command

Calls a Formal API endpoint using a machine user’s credentials. Args: Outputs: Example:

Terraform Examples

Next Steps

Policies

Learn about Formal policies for access control

Terraform Provider

Full Terraform provider documentation