> ## Documentation Index
> Fetch the complete documentation index at: https://prismeai-legacy.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Automations

> Create powerful backend processes and workflows to orchestrate your AI applications

<Frame>
  <img src="https://mintcdn.com/prismeai-legacy/jdOgS9ouJy0zTcFo/images/ai-builder-nav.png?fit=max&auto=format&n=jdOgS9ouJy0zTcFo&q=85&s=8ef165633d24b75f5e155f7f894156e1" alt="AI Builder Automations Interface" width="3020" height="1498" data-path="images/ai-builder-nav.png" />
</Frame>

Automations are the core server-side processes that power your AI Builder applications. They define **what to do** and **when to do it**, allowing you to create sophisticated workflows, integrate with external systems, and build intelligent applications.

## Understanding Automations

<Tabs>
  <Tab title="What are Automations?">
    In simple words, **automations** describe **what to do** and **when**:

    * **What to do**: A sequence of **instructions** that process data and perform actions
    * **When to do it**: **Triggers** that activate the automation when specific conditions are met

    **Example:**

    A *HubspotDealsOnSlack* automation might send a notification message on Slack every time a new Hubspot deal is created:

    * The **what** would be a **fetch** instruction calling Slack API to send a message
    * The **when** would be a **URL** (webhook) trigger that Hubspot calls whenever a new deal is opened
  </Tab>

  <Tab title="Automation Architecture">
    Automations function within an event-driven architecture:

    * **Triggers**: Define when the automation runs (events, endpoints, schedules)
    * **Instructions**: Sequential steps that perform specific tasks
    * **Variables**: Store and manage data during automation execution
    * **Memory Scopes**: Different persistence layers for data (run, session, user, global)
    * **Output**: Final result returned to the caller or next automation

    This architecture enables complex workflows while maintaining flexibility and scalability.
  </Tab>
</Tabs>

## Triggers

Automations can be activated through different types of triggers, configured at the top of the automation graph:

<Accordion title="URL (Webhook/API Endpoint)">
  When an automation activates its **URL** trigger, it becomes publicly available through a URL which you can copy from your Workspace graph or source code. You can then use this URL in external services that support webhooks.

  From inside the automation, 5 variables give access to input HTTP requests:

  * **body**: Request body
  * **headers**: Request headers
  * **method**: HTTP method (GET, POST, etc.)
  * **query**: URL query parameters
  * **pathParams**: Extracted path parameter values (when using path parameters like `:id`)

  For multipart/form-data requests, uploaded files will be detailed within a `body.<fileKey>` object variable.\
  Example :

  ```json theme={null}
    {
      "originalname": "filename.pdf",
      "encoding": "7bit",
      "mimetype": "application/pdf",
      "size": 375966,
      "base64": "<file base 64>"
    }
  ```

  By default, these HTTP requests will receive the automation output as a response body. However, an **\$http** variable available inside the automation gives full control over the response:

  ```yaml theme={null}
  - set:
      name: $http
      value:
        headers:
          content-type: application/json
        status: 200
  ```

  You can also use this variable to implement [Server-Sent Events (SSE)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) for streaming responses:

  ```yaml theme={null}
  - set:
      name: $http
      value:
        chunk: # Data object that will be sent as an SSE event
          partial: "First part of response"
  - set:
      name: $http
      value:
        chunk: # Another chunk
          partial: "Second part of response"
  ```

  <Info>
    * **\$http** is only available in the URL-triggered automation (not in children calls)
    * Headers cannot be set after the first chunk is sent
    * When using SSE events, the automation output will also be sent as the last event
    * SSE automatically sets appropriate headers (Content-Type, Cache-Control, Connection)
  </Info>

  For long-running SSE endpoints, you can configure a keep-alive to avoid timeouts:

  ```yaml theme={null}
  - set:
      name: $http
      value:
        sseKeepAlive: 5000 # Keep-alive interval in milliseconds (minimum 5000ms)
  ```

  After this instruction, a `data: {"keepAlive": true}` chunk will be regularly emitted until the connection ends.

  ### Path Parameters

  Webhook endpoints support path parameters for building RESTful APIs. Path parameters allow you to define dynamic URL segments that extract values from incoming requests.

  **Basic Usage:**

  ```yaml get-user  theme={null}
  when:
    endpoint: "v1/users/:id"
  do:
    - set:
        name: output
        value:
          userId: "{{pathParams.id}}"
  ```

  When a request is made to `/webhooks/{workspaceSlug}/v1/users/123`, the automation receives:

  * `pathParams.id` = `"123"`

  **Multiple Parameters:**

  ```yaml get-user-post theme={null}
  when:
    endpoint: "v1/users/:userId/posts/:postId"
  do:
    - set:
        name: output
        value:
          user: "{{pathParams.userId}}"
          post: "{{pathParams.postId}}"
  ```

  Request to `/webhooks/{workspaceSlug}/v1/users/alice/posts/456` results in:

  * `pathParams.userId` = `"alice"`
  * `pathParams.postId` = `"456"`

  **Combined with Query and Body:**

  ```yaml update-user theme={null}
  when:
    endpoint: "v1/users/:id"
  do:
    - fetch:
        url: "{{config.apiUrl}}/users/{{pathParams.id}}"
        method: "{{method}}"
        body:
          name: "{{body.name}}"
          filter: "{{query.filter}}"
  ```

  <Info>
    **Path Parameter Behavior:**

    * Parameters are defined using `:paramName` syntax (e.g., `:id`, `:userId`)
    * All defined parameters are required - requests missing parameters will not match
    * Parameter values are automatically URL-decoded
    * Exact match endpoints take priority over pattern endpoints
    * When multiple patterns could match, the first defined pattern wins
    * Patterns like `message:stream` (colon without preceding slash) are treated as exact matches, not patterns
  </Info>

  <Warning>
    **Path parameters must be defined in the `endpoint` field, not in the automation slug.**

    The automation slug (e.g., `get-user`) only supports letters, numbers, spaces, underscores, and hyphens. To use path parameters, you must explicitly set the `endpoint` field to your desired path pattern:

    ```yaml theme={null}
        slug: get-user  # Slug without path parameters
        when:
          endpoint: "v1/users/:id"  # Path parameters defined here
    ```

    Using `endpoint: true` will expose the automation at the slug path, but the slug itself cannot contain `:` characters.
  </Warning>
</Accordion>

<Accordion title="Events">
  An automation can listen to a list of events. Whenever such events are received, the automation is executed and can access:

  * **payload**: Event payload data
  * **source**: Event source information (source IP, correlationId, userId, automation, etc.)

  These events can be:

  * **Native events**: Generated automatically by the platform
  * **Custom events**: Emitted from automations in the same workspace
  * **App events**: Emitted from installed Apps

  Example configuration:

  ```yaml theme={null}
  when:
    events:
      - user-login
      - document-uploaded
  ```

  <Info>
    Workspaces can only listen to a specific subset of native events. See the [Supported Native Events](#supported-native-events) section for details.
  </Info>
</Accordion>

<Accordion title="Schedules">
  An automation can be regularly triggered based on cron expressions:

  ```yaml theme={null}
  when:
    schedules:
      - '0 9 * * 1-5' # Run at 9:00 AM on weekdays
  ```

  <Info>
    * Automations can be scheduled at most every 15 minutes
    * Schedules use UTC timezone
    * When scheduled, the automation runs "on the hour" (e.g., a 20-minute schedule starting at 3:14 will run at 3:20, 3:40, etc.)
    * When successfully scheduled, a `runtime.automations.scheduled` event is emitted
  </Info>

  A helpful tool for creating cron expressions is [crontab.guru](https://crontab.guru/).
</Accordion>

## Memory Architecture

Automations can use and modify data across different memory scopes:

<AccordionGroup>
  <Accordion title="Run Scope">
    <Info>
      Available only during current execution
    </Info>

    Access pattern: `{{run.variable}}`
    Run variables include execution context like:

    * `run.date`: Current timestamp
    * `run.ip`: Client IP address
    * `run.automationSlug`: Current automation identifier
    * `run.correlationId`: Unique ID for tracing related events
    * `run.depth`: Current automation depth in the stacktrace
    * `run.trigger.type`: Trigger type (event, endpoint, automation)
    * `run.trigger.value`: Trigger value (event name, endpoint path, etc.)
    * `run.socketId`: Current socket ID if connected by websocket
    * `run.appSlug`: Current app slug if running from an appInstance
    * `run.appInstanceSlug`: Current appInstance slug if applicable
    * `run.parentAppSlug`: Parent app slug if parent is also an appInstance

    The run context is automatically removed 60 seconds after the last automation run.
  </Accordion>

  <Accordion title="User Scope">
    <Info>
      Persistent for the authenticated user
    </Info>

    Access pattern: `{{user.variable}}`

    User variables include:

    * `user.id`: Unique user identifier
    * `user.email`: User's email address
    * `user.authData`: Authentication information
    * `user.role`: User's role in the workspace
    * Custom user-specific data that persists across sessions
  </Accordion>

  <Accordion title="Session Scope">
    <Info>
      Available for the current user session
    </Info>

    Access pattern: `{{session.variable}}`

    Session variables include:

    * `session.id`: Current session ID
    * Custom session data

    Session variables store temporary user data:

    * Form inputs across multiple steps
    * Wizard progress state
    * Temporary preferences

    For authenticated users, session expiration is defined by the Gateway API (default 1 month).
    For unauthenticated endpoint calls, sessions expire after 1 hour of inactivity.
  </Accordion>

  <Accordion title="Global Scope">
    <Info>
      Shared across all users and executions
    </Info>

    Access pattern: `{{global.variable}}`

    Global variables include:

    * `global.workspaceId`: Current workspace ID
    * `global.workspaceName`: Current workspace name
    * `global.apiUrl`: Current API instance public URL
    * `global.studioUrl`: Current studio instance public URL
    * `global.pagesUrl`: Current workspace pages public URL
    * `global.pagesHost`: Current pages instance base domain
    * `global.endpoints`: Map of available endpoint slugs to URLs
    * `global.workspacesRegistry`: Map of public workspaces
    * Custom workspace-wide variables
  </Accordion>

  <Accordion title="Socket Scope">
    <Info>
      Available for the current websocket connection
    </Info>

    Access pattern: `{{socket.variable}}`

    Socket scope provides a temporary state local to a websocket connection, useful for separating state between multiple browser tabs. This context automatically expires after 6 hours without any updates.
  </Accordion>

  <Accordion title="Config Scope">
    <Info>
      Workspace and app configuration
    </Info>

    Access pattern: `{{config.variable}}`

    Contains the workspace configuration defined in the workspace settings.
  </Accordion>

  <Accordion title="$workspace Scope">
    <Info>
      Read-only workspace information
    </Info>

    Access pattern: `{{$workspace.variable}}`

    This read-only context holds the current workspace definition, allowing access to any of its sections (e.g., installed apps config via `$workspace.imports.myApp.config`).
  </Accordion>
</AccordionGroup>

<Info>
  Except for \$workspace, all these contexts can be written to using the `set` instruction. Written data will be persisted and available in subsequent requests. However, when setting variables inside session/user contexts from an unauthenticated webhook, they will not be persisted.
</Info>

## Working with Variables

Inside your automation instructions, dynamic data can be injected by surrounding a variable name with double braces: `{{some.variable.name}}`.

Variables can be created and modified using the [set instruction](#set-instruction) and removed using the [delete instruction](#delete-instruction).

For objects or arrays, you can access specific properties:

```yaml theme={null}
# Basic property access
{{user.profile.name}}

# Dynamic property access using another variable
{{session.myObjectVariable[{{item.field}}]}}
```

If `session.myObjectVariable` equals `{"mickey": "house"}` and `item.field` equals `mickey`, the entire expression resolves to `house`.

## Instructions

Once triggered, automations execute a sequence of instructions in order. Here are the available instructions:

### Logic Instructions

<AccordionGroup>
  <Accordion title="Condition" icon="code-branch">
    Conditionally execute instructions based on variable values or expressions.

    ```yaml theme={null}
    - conditions:
        '{{user.age}} >= 18':
          - set:
              name: status
              value: adult
        '{{user.age}} < 18':
          - set:
              name: status
              value: minor
        default:
          - set:
              name: status
              value: unknown
    ```

    [More details on condition syntax](#condition-syntax)
  </Accordion>

  <Accordion title="Repeat" icon="arrows-rotate">
    Loop through items or execute instructions multiple times.

    ```yaml theme={null}
    # Iterate through an array
    - repeat:
        on: '{{users}}'
        do:
          - set:
              name: processedUsers[]
              value: '{{item.name}}'

    # Execute a fixed number of times
    - repeat:
        until: 5
        do:
          - set:
              name: counter
              value: '{% {{$index}} + 1 %}'
    ```

    You can also process batches in parallel:

    ```yaml theme={null}
    - repeat:
        on: '{{workQueue}}'
        batch:
          size: 3  # Process 3 items by 3 items  in parallel
          interval: 500  # Pause 500ms between batches
        do:
          - process:
              item: '{{item}}'
    ```
  </Accordion>

  <Accordion title="Break" icon="stop">
    Stop execution of the current automation or loop.

    ```yaml theme={null}
    - break:
        scope: repeat  # Breaks out of the nearest repeat loop

    - break:
        scope: automation  # Stops the current automation

    - break:
        scope: all  # Stops all parent automations too
        payload:
          reason: "Operation cancelled"
    ```

    When `break` is meant to be handled from a parent automation's try/catch, `scope` must be set to `all`.

    If using the instruction like this : `- break: {}`, it will default to `scope: automation`.
  </Accordion>

  <Accordion title="All" icon="layer-group">
    Execute multiple operations in parallel.

    ```yaml theme={null}
    - all:
        - automation1: {}
        - automation2: {}
        - fetch:
            url: https://api.example.com/data
    ```
  </Accordion>

  <Accordion title="Try/Catch" icon="shield">
    Handle errors gracefully.

    ```yaml theme={null}
    - try:
        do:
          - riskyOperation: {}
        catch:
          - set:
              name: errorInfo
              value: "{{$error}}"
          - emit:
              event: operation-failed
              payload:
                error: "{{$error}}"
    ```

    The `$error` variable is accessible both inside and outside the `catch` block.
  </Accordion>
</AccordionGroup>

### Data Instructions

<AccordionGroup>
  <Accordion title="Set Instruction" icon="pen">
    Create or update variables in different scopes.

    <Tabs>
      <Tab title="Basics">
        ```yaml theme={null}
        # Simple variable assignment
        - set:
            name: greeting
            value: "Hello, world!"

        # Create or update object property
        - set:
            name: user.profile.firstName
            value: "Jane"
        ```
      </Tab>

      <Tab title="Objects">
        ```yaml theme={null}
        # Merge objects
        - set:
            name: settings
            type: merge
            value:
              theme: "dark"
        ```
      </Tab>

      <Tab title="Array">
        ```yaml theme={null}
        # Add item to array
        - set:
            name: users[]
            value: 
              id: 123
              name: "Jane Doe"

        # Add multiple items to array
        - set:
            name: users
            type: merge
            value:
              - id: 124
                name: "Alice"
              - id: 125
                name: "Bob"     
        ```
      </Tab>
    </Tabs>

    Like everywhere else, you can also use expressions in the value parameter:

    ```yaml theme={null}
    - set:
        name: counter
        value: '{% {{counter}} + 1 %}'
    ```
  </Accordion>

  <Accordion title="Delete Instruction" icon="trash">
    Remove variables when no longer needed.

    ```yaml theme={null}
    - delete:
        name: temporaryData
    ```
  </Accordion>
</AccordionGroup>

### Integration Instructions

<AccordionGroup>
  <Accordion title="Fetch Instruction" icon="globe">
    Make HTTP requests to external APIs.

    <Tabs>
      <Tab title="Basics">
        ```yaml theme={null}
          # Basic GET request
          - fetch:
              url: https://api.example.com/users
              method: GET
              headers:
                Authorization: Bearer {{secret.apiToken}}
              output: apiResponse
          
          # POST request with JSON body
          - fetch:
              url: https://api.example.com/users
              method: POST
              body:
                name: "New User"
                email: "user@example.com"
              output: createResponse
        ```
      </Tab>

      <Tab title="Output options">
        **`Retrieve response headers and status with outputMode: detailed_response :`**

        ```yaml theme={null}
            # Detailed response with headers
            - fetch:
                url: https://api.example.com/status
                outputMode: detailed_response
                output: fullResponse
            # Access `{{fullResponse.body}}`, `{{fullResponse.headers}}` and `{{fullResponse.status}}`        
        ```

        **`Other outputMode :`**

        * **base64** : return the base64 encoded response body
        * **data\_url** : return the response body encoded as a data\_url
      </Tab>

      <Tab title="multipart/form-data">
        ```yaml theme={null}
          - fetch:
              url: https://api.example.com/upload
              method: POST
              multipart:
                - fieldname: file
                  value: "{{fileContent}}" # Can be an ascii string, a base64 encoded string or a buffer array
                  filename: report.pdf # Required if value is a file
                  contentType: application/pdf
                - fieldname: metadata
                  value: "{{fileMetadata}}"
              output: uploadResult        
        ```
      </Tab>

      <Tab title="application/x-www-form-urlencoded">
        ```yaml theme={null}
          - fetch:
              url: '...'
              headers:
                Content-Type: application/x-www-form-urlencoded
              body:
                foo: bar
        ```
      </Tab>

      <Tab title="HTTP SSE (Server Side Events)">
        By default, HTTP responses indicating a `content-type: text/event-stream` header will force their **responseMode** to `detailed_response`, and their `{{output.body}}` will be a stream that can be read in real time from the calling automation :

        ```yaml theme={null}
        - fetch:
            url: "some SSE url (i.e openai /chat-completion endpoint)"
            output: output
        - repeat:
            'on': '{{output.body}}'
            do:
              - set:
                  name: test[]
                  value: '{{item}}'    
        ```

        Here, the `repeat` instruction will block until all chunks have been processed & the HTTP socket is closed.\
        Each `{{item}}` will look like this :

        ```json theme={null}
        {
          "chunk": {
            "data": [
              "data1",
              "data2"
            ]
          }
        }
        ```

        Here, `data1` and `data2` correspond to 2 individual chunks written by the remote server, which can be grouped together if they were received at the same time.\
        If these data strings are valid JSON, they will be automatically parsed into objects.

        Alternatively, we can `emit` received chunks so they can be processed asynchronously & concurrently from other automations :

        ```yaml theme={null}
        - fetch:
            url: ..
            stream:
              event: chunk
              payload:
                foo: bar
        ```

        Each chunk will be emitted like this :

        ```json theme={null}
        {
          "type": "chunk",
          "payload": {
            "chunk": {
              "data": [
                "data1",
                "data2"
              ]
            },
            "additionalPayload": {
              "foo": "bar"
            }
          }
        }
        ```

        An ending chunk can be specified with **endChunk** :

        ```yaml theme={null}
        - fetch:
            url: ..
            stream:
              event: chunk
              endChunk:
                foo: bar
        ```

        **stream** option also accepts **target** and **options** fields from emit instruction.
      </Tab>

      <Tab title="AWS SigV4">
        The `auth.awsv4` parameter allows configuring an access / secret access key pair to automatically sign your request with [**AWS Signature V4**](https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html) :

        ```yaml theme={null}
          - fetch:
              url: https://bedrock-runtime.eu-west-3.amazonaws.com/model/{{model}}/invoke
              auth:
                awsv4:
                  accessKeyId: ''
                  secretAccessKey: ''
                  service: bedrock
                  region: 'eu-west-3'
              method: POST
              body:
                inputText: Hello
              output: output
              emitErrors: true
        ```

        **service** and **region** are optional and automatically calculated from given url.
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Emit Instruction" icon="bolt">
    Trigger events for UI updates or other automations.

    <Tabs>
      <Tab title="Basics">
        ```yaml theme={null}
        - emit:
            event: user-registered
            payload:
              userId: "{{user.id}}"
              timestamp: "{{run.date}}"        
        ```
      </Tab>

      <Tab title="Target">
        ```yaml theme={null}
        - emit:
            event: user-registered
            payload:
              userId: "{{user.id}}"
              timestamp: "{{run.date}}"        
            target:
              userTopic: 'target user topic'        
              sessionId: 'target session id'
              userId: 'target user id'
        ```
      </Tab>

      <Tab title="Options">
        **Disable events persistence :**

        ```yaml theme={null}
        - emit:
            event: user-registered
            payload:
              userId: "{{user.id}}"
              timestamp: "{{run.date}}"        
            options:
              persist: false        
        ```
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Wait Instruction" icon="clock">
    Pause execution until a specific event is received.

    ```yaml theme={null}
    - emit:
        event: start-processing
        payload:
          documentId: "{{documentId}}"

    - wait:
        oneOf:
          - event: processing-complete
            filters:
              payload.documentId: "{{documentId}}"
        timeout: 30  # Defaults to 20 seconds
        output: processingResult
    ```
  </Accordion>

  <Accordion title="Rate Limit Instruction" icon="gauge">
    Control resource usage with rate limiting.

    ```yaml theme={null}
    - rateLimit:
        name: ExternalAPICall
        window: 60  # In seconds (1 minute)
        limit: 5    # Maximum 5 calls per minute
        consumer: "{{user.id}}"  # Per-user limit
        output: limits
    - conditions:
        "{{limits.ok}}":
          - fetch:
              url: https://api.example.com/data
        default:
          - emit:
              event: rate-limit-exceeded
              payload:
                retryAfter: "{{limits.retryAfter}}"
                limit: "{{limits.limit}}"
                window: "{{limits.window}}"
                remaining: "{{limits.remaining}}"
                consumer: "{{limits.consumer}}"
    ```
  </Accordion>
</AccordionGroup>

### Other Instructions

<AccordionGroup>
  <Accordion title="Auth Instruction" icon="key">
    Generate authentication tokens for internal API calls.
    This token cannot be used outside of automations, and is specifically intented for `fetch` consumption (as an **Authorization** header).

    ```yaml theme={null}
    - auth:
        workspace: true
        output: jwt
    - fetch:
        url: https://api.studio.prisme.ai/v2/workspaces/123/webhooks/someAutomation
        headers:
          Authorization: Bearer {{jwt.jwt}}
        output: apiResponse
    ```

    When fetching a Prismeai automation endpoint with such workspace token, a `{{run.authenticatedWorkspaceId}}` variable (which cannot be manually set) will be made available to securely check calling workspace.\
    You can also forward source workspace authentication to a subsequent fetch :

    ```yaml theme={null}
    - fetch:
        url: https://api.studio.prisme.ai/v2/workspaces/123/webhooks/someAutomation
        auth:
          prismeai:
            forwardWorkspaceAuth: true
        output: apiResponse
    ```
  </Accordion>

  <Accordion title="User Topic Instructions" icon="users">
    Manage user subscription topics.

    User topics allow sending events to multiple users without knowing who they are in advance, automatically granting them read access to these events without requiring any API Key.

    ```yaml theme={null}
    # Create a user topic
    - createUserTopic:
        topic: project-updates
        userIds: 
          - "{{user1Id}}"
          - "{{user2Id}}"

    # Add users to a topic
    - joinUserTopic:
        topic: project-updates
        userIds: # Defaults to current user.id
          - "{{newUserId}}"
    ```

    User topics allow sending events to multiple users without knowing who they are in advance.
  </Accordion>
</AccordionGroup>

### Run instruction

**Run** is a generic instruction allowing you to call **runtime modules**.\
These are lightweight NodeJS packages offering various methods for use cases needing raw Javascript for better performances than standard automations.

**Example :**

```yaml theme={null}
- run:
    module: collections
    function: create
    parameters:
      collection: 'someCollection'
      data: {}
    onError: break
    output: output
```

**Parameters :**

* **module** : Module name
* **function** : Function name
* **parameters** : Function parameters object
* **onError** : Exception handling behaviour
  * `break` will break current automation with given exception (default)
  * `emit` will emit an error event but continue current automation
  * `continue` will only return the error and continue current automation

#### Collections

Store, query, and manage structured data with MongoDB-style queries.
This module is generally meant to be used through the [**Collection** application](https://docs.prisme.ai/apps-store/marketplace/-collection).

<Card title="Collections Module Reference" icon="database" href="/products/ai-builder/module-collections">
  Functions: `create`, `findMany`, `updateOne`, `deleteOne`, `aggregate`, and more
</Card>

#### Secrets

Securely store and retrieve sensitive values (API keys, tokens, credentials) at runtime, with automatic redaction from logs.

<Card title="Secrets Module Reference" icon="key" href="/products/ai-builder/module-secrets">
  Functions: `set`, `get`, `delete` — scopes: `workspace`, `user`
</Card>

#### Access Manager

Manage organization service account tokens at runtime with in-memory secret caching and event-driven invalidation.

<Card title="Access Manager Module Reference" icon="user-shield" href="/products/ai-builder/module-access-manager">
  Functions: `getServiceAccountToken`, `createServiceAccount`, `rotateServiceAccountSecret`, `deleteServiceAccount`
</Card>

#### Text

Pure-JS text processing utilities for splitting text into chunks with configurable separators and overlap.

<Card title="Text Module Reference" icon="scissors" href="/products/ai-builder/module-text">
  Functions: `splitText`
</Card>

## Condition and Expression syntax

Conditions allow you to execute different instructions based on contextual information. You can use a powerful expression syntax in conditions and anywhere with `{% ... %}` delimiters.

### Basic Operators

```yaml theme={null}
# Comparison operators
{{someAge}} > 18
{{someAge}} >= 18
{{someAge}} < 18
{{someAge}} <= 18
{{someAge}} == 18
{{someAge}} = 18
{{cityName}} = "Toulouse"

# Inequality
{{someAge}} !== 18
{{someAge}} != 18

# String matching
"hello" matches "hel"
"hello" matches {{someArray}}

# Variable checking
{{testedVariable}}      # Is this variable defined?
!{{testedVariable}}     # Is this variable empty?

# Membership testing
{{someValue}} in {{someList}}
{{someKey}} in {{someObject}}
{{someKey}} not in {{someObject}}
{{someKey}} not in "my,string,list"

# Type checking
isArray({{someVariable}})
isObject({{someVariable}})
isString({{someVariable}})
isNumber({{someVariable}})
```

### Logical Operators

```yaml theme={null}
# AND operators
{{someAge}} >= 18 and {{cityName}} == "Toulouse"
{{someAge}} >= 18 && {{cityName}} == "Toulouse"

# OR operators
{{someAge}} >= 18 or {{cityName}} == "Toulouse"
{{someAge}} >= 18 || {{cityName}} == "Toulouse"

# Grouping with parentheses
{{someCity}} == "Paris" || ({{someAge}} >= 18 && {{cityName}} == "Toulouse")

# Negation
{{someCity}} == "Paris" || ! ({{someAge}} >= 18 && {{cityName}} == "Toulouse")
{{someCity}} == "Paris" || not ({{someAge}} >= 18 && {{cityName}} == "Toulouse")
```

### Regular Expressions

```yaml theme={null}
"luke.skywalker@gmail.com" matches regex("luke|skywalker")
"luke.skywalker@gmail.com" matches regex(/luke|skywalker/)
```

### MongoDB-like Conditional Matches

```yaml theme={null}
jsonmatch({{object}}, {{condition}})
```

Example condition:

```json theme={null}
{
  "$or": [
    {
      "test": "unknown"
    },
    {
      "one": {
        "$eq": "three"
      }
    }
  ]
}
```

### Deep merge objects

This functiun helps deep merge two objects.

```yaml theme={null}
deepmerge({{firstObject}}, {{secondObject}})
```

It also accepts an option object which can slightly modify the merge behaviour.

```yaml theme={null}
deepmerge({{firstObject}}, {{secondObject}}, {{options}})
```

Example options:

```json theme={null}
{
  "concatStrings": true // Rather than replacing string from the same keys, concatenate them if possible.
}
```

### Date Functions

#### Parsing and Access

```yaml theme={null}
date("2022-04-13T08:00:05.493Z").hour == 8
date({{mydate}}).minute > 34 && date({{mydate}}).minute < 37
date({{mydate}}).second >= 5
date({{mydate}}).date == 23
date({{mydate}}).month >= 6 && date({{mydate}}).month < 10
date({{mydate}}).year == 2022
date({{mydate}}).day == 3
date({{mydate}}).day in {{allowedDays}}
date({{mydate}}).ts == 1649836805493
date({{mydate}}).iso == '2022-04-13T08:00:05.493Z'
```

Note: Tested values are UTC based, and day starts on 0 for Sunday (so 3 is Wednesday).

#### Formatting

```yaml theme={null}
date("2023-03-31T17:07:23.975Z", "l") == "3/31/2023"
date("2023-03-31T17:07:23.975Z", "DD/MM/YYYY") == "3/31/2023"
date("2023-03-31T17:07:23.975Z", "LT") == "7:07 PM"
date("2023-03-31T17:07:23.975Z", "LT", "fr") == "19:07"
date("2023-03-31T17:07:23.975Z", "lll", "fr") == "31 mars 2023 19:07"
date("2023-03-31T17:07:23.975Z", "l LT") == "3/31/2023 7:07 PM"
date("2023-03-31T17:07:23.975Z", "LT", "fr", "America/New_York") == "13:07"
```

See all formatting options on [Day.js documentation](https://day.js.org/docs/en/display/format).

### Math Functions

#### Operators

```yaml theme={null}
1+1
1+{{someVariable}}
{{firstVar}} * {{secondVar}}
({{firstVar}} * {{secondVar}} + 10) / 2
```

#### Functions

```yaml theme={null}
rand(50, 150)  # Random number between 50 and 150
rand()  # Random float between 0 and 1

number("42")  # 42 — parse a string to integer

round(10.2)  # 10
round(10.2, 1)  # 10.2
round(10.26, 1)  # 10.3

floor(10.9)  # 10
floor(10.26, 1)  # 10.2

ceil(10.1)  # 11
ceil(10.9)  # 11
```

### String Functions

````yaml theme={null}
# convert string to lower case
lower({{foo}})

# convert string to upper case
upper({{foo}})

# Truncate string
truncate({{str}})
truncate({{str}}, 42)
truncate({{str}}, 42, ' etc')
truncate({{str}}, {{len}}, {{ellipsis}})

# JSON parsing/stringifying
json('{"foo": "bar"}')  # Object { foo: "bar" }
json({"foo": "bar"})  # String '{"foo":"bar"}'

# Unsafe JSON parsing: never raises exception, try to extract a JSON object or array when surrounded by other text
unsafejson('Voici un tableaux: ["un"] !') # ["un"]
unsafejson('Voici un objet :\n ```{"un": 1}```\n !') # {"un": 1}

# String manipulation
split('one,two,three', ',')  # Array ["one", "two", "three"]
join(['one', 'two', 'three'], ',')  # String "one,two,three"
replace('hello world', 'world', 'there')  # String "hello there"

# Array slicing
slice({{myArray}}, 0, 3)    # First 3 elements
slice({{myArray}}, 2)       # From index 2 to end
slice({{myArray}}, 0, -1)   # All except the last element

# Sanitize html
sanitize('<b>Bonjour <u>toi</u></b> !') # &#60;b&#62;Bonjour &#60;u&#62;toi&#60;/u&#62;&#60;/b&#62; !

# Remove complex unicode characters (non BMP, non UTF16 surrogates)
sanitize('Bonjour 🌍 ! Ça va ? 我爱你 ❤️') # Bonjour  ! Ça va ? 我爱你 ❤️

# Base64 encoding
base64("Hello World")  # String "SGVsbG8gV29ybGQ="
base64({{someBuffer}})  # Base64 encode a buffer variable

# Generate a random UUID (without dashes)
uuid()  # String "550e8400e29b41d4a716446655440000"
````

### URL parsing

Parse URL search params :

```
URLSearchParams("key1=value1&key2=value2").asJSON  # Object
URLSearchParams({foo: "bar", abc: "xyz"}).asString  # String "foo=bar&abc=xyz"
```

Or parse a complete URL as an object :

```
URL("https://user:password@www.google.fr/some/path/?query=string&foo=bar#anchor")
```

This returns :

```json theme={null}
{
  href: 'https://user:password@www.google.fr/some/path/?query=string&foo=bar#anchor',
  origin: 'https://www.google.fr',
  protocol: 'https:',
  username: 'user',
  password: 'password',
  host: 'www.google.fr',
  hostname: 'www.google.fr',
  port: '',
  pathname: '/some/path/',
  search: '?query=string&foo=bar',
  searchParams: { "query": "string", "foo": "bar" },
  hash: '#anchor'
}
```

Or directly access a specific field :

```
URL("https://user:password@www.google.fr/some/path/?query=string&foo=bar#anchor").hostname # www.google.fr
```

## Arguments

When calling a native instruction or another automation, different arguments can be transmitted. These graphical inputs are not reserved to native instructions, but can also be configured for your own custom automations by specifying expected arguments and their types.

```yaml theme={null}
testArguments:  
  do: []  
  name: testArguments
  arguments:
    someString:
      type: string
    someNumber:
      type: number
    someObject:
      type: object
      properties:
        someStringField:
          type: string
    someOtherObject:
      type: object
      properties:
        nestedObject:
          type: object
          properties:
            someField:
              type: number
    someStringArray:
      type: array
      items:
        type: string
    someObjectArray:
      type: array
      items:
        type: object
        properties:
          fieldA:
            type: string
    someRawJSON:
      type: object
      additionalProperties: true          
    someToken:
      type: string        
      secret: true
```

The `someToken` argument defined with `secret: true` is automatically redacted from native runtime events to avoid accidental leaks of sensitive information.

### Arguments Validation

Automation arguments can be validated during execution by enabling `validateArguments: true`:

```yaml theme={null}
slug: test
name: test
do: []
when:
  endpoint: true
output: '{{body}}'
arguments:
  body:
    type: object
    required:
      - str
    properties:
      str:
        type: string
      uri:
        type: string
        format: uri
      obj:
        type: object
        required:
          - un
        properties:
          un:
            type: string
            pattern: '^[a-z]+$'
validateArguments: true
```

Arguments support various validation formats including date, url, time, password, etc. Validation errors immediately stop current and parent automations.

## Advanced Automation Patterns

<Tabs>
  <Tab title="Webhook Handling">
    Implement secure webhook endpoints for third-party integrations:

    ```yaml theme={null}
    # Webhook automation
    slug: hubspot-webhook
    name: Hubspot Deal Created
    when:
      endpoint: true
    do:
      # Validate webhook signature
      - conditions:
          '!{{headers["x-hubspot-signature"]}}':
            - set:
                name: $http
                value:
                  status: 401
            - break:
                scope: automation
      
      # Process webhook data
      - set:
          name: newDeal
          value: "{{body.deal}}"
      
      # Notify team on Slack
      - fetch:
          url: "{{config.slackWebhookUrl}}"
          method: POST
          body:
            text: "New deal created: {{newDeal.name}} ({{newDeal.amount}})"
          output: slackResponse
      
      # Return success response
      - set:
          name: output
          value:
            success: true
            message: "Webhook processed successfully"
    ```
  </Tab>

  <Tab title="Data Processing Pipeline">
    Create multi-stage data processing workflows:

    ```yaml theme={null}
    # Document processing automation
    slug: process-document
    name: Process Document
    when:
      events:
        - document-uploaded
    do:
      # Parse document
      - set:
          name: documentUrl
          value: "{{payload.documentUrl}}"
      
      # Extract text with OCR
      - fetch:
          url: "{{config.ocrServiceUrl}}"
          method: POST
          body:
            url: "{{documentUrl}}"
          output: ocrResult
      
      # Classify document
      - fetch:
          url: "{{config.aiClassifierUrl}}"
          method: POST
          body:
            text: "{{ocrResult.text}}"
          output: classification
      
      # Store results
      - emit:
          event: document-processed
          payload:
            documentId: "{{payload.documentId}}"
            text: "{{ocrResult.text}}"
            category: "{{classification.category}}"
            confidence: "{{classification.confidence}}"
    ```
  </Tab>

  <Tab title="Multi-LLM Orchestration">
    Coordinate multiple AI models for complex tasks:

    ```yaml theme={null}
    # AI Orchestration
    slug: analyze-product-feedback
    name: Analyze Product Feedback
    when:
      events:
        - analyze-feedback-request
    do:
      # Categorize feedback
      - fetch:
          url: "{{config.llmApiUrl}}/chat-completions"
          method: POST
          body:
            model: "gpt-3.5-turbo"
            messages:
              - role: system
                content: "Categorize this product feedback into one of these categories: Bug, Feature Request, UX Issue, Praise, Other."
              - role: user
                content: "{{payload.feedbackText}}"
          output: categorization
      
      # Extract sentiment and key points
      - fetch:
          url: "{{config.llmApiUrl}}/chat-completions"
          method: POST
          body:
            model: "mistral"
            messages:
              - role: system
                content: "Analyze this product feedback and extract: 1) Sentiment (positive/negative/neutral), 2) Key points as bullet points, 3) Actionability score (1-10)"
              - role: user
                content: "{{payload.feedbackText}}"
          output: analysis
      
      # Store and notify
      - emit:
          event: feedback-analysis-complete
          payload:
            feedbackId: "{{payload.feedbackId}}"
            category: "{{categorization.choices[0].message.content}}"
            analysis: "{{analysis.choices[0].message.content}}"
    ```
  </Tab>
</Tabs>

## Supported Native Events

Workspaces can listen to a specific subset of native events:

<Accordion title="Workspace Events">
  <Properties>
    <Property name="workspaces.configured" type="event">
      Emitted when workspace configuration is updated

      Payload:

      ```json theme={null}
      {
        "config": "Config object from workspace.config"
      }
      ```
    </Property>

    <Property name="workspaces.deleted" type="event">
      Emitted when a workspace is deleted

      Payload:

      ```json theme={null}
      {
        "workspaceId": "workspace id"
      }
      ```
    </Property>

    <Property name="workspaces.imported" type="event">
      Emitted after import or repository pull

      Payload:

      ```json theme={null}
      {
        "files": ["index", "security", "pages/test.yml", "..."],
        "deleted": ["automations/removedAutomation.yml"],
        "version": {
          "name": "latest",
          "repository": { "id": "yourRepositoryId" }
        },
        "errors": [
          {
            "msg": "Could not rename workspace slug...",
            "err": "SlugAlreadyInUse",
            "conflictingWorkspaceId": "..."
          }
        ]
      }
      ```
    </Property>

    <Property name="workspaces.versions.published" type="event">
      Emitted when a new workspace version is committed

      Payload:

      ```json theme={null}
      {
        "version": {
          "name": "version name",
          "createdAt": "iso date",
          "description": "version description"
        }
      }
      ```
    </Property>

    <Property name="workspaces.versions.rollback" type="event">
      Emitted when a previous version has been rolled back

      Payload:

      ```json theme={null}
      {
        "version": {
          "name": "version name",
          "createdAt": "iso date",
          "description": "version description"
        }
      }
      ```
    </Property>

    <Property name="workspaces.pages.permissions.shared" type="event">
      Emitted when some page has been shared with someone

      Payload:

      ```json theme={null}
      {
        "subjectId": "<pageId>",
        "permissions": {
          "email": "<user email>",
          "policies": {
            "read": true
          },
          "id": "<user id>"
        }
      }
      ```
    </Property>

    <Property name="workspaces.pages.permissions.deleted" type="event">
      Emitted when someone's access to the page has been removed

      Payload:

      ```json theme={null}
      {
        "subjectId": "<pageId>",
        "userId": "<user id>",
        "email": "<user email>"
      }
      ```
    </Property>
  </Properties>
</Accordion>

<Accordion title="App Events">
  <Properties>
    <Property name="workspaces.apps.configured" type="event">
      Emitted when app instance configuration is updated

      Payload:

      ```json theme={null}
      {
        "appInstance": "AppInstance object from workspace.imports",
        "slug": "AppInstance slug"
      }
      ```
    </Property>

    <Property name="workspaces.apps.installed" type="event">
      Emitted when app instance is installed

      Payload:

      ```json theme={null}
      {
        "appInstance": "AppInstance object from workspace.imports",
        "slug": "AppInstance slug"
      }
      ```
    </Property>

    <Property name="workspaces.apps.uninstalled" type="event">
      Emitted when app instance is uninstalled

      Payload:

      ```json theme={null}
      {
        "appInstance": "AppInstance object from workspace.imports",
        "slug": "AppInstance slug"
      }
      ```
    </Property>

    <Property name="apps.published" type="event">
      Emitted when workspace is published as an app

      Payload:

      ```json theme={null}
      {
        "app": "App object"
      }
      ```
    </Property>

    <Property name="apps.deleted" type="event">
      Emitted when workspace app is unpublished

      Payload:

      ```json theme={null}
      {
        "appSlug": "Unpublished app slug"
      }
      ```
    </Property>
  </Properties>
</Accordion>

<Accordion title="Automation Events">
  <Properties>
    <Property name="workspaces.automations.created" type="event">
      Emitted when an automation is created

      Payload:

      ```json theme={null}
      {
        "automation": "Automation object",
        "slug": "Automation slug"
      }
      ```
    </Property>

    <Property name="workspaces.automations.updated" type="event">
      Emitted when an automation is updated

      Payload:

      ```json theme={null}
      {
        "automation": "Automation object",
        "slug": "Automation slug",
        "oldSlug": "Automation old slug in case of renaming"
      }
      ```
    </Property>

    <Property name="workspaces.automations.deleted" type="event">
      Emitted when an automation is deleted

      Payload:

      ```json theme={null}
      {
        "automationSlug": "Automation slug"
      }
      ```
    </Property>

    <Property name="runtime.automations.executed" type="event">
      Emitted when an automation completes execution

      Payload:

      ```json theme={null}
      {
        "automation": "automation slug",
        "workspace": "workspace id",
        "duration": 1250,
        "throttled": 0,
        "status": "success",
        "output": "automation output"
      }
      ```
    </Property>

    <Property name="runtime.automations.scheduled" type="event">
      Emitted when an automation is successfully scheduled

      Payload:

      ```json theme={null}
      {
        "slug": "automation slug",
        "schedules": ["*/15 * * * *"]
      }
      ```
    </Property>
  </Properties>
</Accordion>

<Accordion title="Runtime Events">
  <Properties>
    <Property name="runtime.fetch.failed" type="event">
      Emitted when a fetch receives a 4xx or 5xx HTTP status

      Payload:

      ```json theme={null}
      {
        "request": "fetchInstructionBody",
        "response": {
          "status": 500,
          "body": {},
          "headers": {}
        }
      }
      ```
    </Property>

    <Property name="runtime.webhooks.triggered" type="event">
      Emitted when a webhook is called

      Payload:

      ```json theme={null}
      {
        "workspaceId": "workspace id",
        "automationSlug": "webhook slug",
        "method": "http method"
      }
      ```
    </Property>

    <Property name="runtime.schedules.triggered" type="event">
      Emitted when a schedule is triggered

      Payload:

      ```json theme={null}
      {
        "workspaceId": "workspace id",
        "automationSlug": "automation slug",
        "schedule": "*/15 * * * *"
      }
      ```
    </Property>
  </Properties>
</Accordion>

## Best Practices

<AccordionGroup>
  <Accordion title="Modular Design" icon="cubes">
    Create maintainable automation structures:

    <ul>
      Break complex flows into smaller automations

      Use events for communication between modules

      Create reusable patterns for common tasks

      Document automation purposes and interfaces
    </ul>
  </Accordion>

  <Accordion title="Error Handling" icon="shield-check">
    Build robust fault tolerance:

    <ul>
      Use try/catch blocks for risky operations

      Implement appropriate retry strategies

      Provide informative error messages

      Create fallback paths for critical operations
    </ul>
  </Accordion>

  <Accordion title="State Management" icon="database">
    Handle data appropriately across scopes:

    <ul>
      Use appropriate memory scopes for different data needs

      Clean up temporary variables when finished

      Initialize variables before using them

      Be mindful of persistence requirements
    </ul>
  </Accordion>

  <Accordion title="Security Best Practices" icon="lock">
    Keep your automations secure:

    <ul>
      Store sensitive data in secrets

      Validate inputs from external sources

      Implement rate limiting for external APIs

      Use proper authentication for API calls
    </ul>
  </Accordion>

  <Accordion title="Performance Optimization" icon="gauge-high">
    Ensure efficient execution:

    <ul>
      Use parallel processing for independent operations

      Implement batching for large data sets

      Cache results when appropriate

      Monitor execution times and optimize bottlenecks
    </ul>
  </Accordion>

  <Accordion title="Testing" icon="vial">
    Validate automation functionality:

    <ul>
      Test with representative data samples

      Verify error handling paths

      Test edge cases and unexpected inputs

      Use Activity view to review execution history
    </ul>
  </Accordion>
</AccordionGroup>

## Next Steps

<AccordionGroup>
  <Accordion title="Blocks" icon="puzzle-piece">
    Learn about UI components that trigger automations
  </Accordion>

  <Accordion title="Pages" icon="file-code">
    Discover how to create interfaces for your applications
  </Accordion>

  <Accordion title="Deployment" icon="rocket">
    Learn more about deployment strategies
  </Accordion>
</AccordionGroup>
