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

# Confirm, run a background script, show the result

> A worked example: a document action asks for confirmation, a workflow withdraws a batch of generated letters with a background script, and the person who clicked sees what happened.

## What you will build

A **Letter batch** document stands for one mass mailing. Each letter generated for it is a **Letter** document whose **BatchNo** keyword holds the batch's number, and whose **SignedDate** keyword is filled in once the recipient has signed.

Someone opens a letter batch and chooses **Withdraw letters**. They are asked to confirm. A workflow then runs a script in the background that deletes every unsigned letter of the batch and keeps the signed ones. While it works, they see its progress. When it is done, they see how many letters were deleted and how many were kept. A **Test run** choice counts the letters without deleting anything.

The example has three parts: a script, a workflow definition, and a document action. The names are illustrative; substitute your own document types and keywords.

## Prepare the configuration

You need a tenant with the workflow engine switched on, and:

* `script-engine.manage` to create and publish the script;
* `workflow-engine.manage` to build the workflow and to configure a workflow document action, plus document configuration access for **Documents → Document actions**.

The person who uses the action needs none of these. They need to be in one of the action's user groups and able to open the letter batch.

The script runs in the background, so it calls Insight as the **Script Engine's service account**. Grant that account's user **View** and **View keywords** on **Letter batch**, and **View**, **View keywords**, and **Delete** on **Letter**, under [document access rights](https://docs.insight.nobly.dk/configuration/document-access-rights.md). The workflow itself reads no keywords: it passes the batch document's ID to the script, so the Workflow Engine's service account needs no rights on these document types.

Have ready a test letter batch with a few unsigned letters and at least one signed letter, and two accounts in the action's user group: neither needs a workflow permission.

## Write the script

Create and publish a **Workflow Action** script named `Withdraw letters` from [Return a summary for a workflow message](https://docs.insight.nobly.dk/scripts/examples.md#return-a-summary-for-a-workflow-message), with your own document type and keyword type IDs. Note its slug in the **Scripts** list.

Its contract is all the workflow relies on:

* **Input:** `document_id`, the letter batch, and `test_run`, true when nothing should be deleted.
* **Output:** `summary`, one line of text for the person, and `level`, `success` when every letter was withdrawn or `warning` when signed letters were kept.
* **Failure:** a batch document without a BatchNo makes the script fail, which sends the workflow down its error path.

## Build the workflow

1. Open **Settings → Admin Settings → Workflow → Designer** and create a definition named `Withdraw letters`.

2. Choose the **Document** anchor and scope it to **Letter batch**. Leave the triggers empty: the document action starts it.

3. Add an initial node named **Withdrawing**, and two terminal nodes named **Done** and **Could not withdraw**. In the definition panel, choose **Could not withdraw** as the **Error node**.

4. On **Withdrawing**, open the **Actions** tab and add two actions, in this order:
   * `Workflow.SetMessage` — `Level` `info`, `Text` `Withdrawing letters…`. The person sees this as progress while the script runs.
   * `Script.Run` — your script's slug in `ScriptSlug`, **RunInBackground** on, `IntoVariable` `undo`, and this `Input`, written in the formula editor:

     ```text theme={null}
     { document_id: $document.id, test_run: $instance.choice == "test" }
     ```

5. Draw a **Join** transition from **Withdrawing** to **Done** whose job is `$instance.undo`.

6. On **Done**, add `Workflow.SetMessage`. Switch `Level` to expression mode and enter `$instance.undo.output.level`, and set `Text` to `{{instance.undo.output.summary}}`. Leave `Title` empty: the person then sees the level's heading, *Done* or *Done, with warnings*, which fits a test run as well as a real one.

7. On **Could not withdraw**, add `Workflow.SetMessage` with `Level` `error`, `Title` `Letters not withdrawn`, and the text `Not all letters could be withdrawn. Run the action again, or ask your administrator to check the run.`

Validate, save, and publish.

Three details decide how this behaves:

* **The choice arrives as `$instance.choice`.** The document action below puts the chosen value there, and the input turns it into `test_run`. Without a confirmation, `$instance.choice` is null, so `test_run` is false.
* **The error node needs its own message.** If the script fails, the run reaches **Could not withdraw**. The *Withdrawing letters…* message was set before the error path, so it is no longer shown; without a message on the error node, the person would see the action as done. You can add `{{instance._error.message}}` to the text, but it is the failing step's technical reason.
* **`{{owner.username}}` is the person who clicked.** Steps after the Join run as the system, so `{{identity.username}}` on **Done** would render `system`. The run's [owner](https://docs.insight.nobly.dk/workflows/expressions.md#the-owner-of-a-run) is the person who chose the action, in every step, so use `{{owner.username}}` in anything you add there later, such as a note.

## Create the document action

Open **Documents → Document actions** and choose **Add action**.

1. Name it `Withdraw letters`, choose **Workflow Action**, and select the `Withdraw letters` workflow.
2. Select the **Letter batch** document type, not **Global**, and the user group that may withdraw letters.
3. Under **Confirmation**, switch on **Ask the user before the workflow starts**, and fill in:
   * **Title:** `Withdraw the letters in this batch?`
   * **Message:** `Letters that have not been signed are deleted. Signed letters are kept.`
   * **Choices:** **Withdraw** with value `withdraw` and style **Destructive**, and **Test run** with value `test` and style **Secondary**.
   * **Variable for the choice:** keep `choice`.
4. Choose **Preview** to check the dialog, then save.

The input compares the choice's value with `test` exactly, so the **Test run** value has to stay `test` even if its label changes. **Cancel** is added automatically and starts nothing. See [Ask for confirmation](https://docs.insight.nobly.dk/client-administration/defaults-and-actions.md#ask-for-confirmation) for every field.

## Verify the whole path

Sign in as a member of the action's user group without any workflow permission, and open the test letter batch.

| Test | Expected outcome |
| - | - |
| Choose the action, then **Cancel** | Nothing starts, and no instance is created |
| Choose the action, then **Test run** | A progress dialog shows *Withdrawing letters…*. The result reports how many letters would be deleted and how many signed letters were kept. No letter is deleted |
| Choose the action, then **Withdraw** | Progress, then the result with the script's summary, headed *Done* when no letter was signed or *Done, with warnings* when signed letters were kept. Searching the batch's letters finds only the signed ones |
| Close the progress dialog while it runs | The action keeps running, and a notification with **Show** appears when it ends. **Show** opens the result |
| Close the progress dialog and choose the action again while it runs | The progress dialog opens again, and no second instance starts |
| Choose the action as the second account while the first account's run is active | *This action is already running on this document. Try again when it is done.* |
| Run it on a letter batch without a BatchNo | The result *Letters not withdrawn*, at error level |
| Sign in as someone outside the action's user group | The action is not shown |

Under [Workflow Instances](https://docs.insight.nobly.dk/workflows/monitoring.md#workflow-instances), each run's **Owner** is the person who clicked, and its variables hold `choice` and the script's result in `undo`. The history shows each `Workflow.SetMessage` with the message it set.

## When it does not work

| Symptom | Check |
| - | - |
| *This action is already running on this document* | Another run of the workflow is active on the batch. Find it under Workflow Instances by filtering on the batch document's ID |
| The person sees *Withdraw letters is done* without the result, or *Something went wrong* | A failed run, or one that took its error path, does not show the earlier information message. Choose **Could not withdraw** as the error node and give it an error-level message |
| The result names `system` instead of the person | A step after the Join reads `{{identity.username}}`. Use `{{owner.username}}` instead |
| The result appears a while after the script has finished | Expected: after a background script finishes, the result can take up to about a minute to appear |
| The script fails, or deletes nothing | The Script Engine's service account needs the rights listed above on both document types. Check the script's [execution log](https://docs.insight.nobly.dk/scripts/secrets-and-troubleshooting.md), and that the IDs in the script are your document type and keyword types |
| **Test run** deletes letters | The choice's value is not exactly `test` |
| *This action's workflow does not apply to this document's type* | The action covers a document type outside the workflow's scope. Select only **Letter batch** on the action, or widen the workflow's scope |

> [!NOTE]
>
> The script deletes letters as the Script Engine's service account, whatever rights the person who clicked has on **Letter**. The action's user groups decide who can withdraw a batch, so keep them as narrow as the task requires.

## Where to read next

> **[Workflow trigger or script hook](https://docs.insight.nobly.dk/workflows/choosing-automation.md)**
>
> Which extension point to reach for when a content event should cause something, and what changes if you pick the other one.

> **[Client defaults and document actions](https://docs.insight.nobly.dk/client-administration/defaults-and-actions.md#configure-document-actions)**
>
> Who can configure and run a workflow action, every confirmation field, and what the person sees.

> **[Action reference](https://docs.insight.nobly.dk/workflows/actions.md#show-a-result-to-the-person-who-started-the-run)**
>
> `Workflow.SetMessage` and background `Script.Run`, with their parameters and rules.


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