# Discourse Workflows

**URL:** https://meta.discourse.org/t/discourse-workflows/407100
**Category:** Plugin
**Tags:** official, included-in-core, workflows
**Created:** [July 13, 2026, 1:54am UTC](https://meta.discourse.org/t/discourse-workflows/407100 "2026-07-13T01:54:16Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![lindsey](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/lindsey/32/318210_2.png) [@lindsey](https://meta.discourse.org/u/lindsey)
#### Post date: [July 13, 2026, 1:54am UTC](https://meta.discourse.org/t/discourse-workflows/407100/1 "2026-07-13T01:54:16Z")

</div>

| | | |
| --- | --- | --- |
| :discourse2: | **Summary** | **Discourse Workflows** lets admins create advanced automations through a visual builder to automate almost anything in your community. |
| 📖 | **Install Guide** | **This plugin is bundled with Discourse core**. There is no need to install the plugin separately. |

> [@](#):
>
> :discourse2: As this is an #official plugin maintained by the Discourse team, #Support, #Contribute > Bug, #Contribute > UX, and #Contribute > Feature requests can be made in the respective categories here on Meta. Click on a link below to get one started. 👍
> 
> [❓ **Support**](https://meta.discourse.org/new-topic?category_id=6&tags=workflows) [🐛 **Bug**](https://meta.discourse.org/new-topic?category_id=1&tags=workflows) [👀 **UX**](https://meta.discourse.org/new-topic?category_id=9&tags=workflows%22) [💡 **Feature**](https://meta.discourse.org/new-topic?category_id=2&tags=workflows)

Workflows is a visual automation builder that lets admins create advanced, multi-step automations using a drag-and-drop canvas — connecting triggers, conditions, actions, and flow-control nodes to automate almost anything on your Discourse site.

> :discourse: **Discourse Workflows** is available on the **Business** or **Enterprise** plans.

## Key concepts

If you’re familiar with other automation tooling, you will likely recognize most of the vocabulary used in Workflows:

- **Workflow** : A saved automation made up of connected nodes.
- **Node** : A single step in a workflow: triggers, conditions, actions, and flow-control / utilities.
- **Trigger** : The starting point of a workflow. A trigger can be manual or initiated by a specific event — topic being created, a schedule firing, or an incoming webhook.
- **Condition** : A routing node that evaluates a rule and splits the flow into branches. For example, an _If_ node routes the flow based on a true or false evaluation.
- **Action** : A node that does something specific — creating a post, granting a badge, calling an external API, etc.
- **Item** : The data that flows between nodes. Items are JSON objects that you can inspect in execution logs and reference using expressions.
- **Expression** : A dynamic value written as `{{ ... }}` that resolves at runtime and is used to reference data from earlier nodes, workflow variables, or site settings.

## Creating a workflow

To build a workflow:

1. Go to **Admin \> Plugins \> Workflows** and click New workflow.

 ![The New Workflow button on the Workflows tab.](https://global.discourse-cdn.com/meta/original/4X/7/5/6/7567a39bbcc611861023952a3f4fa1bb9aaf7230.png)

1. Name your workflow.
2. Click Add first step and choose your trigger.

 ![Naming and adding the first step to the new workflow.](https://global.discourse-cdn.com/meta/original/4X/8/7/2/87200e4dded9e84e91d59ac706b6b1444e3ba708.png)

1. Use the + button to add additional nodes.

 ![Click the "+" icon next to a node to add a new node.](https://global.discourse-cdn.com/meta/original/4X/1/c/0/1c08f8ad0de2eca53dcdb15c9c6baf3d87f97924.png)

1. Double-click on a node to configure it. In the configuration panel, details about inputs for the node will be shown on the left side and details about the outputs of the node will be shown on the right side of the screen. You may need to run the workflow once before seeing all the various details.

 ![The Edit Node page where you can configure how it should function in detail.](https://global.discourse-cdn.com/meta/original/4X/3/4/6/3468ac1e76229bd520c0879820fda2f8badadab0.png)

1. When you’re ready to go live, click Publish.

 ![The Publish button to launch the workflow.](https://global.discourse-cdn.com/meta/original/4X/7/c/0/7c09a76da204b8ba7da22a0ba1b273b06bcd8b16.png)

> 💡 **Tips:**
> 
> - Use **sticky notes** , located in the three-dot menu in the top right of the builder, to document what your workflow does. Stickies don’t have any effect on the workflow but make templates and shared workflows easier to understand.
> - Use the **log node** during development to send debug values into the execution log without impacting the workflow’s behavior.
> - You can **export and import** workflows as JSON to share them with teammates or recreate workflows from other sites.

### Expressions and dynamic data

Fields that accept expressions show a `{/}` button in the editor. Click it to browse available data from the trigger and earlier nodes and insert a reference.

#### Common expressions

| Expression | What it returns |
| --- | --- |
| `{{ $json.topic.title }}` | The title of the topic from the current item |
| `{{ $json.post.url }}` | The URL of the post from the current item |
| `{{ $json.user.username }}` | The username of the user associated with the current item |
| `{{ $vars.my_variable }}` | The value of a workflow variable named `my_variable` |
| `{{ $site_settings.title }}` | Your site’s title |
| `{{ $execution.id }}` | The unique ID of the current execution |
| `{{ $('Node Name').item.json.property }}` | Output from a specific upstream node, referenced by its canvas name |

#### Static and dynamic values

Fields that start with `=` are treated as expressions. Fields without a leading `=` are treated as plain text. The expression picker handles this for you automatically.

## Managing workflows

There are a number of features that help you manage your existing workflows.

### Executions

Every time a workflow runs, Discourse records an execution. Go to **Workflows → Executions** to see the history.

 ![The Executions log for a workflow.](https://global.discourse-cdn.com/meta/original/4X/5/9/8/598fd8358b41f677e87fb88e2cffb8418c09d73a.png)

Each execution shows the date and time when it was completed and its status:

- **Completed** : Ran to completion without error.
- **Error** : Failed at a specific node; click into the execution to see the error and the data that caused it.
- **Running** : Currently processing.
- **Waiting** : Paused due to a Wait node; waiting for a response in a form, modal, chat approval; or a Call Workflow node waiting for a sub-workflow to complete.
- **Rate limited** : The workflow was skipped due to rate limiting.
- **Skipped** : The trigger fired but the workflow was unpublished.

You can click the Show button for a more in depth look at the workflow’s execution. This shows each step of the workflow, which you can expand to view the exact details, and the duration of that step.

 ![The detailed log for a single execution of the workflow.](https://global.discourse-cdn.com/meta/original/4X/5/d/f/5dfa4f5f39411a2026edce1a7af467c20fd84c34.png)

At the bottom of the page, you can see the overall duration of the workflow. You can also Export the log if needed for sharing or troubleshooting purposes.

### Settings

On the **Workflows →**  **Settings** tab, you can:

- Configure an **error workflow** that should trigger if there are any failures when this workflow runs. If the workflow has an error trigger, it will handle errors as defined by that trigger.
- Set the **timezone** for schedule triggers. The workflow will default to using the site timezone if this is unset.
- **Delete the workflow**. ⚠ This is **permanent** so you should consider exporting your workflow (accessible in the three-dot menu on the top right corner of the workflow builder) before proceeding.

### Versions

Every time you make an update to the workflow, we’ll save the previous version(s). This makes it easy to Revert changes that didn’t work as you expected.

 ![The Versions tab lets you undo changes to your workflow with the Revert button.](https://global.discourse-cdn.com/meta/original/4X/b/e/5/be5b6262bb065a761e2673c54538b3593a9cabe2.png)

## Variables

Variables are key-value pairs scoped to a single workflow. Define them in the workflow’s **Variables** panel and reference them anywhere with `{{ $vars.key_name }}`. Use variables to store configuration values (like a category ID or a recipient username) that you want to be able to change without editing the workflow graph.

 ![The Variables table in Workflows lets you save commonly used key-value pairs for easy reference.](https://global.discourse-cdn.com/meta/original/4X/f/a/6/fa6d8cee5c5b39abad02e95ef90541ff0a08dda5.png)

## Credentials

Some nodes — like HTTP request or AI Agent — need to authenticate with external services. Store API keys and secrets in **Workflows → Credentials** rather than pasting them directly into node fields. Credentials are encrypted at rest and can be reused across workflows.

Supported credential types:

- **Basic Auth** (username + password)
- **Bearer token**
- **Header auth** (custom header name and value)

 ![The Credentials tab lets you add credentials that can be used by nodes in your workflows.](https://global.discourse-cdn.com/meta/original/4X/8/c/9/8c95b858ffd05da7d3baf4a88a9ee2459ea358b4.png)

## Data tables

Data tables are persistent, structured tables internal to the Workflows plugin. Use the **Data table** node to read from or write to them. They support `string`, `number`, `boolean`, and `date` column types.

Data tables are useful for:

- **Deduplication** — record which users or topics a workflow has already processed
- **State** — track whether a topic is in a particular stage of a process
- **Lookups** — store mappings (like topic ID → assigned staff member) that your workflows can query

 ![Data Tables can be referenced by workflows and can house the data created during a workflow for easy reference.](https://global.discourse-cdn.com/meta/original/4X/1/2/3/123634f078e7ffee97efd0b065eb9a5f3a55b187.png)

## Executions

You can view all the executions of all workflows from the **Executions** tab. The format and function is very similar to the workflow-specific executions, but shows across all workflows for easier monitoring.

 ![The Executions tab shows all the recent executions across all of your active workflows.](https://global.discourse-cdn.com/meta/original/4X/3/9/8/39817701e82b32ec21cce17643f162f2fb6509b6.png)

## Templates

When you create a new workflow, you can start from a **template** instead of a blank canvas. Templates are pre-built workflows for common use cases — they’re annotated with sticky notes explaining how they work and are a good way to learn the system.

> 📣 **Interested in seeing more templates?** We will work to expand the library of available templates over time, but please let us know if there’s a template that you’d like to see here to make your use of Workflows easier.

You can also export any workflow as a JSON file to share it with others or use it as your own starting point.

 ![The Templates tab shows workflow templates that you can select to jumpstart the workflow creation process.](https://global.discourse-cdn.com/meta/original/4X/a/2/6/a2617e6aa93202195ba608aa5e99eb60c4280409.png)

---

<div class="post-metadata">

### Author: ![patrickemin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/patrickemin/32/520162_2.png) [@patrickemin](https://meta.discourse.org/u/patrickemin)
#### Post date: [July 13, 2026, 6:28pm UTC](https://meta.discourse.org/t/discourse-workflows/407100/2 "2026-07-13T18:28:47Z")

</div>

Hi, when trying to activate this plugin I have the following error message: You do not have permission to change the hidden settings : discourse\_workflows\_enabled

---

<div class="post-metadata">

### Author: ![awesomerobot](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/awesomerobot/32/142900_2.png) [@awesomerobot](https://meta.discourse.org/u/awesomerobot)
#### Post date: [July 13, 2026, 8:40pm UTC](https://meta.discourse.org/t/discourse-workflows/407100/3 "2026-07-13T20:40:46Z")

</div>

At the moment it must be enabled from `/admin/config/upcoming-changes`, not `admin/plugins`

---

<div class="post-metadata">

### Author: ![patrickemin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/patrickemin/32/520162_2.png) [@patrickemin](https://meta.discourse.org/u/patrickemin)
#### Post date: [July 13, 2026, 9:40pm UTC](https://meta.discourse.org/t/discourse-workflows/407100/4 "2026-07-13T21:40:51Z")

</div>

Hi, if I understand the purpose of these Workflows correctly, one template example I wish is to add an admin button to topics that would immediately bump the topic. Feasible ? 😀

---

<div class="post-metadata">

### Author: ![dennisjbr](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/dennisjbr/32/444916_2.png) [@dennisjbr](https://meta.discourse.org/u/dennisjbr)
#### Post date: [July 29, 2026, 7:40am UTC](https://meta.discourse.org/t/discourse-workflows/407100/5 "2026-07-29T07:40:55Z")

</div>

Howdy!

How do we ensure that the “Build with AI” uses a particular LLM?  
When using Google Gemini as the default LLM in our system im getting the error: Invalid JSON payload received. Unknown name “additionalProperties” at ‘tools[0].function\_declarations[5].parameters’: Cannot find field

Thanks!

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [July 29, 2026, 10:01am UTC](https://meta.discourse.org/t/discourse-workflows/407100/6 "2026-07-29T10:01:21Z")

</div>

Which Gemini model are you using? To change it pick the workflow agent and swap the default llm on it

---

<div class="post-metadata">

### Author: ![dennisjbr](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/dennisjbr/32/444916_2.png) [@dennisjbr](https://meta.discourse.org/u/dennisjbr)
#### Post date: [July 29, 2026, 10:27am UTC](https://meta.discourse.org/t/discourse-workflows/407100/7 "2026-07-29T10:27:16Z")

</div>

Hey Sam! Gemini 3 Flash.

I found the workflow setting and it was indeed Gemini Flash 3. I moved to ti GPT Nano 5, and still get the same error.

I even changed default for everyone to GPT Nano 5 and checked the individual Workflow setting. Set that to override with GPT Nano 5 as well.

Still no dice. ☹

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [July 29, 2026, 10:41am UTC](https://meta.discourse.org/t/discourse-workflows/407100/8 "2026-07-29T10:41:21Z")

</div>

Any chance you have access to Luna or terra, or 3.5 flash or sonnet ?

The workflow ai agent has quite a few tools so if tend to require a recent llm

---

<div class="post-metadata">

### Author: ![dennisjbr](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/dennisjbr/32/444916_2.png) [@dennisjbr](https://meta.discourse.org/u/dennisjbr)
#### Post date: [July 31, 2026, 3:13am UTC](https://meta.discourse.org/t/discourse-workflows/407100/9 "2026-07-31T03:13:54Z")

</div>

I could have sworn Flash Lite worked, but it did not. GPT Nano 5 definitely worked. It looks like this is a known issue even with Wordpress. here is a link for reference. What we need to do is whenever we are using a Gemini provider, to remove the additionalProperties item from the JSON Response Schema: [Remove `additionalProperties` from the JSON response schema - Pull Request #18 - WordPress/ai-provider-for-google - GitHub](https://github.com/WordPress/ai-provider-for-google/pull/18)

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [July 31, 2026, 3:19am UTC](https://meta.discourse.org/t/discourse-workflows/407100/10 "2026-07-31T03:19:24Z")

</div>

yikes, I am spiking a move to interactions api, so I think this should give us a far more stable bridge into gemini models, hopefully next week.

---

<div class="post-metadata">

### Author: ![dennisjbr](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/dennisjbr/32/444916_2.png) [@dennisjbr](https://meta.discourse.org/u/dennisjbr)
#### Post date: [July 31, 2026, 3:24am UTC](https://meta.discourse.org/t/discourse-workflows/407100/11 "2026-07-31T03:24:04Z")

</div>

Awesome and thanks for the quick response! I found some more content but I think you get the idea. 😉

---

<div class="post-metadata">

### Author: ![dennisjbr](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/dennisjbr/32/444916_2.png) [@dennisjbr](https://meta.discourse.org/u/dennisjbr)
#### Post date: [July 31, 2026, 3:28am UTC](https://meta.discourse.org/t/discourse-workflows/407100/12 "2026-07-31T03:28:57Z")

</div>

This is Google’s own Gemini explanation. Hope it makes sense? I don’t get all of it, but I just know it chokes on that property. LOL.

**TL;DR:** The error persists because Google uses **two entirely different engines** for schema processing. While Gemini supports standard JSON Schema for **Structured Outputs** (`response_json_schema`), its **Function Calling / Tool Execution** engine still uses Google’s strict OpenAPI 3.0 Protobuf parser, which rejects or chokes on `additionalProperties`.

## 1. Tool Calling vs. Structured Output (The Engine Split)

Google’s Gemini API validates schemas in two separate places:

- **Structured Outputs (`response_json_schema`):** Designed for formatting the model’s final response. It uses standard JSON Schema parsing and handles `additionalProperties` cleanly.

- **Tool / Function Calling (`tools[0].function_declarations`):** Designed for passing site tools (like Discourse AI search, persona actions, or web browsing) to the model. This endpoint parses schemas into Google’s internal `google.ai.generativelanguage.v1beta.Schema` Protobuf object.

Because the tool endpoint maps parameters to a legacy OpenAPI 3.0 subset, sending `additionalProperties` in a function declaration causes the API parser to return a `400 Bad Request` or `MALFORMED_FUNCTION_CALL`.

GitHub

## 2. Why Frameworks Like Discourse Inject It

Orchestration frameworks (Discourse AI, Model Context Protocol/MCP, LangChain, Pydantic, Zod) automatically generate JSON schemas for custom tools:

1. **Strict Enforcement Defaults:** Generators automatically add `"additionalProperties": false` to force strict parameter typing.

2. **Dynamic Maps/Dictionaries:** If a tool parameter uses a key-value hash/dictionary (e.g., `dict[str, Any]` or a Ruby `Hash`), schema generators output `"additionalProperties": { "type": "string" }`.

3. **Unsanitized Payload:** When Discourse sends these auto-generated tool schemas to Google’s function declarations endpoint, Gemini’s Protobuf parser flags `additionalProperties` as an invalid or unknown field.

## 3. How to Resolve It in Discourse

If you are seeing this error in Discourse AI tool calls:

- **Avoid Dynamic Hash/Dict Parameters:** Ensure custom tool parameters explicitly define every expected key under `properties` rather than using open-ended objects.

- **Serialize Dynamic Data as Strings:** If a tool must accept arbitrary key-value pairs, define the parameter as a `STRING` and instruct the tool to accept a serialized JSON string.

- **Filter Out `additionalProperties` in Custom Tools:** If you have custom AI tools defined under `/admin/plugins/discourse-ai/ai-tools`, edit the parameter JSON schema to remove any `"additionalProperties"` blocks.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [August 2, 2026, 2:35am UTC](https://meta.discourse.org/t/discourse-workflows/407100/13 "2026-08-02T02:35:55Z")

</div>

I just made a pr that add support for interaction api, if you have a test env would be happy with some more testing

---

<div class="post-metadata">

### Author: ![KockaAdmiralac](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/kockaadmiralac/32/518624_2.png) [@KockaAdmiralac](https://meta.discourse.org/u/KockaAdmiralac)
#### Post date: [August 4, 2026, 3:24pm UTC](https://meta.discourse.org/t/discourse-workflows/407100/14 "2026-08-04T15:24:45Z")

</div>

Are there any plans to allow retrieving external user IDs through workflows? I’d like to make a form which checks some information about the current user in the identity provider system before continuing, but the Get User node does not output any `external_id` field as far as I can tell.

---

<div class="post-metadata">

### Author: ![j.jaffeux](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/j.jaffeux/32/60297_2.png) [@j.jaffeux](https://meta.discourse.org/u/j.jaffeux)
#### Post date: [August 6, 2026, 11:11am UTC](https://meta.discourse.org/t/discourse-workflows/407100/15 "2026-08-06T11:11:21Z")

</div>

Thanks for the feedback, that should do it: [FIX: supports optional data for workflow user node (#42400) · discourse/discourse@4d0c688 · GitHub](https://github.com/discourse/discourse/commit/4d0c6886adb531802af4c744e459b7835a31444c)

---

<div class="post-metadata">

### Author: ![thgl](https://avatars.discourse-cdn.com/v4/letter/t/f08c70/32.png) [@thgl](https://meta.discourse.org/u/thgl)
#### Post date: [August 12, 2026, 2:01pm UTC](https://meta.discourse.org/t/discourse-workflows/407100/16 "2026-08-12T14:01:59Z")

</div>

Is there some way to convert a user\_id into username? I was looking into a use case that sends the creator of a topic a personal message. But from the `topic` object I can only get the `user_id`, and the action for personal message requires a username instead.

Or alternatively - if there was a way to get the first post using the topic\_id, then it would work too, I see post has a `username` field

---

<div class="post-metadata">

### Author: ![j.jaffeux](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/j.jaffeux/32/60297_2.png) [@j.jaffeux](https://meta.discourse.org/u/j.jaffeux)
#### Post date: [August 18, 2026, 12:26pm UTC](https://meta.discourse.org/t/discourse-workflows/407100/17 "2026-08-18T12:26:33Z")

</div>

@thgl Yes given we have a data-explorer node, any kind of query to get any kind of info is possible (in this case I hardcoded the user\_id but you get the idea):

[workflow-nodes-2026-08-18.json](https://meta.discourse.org/uploads/short-url/AivmDmn3pbr2jwr1CrQLMarKHiy.json) (2.1 KB)

---

<div class="post-metadata">

### Author: ![j.jaffeux](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/j.jaffeux/32/60297_2.png) [@j.jaffeux](https://meta.discourse.org/u/j.jaffeux)
#### Post date: [August 18, 2026, 12:31pm UTC](https://meta.discourse.org/t/discourse-workflows/407100/18 "2026-08-18T12:31:58Z")

</div>

@patrickemin Not sure if you have seen it already but I have added all the building blocks necessary for this use case, let me know if you need help.

---

<div class="post-metadata">

### Author: ![thgl](https://avatars.discourse-cdn.com/v4/letter/t/f08c70/32.png) [@thgl](https://meta.discourse.org/u/thgl)
#### Post date: [August 18, 2026, 12:44pm UTC](https://meta.discourse.org/t/discourse-workflows/407100/19 "2026-08-18T12:44:28Z")

</div>

Ah that is nifty, thanks!

---

<div class="post-metadata">

### Author: ![patrickemin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/patrickemin/32/520162_2.png) [@patrickemin](https://meta.discourse.org/u/patrickemin)
#### Post date: [August 18, 2026, 1:49pm UTC](https://meta.discourse.org/t/discourse-workflows/407100/20 "2026-08-18T13:49:21Z")

</div>

Well, I did not find the action to assign to the admin topic button for that use case:

 ![image](https://global.discourse-cdn.com/meta/original/4X/a/2/9/a292d136082263456ff269620de37c1de0df9355.png)

[Next page](https://meta.discourse.org/t/discourse-workflows/407100.md?page=2)
