> For the complete documentation index, see [llms.txt](https://docs.rewst.help/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rewst.help/rewst-documentation/documentation/automations/nodes/nodes-data.md).

# Nodes: Data

*Transformational action nodes*, called *Data nodes* for short, take something from the context and change it. Use these nodes to manipulate your existing context of your workflow.&#x20;

{% hint style="info" %}
Were you a Rewst Classic user? Data nodes are the new way to handle data in Rewst. Dedicated data aliases are no longer necessary, and aliases are automatic and universal.&#x20;

Ask the Rewst Agent to explain any node in Rewst. This documentation exists to help you get started, but in-platform questions and learning are the fastest way to achieve automation.
{% endhint %}

## Data types: Built-in data nodes

<details>

<summary>Aggregate Values - <code>CTX.aggregate_values</code></summary>

This node reduces a whole array down to a single result: a count, a sum, an average, a min or max, the first or last item, or all items joined into one string. It works on arrays of numbers, objects, or strings.&#x20;

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FTKJldZhUcxN4ZIoKn74a%2FScreenshot%202026-08-11%20at%203.46.51%E2%80%AFPM.png?alt=media&amp;token=12fe10dc-b4e0-4eec-8877-8de208d03cea" alt=""><figcaption></figcaption></figure>

Configuration fields

* **Source Array** - The values to aggregate: use wildcard \[\*] to extract fields from objects, for example `TRIGGER.payload.orders[*].amount`
* **Operation** - Aggregation operation to perform
  * **Sum** - add all numeric values
  * **Count** - number of items
  * **Average** - mean of numeric values
  * **Min** - smallest value
  * **Max** - largest value
  * **First** - first item in array
  * **Last** - last item in array
  * **Join** - combines items into one string using a Join Separator (default `,` ) ; it doesn't add numbers

</details>

<details>

<summary>Build CSV - <code>CTX.build_csv</code></summary>

Build CSV text from an array of objects or arrays. Use this when workflow data needs to eb exported, attached, or sent to another system as comma-separated values. Spreadsheet formula sanitization is on by default, so cells beginning with =, +, -, or @ is prefixed with a single quote. The CSV string is produced on the node's output.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FugRhbXlQ8stdFdTd9L2E%2FScreenshot%202026-08-11%20at%203.47.31%E2%80%AFPM.png?alt=media&amp;token=aa762a61-f820-4f03-9a68-830bdb2220d4" alt=""><figcaption></figcaption></figure>

Configuration fields

* **Rows** - Rows to write as a CSV: use an array of objects or an array or arrays
* **Delimiter** - Single character, placed between CSV cells

</details>

<details>

<summary>Build XML - <code>CTX.build_xml</code></summary>

This node builds an XML document from an object shaped by Rewst's XML convention, the same shape that Parse Data produces: attributes are keys prefixed with -, element text is #text. Use it to send data to an XML API or export an XML file. Values that cannot map to a single-root XML document route to an "Invalid Data" handle instead of failing the whole node, so you can branch on bad input.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FOhAFBX5rZhAURbaY8w9V%2FScreenshot%202026-08-11%20at%203.48.52%E2%80%AFPM.png?alt=media&amp;token=e8f53db7-f34b-4c57-9b45-fe3a22a8c4a9" alt=""><figcaption></figcaption></figure>

Configuration fields

* **Input** - Single-root object following the SML JSON convention
  * Attributes as -prefixed keys
  * Text as #text

</details>

<details>

<summary>Decode Data - <code>CTX.decode_data</code></summary>

This node decodes encoded text back into plain text or JSON. It handles Base64, Base64URL, URL percent-encoding, hex, and Data URLs. It's built for untrusted input: malformed data routes to an "Invalid Data" handle rather than failing the node, so workflows can branch on bad data.&#x20;

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FZK0TdJd4bnrJ38DJQo2C%2FScreenshot%202026-08-11%20at%203.49.42%E2%80%AFPM.png?alt=media&amp;token=2dde861b-012c-4081-968b-4b9e9904c876" alt=""><figcaption></figcaption></figure>

Configuration fields

* **Input** - Encoded runtime input to decode
* **Input Format** - Encoding format to decode: **Base64**, **Base64 URL**, **URL Percent**, **Hex**, or **Data URL**
* **Strictness**
  * **Strict -** Rejects malformed runtime data
  * **Lenient** - Accepts safe transport variants such as missing Base64 padding
* **Output Kind**
  * **Text** - Default
  * **JSON Parse** - To parse the decoded text

</details>

<details>

<summary>Encode Data - <code>CTX.encode_data</code></summary>

This node encodes trusted workflow data into Base64, Base64URL, URL percent-encoding, hex, or a Data URL. Text input is treated as UTF-8 bytes internally; choose JSON to stringify an object before encoding. Use Line Wrapping (RFC 2045, 76 charaxcters) for legacy MIME consumers, or Data URL when emitting line image/text payloads.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FC7orPRMyVV4UX6bbbLvS%2FScreenshot%202026-08-11%20at%203.50.19%E2%80%AFPM.png?alt=media&amp;token=1aef3345-2537-4df0-b95c-f80972eb71c5" alt=""><figcaption></figcaption></figure>

Configuration fields

* **Input** - Runtiume input to encode: text is treated as UTF-8 bytes internally, and no charset selector is exposed
* **Input Kind** - Treat input as **text** or **JSON-stringify** it before encoding
  * UTF-8 is the implicit text encoding
  * There is no separate UTF-8 mode
* **Output Format** - Encoding format to produce: **Base64**, **Base64URL**, **URL percent-encoding**, **hex**, or a **Data URL**

</details>

<details>

<summary>Group &#x26; Aggregate - <code>CTX.group_aggregate</code></summary>

Group a list by a field and compute per-group metrics: sum, count, acerage, median, min, max, first, last, or collect. Optionally attach fields from a second list matched by the group key. Use this instead of a code expression for rollups, pivots, and grouped reports. For example, group charge rows by companyID, sum charge, then attach company name from a companies list.&#x20;

Configuration fields

* **Source Array** - The list to group: bind an upstream array or enter a templated array expression
* **Group By Field** - Dot path on each source item that supplies the group key, for example companyID or ticket.subType.name
* **Aggregations**
  * Add one row per metric
  * Pick an operation, the item attribute it reads, and the output name for the grouped row
  * Operations: sum, count, avg, min, max, median, first, last, collect
* **Enrichment Source** - Optional second list used to attach fields to each grouped row
* **Enrichment Match Field** - Dot-path on each enrichment item matched to the group key, for example id
* **Enrichment Fields** - Optional fields copied from the first matching enrichment item
  * Each row names the attribute to read and the output name on the grouped row
* **Output Shape**
  * **Rows** preserve key types and order
  * **Map** is convenient for keyed lookup

</details>

<details>

<summary>Lookup Value - <code>CTX.lookup_value</code></summary>

When your data uses codes or abbreviations, this node translates them into human-readable values. Feed it a status code and get back "Success." Or, feed it "CA" and get back "California." Think of it as a small mapping table - status code to label, region code to region name. You define the translation table.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FmvepM9EP8FJfOkt1amCX%2FScreenshot%202026-08-11%20at%203.51.11%E2%80%AFPM.png?alt=media&amp;token=67d494ea-ba9a-4991-826d-296e3b783f1a" alt=""><figcaption></figcaption></figure>

Configuration fields

* **When I receive** - The value to translate, such as the status code or priority number
* **Translate it using this table** - Add rows for each translation
  * Use **Start with Example** to launch an example table you can edit
  * Use **+ Add Manually** to launch blank table Input and Output fields
* **If no match, return** - Returned when input doesn't match any row; leave empty for null
* **Match exact uppercase/lowercase** - When toggled to **enabled**, Error and error are treated as different, case-sensitive values

</details>

<details>

<summary>Object Builder - <code>CTX.object_builder</code></summary>

Build your output object by picking fields from previous nodes and optionally transforming them. Use this when you need to reshape data, combine fields from multiple sources, or prepare a payload for an API call.&#x20;

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FmcZXJXMJy1kA3fFLtcsq%2FScreenshot%202026-08-11%20at%203.52.00%E2%80%AFPM.png?alt=media&amp;token=4445eca4-9b61-4788-9aa9-91d163e1ebe3" alt=""><figcaption></figcaption></figure>

Configuration fields

* **Output fields** - Define what this node outputs
  * **+ Add Field Manually** - Full control, adding one field at a time\
    ![](https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2Fq5ecq4kbWU8nKLJDltae%2FScreenshot%202026-08-26%20at%2011.35.47%E2%80%AFAM.png?alt=media\&token=bb409714-d26c-49ff-b2d7-eb33a1bf3f74)
  * **Use the Wizard** - Guided setup with suggestions, recommended \
    ![](https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FCNYEutpTcJD0rGOe7pyf%2FScreenshot%202026-08-26%20at%2011.36.04%E2%80%AFAM.png?alt=media\&token=b84651e7-27ba-4918-97d8-da517379aab3)
  * **Import from JSON** - Launches a dialog to upload JSON file

</details>

<details>

<summary>Parse Data - <code>CTX.parse_data</code></summary>

This node parses JSON, YAML, CSV, or XML text into workflow data. Malformed runtime input routes to an "Invalid Data" handle instead of failing the node, so workflows can branch on bad data. Choose the format explicitly, then use advanced CSV or XML options when needed.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FC8qxIoz34jPFWwCOOOFJ%2FScreenshot%202026-08-11%20at%203.52.25%E2%80%AFPM.png?alt=media&amp;token=c894cf86-e57e-4671-b199-b62f07ca1640" alt=""><figcaption></figcaption></figure>

Configuration fields

* **Input** - Text to parse as the selected format
* **Format** - Format of the input text: **JSON**, **YAML**, **CSV**, or **XML**

</details>

<details>

<summary>Regex Replace - <code>CTX.regex_replace</code></summary>

This node finds and replaces text using a regular expression. It uses Go's RE2 engine, which has no backtracking or lookaround. Replacement references use `$1` and `${name}`; use `$$` for a literal dollar. Zero matches pass the input through unchanged on out. Invalid patterns fail the node with position detail.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2Fw98az65Re6Rr51KYCyXi%2FScreenshot%202026-08-11%20at%203.53.13%E2%80%AFPM.png?alt=media&amp;token=d2490574-8696-4b1d-adb3-3e86d6efe889" alt=""><figcaption></figcaption></figure>

Configuration fields

* **Input** - Runtime string to transform
* **Pattern** - Go regexp pattern, lookaround and backtracking-only constructs are not supported
* **Replacement** - Replacement text
  * Leave field empty to delete matches
  * Capture references use `$1` or `$name`
  * Literal dollar is `$$`
* **Replace All** - Replace all matches; toggle off to replace only the first match
* **Ignore Case** - Match without case sensitividy via RE2 inline flat (?i)
* **Multiline** - Make ^ and $ match line boundaries via RE2 inline flag (?m)

</details>

<details>

<summary>Render Template Asset - <code>CTX.render_template_asset</code></summary>

This node loads a template from Rewst's [Automation Asset library](/rewst-documentation/documentation/automations/automation-assets-templates-and-scripts.md) and renders it with the current workflow context. Use it for reusable email templates, markdown summaries, or JSON payloads that are managed centrally rather than pasted into each workflow. You can pick a fixed template, or enter a dynamic slug from upstream data.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FJh5MqbbDCdw42McXCein%2FScreenshot%202026-08-11%20at%203.54.01%E2%80%AFPM.png?alt=media&amp;token=a502fb36-87f6-47e9-b318-320b2abafdbf" alt=""><figcaption></figcaption></figure>

Configuration fields

* **Template Asset** - Pick a template from the Asset Library
  * Leave blank if using a dynamic slug below instead
* **Template Parameters** - Parametrer bidings passed to the templagte as PARAMS via key-value pairs
  * Ex: `{{ PARAMS.ticketId }}`
* **Output Type** - The data type the rendered template produces
  * Automatically detects it from the rendered value
  * String always stringifies
  * Number, Boolean, Object and Array coerce to that type and error if the value does not match
  * This type is what downstream nodes see when they browse this output

</details>

<details>

<summary>Resolve Script Asset - <code>CTX.resolve_script_asset</code></summary>

Select a script from Rewst's [Automation Asset library](/rewst-documentation/documentation/automations/automation-assets-templates-and-scripts.md) and resolve its body and metadata. The resolved script body is output for downstream execution nodes. You can pick a fized script or enter a dynamic slug from upstream data.

Configuration fields

* **Script Asset** - Pick a script from the Asset library, or leave empty of using a dynamic slug below instead
* **Script Parameters** - Parameter bindings passed to the script at execution time, via key-value pairs

</details>

<details>

<summary>Transform Array - <code>CTX.transform_array</code></summary>

This node performs per-item array work without a Loop node: map, filter, sort, unique, groupBy, batch, append, concat, or flatten. It's the first choice for reshaping a list.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FSh3DJHBeJVi6bovjtgQ8%2FScreenshot%202026-08-11%20at%203.54.31%E2%80%AFPM.png?alt=media&amp;token=949b3846-3d9e-475b-ae7e-4578389e7d90" alt=""><figcaption></figcaption></figure>

Configuration fields

* **Operation**
  * **Remove Duplicates** - Remove duplicate items from the array
  * **Sort** - Reorder items by a field or value
  * **Randomize** - Randomize the item order
  * **Filter** - Keep only items that match a condition
  * **Map** - Transform each item into something new
  * **Append** - Nest an array as one element
  * **Concat** - Flat-combine two arrays
  * **Remove First** - Remove the first item in the array
  * **Remove Last** - Remove the last item in the array
  * **Flatten** - Merge nested arrays into one level
  * **Group By** - Group items by a field and return an object with arrays
  * **Batch** - Split into smaller arrays of a fixed size
* **Source Array** - The array to transform

</details>

## Data types: Calculate

<details>

<summary>Generate Random Value - <code>CTX.generate_random_value</code></summary>

Create a new random value each time your workflow runs. You pick the type of value you want and get a new value each time the workflow runs. If you need the same value in several places, generate it once and reuse it. Don't add a second Generate step, as that would create a different value.

Use it to generate temporary passwords during onboarding, to give each workflow run a unique ID to find it later in logs or tickets, or to choose a random number to decide which tech will be assigned a task.&#x20;

Configuration fields

* **Generator type** - the value you want to generate
  * **Unique ID** - a long code that will never repeat
  * **Number** - a random whole integer
  * **Characters** - a random. mix of letters and numbers, great for temp passwords
  * **Hex** - a random code made of numbers and the letters A-F
  * **Base64** - another style of random text code
  * **Passphrase** - a few random words strung together, easier to read than random characters
  * **Color** - a random color code, for example #4A90E2
* **UUID format** - choose the output shape when generating UUIDs: defaults to v4 when unset
* **Format (legacy)** - legacy shared format key superseded by UUID format and ignored when set; retained so existing configurations keep working<br>

</details>

<details>

<summary>Hash Data - <code>CTX.hash_data</code></summary>

Hashing lets you quickly check whetehr two sets of data are identical before you spend time comparing them line by line. Make a fingerprint of a piece of information. Give the node some data, such as a name, email address or list of records, and it will give back a short code that stands for that data. Use it to  spot changes in a customer's user list over time, compare private information safety, or confirm that a message from an outside system is genuine.&#x20;

* The same data always gives the same fingerprint. The code will be identical always.
* Any change gives a completely different fingerprint.&#x20;
* It only works one way— you can't turn the fingerprint back to the original data.

Configuration Fields

* **Mode** -&#x20;
  * hash creates an unkeyed digest, a plain fingerprint of the data
  * HMAC creates a keyed digest, mixing in a secret password
* **Algorithm** - choose a digest algorithm as the method used to make the fingerprint; MD5 is legacu and non-secure, not for passwords or tamper resistance
* **Input kind** - text hashes the value as UTF-8 text; JSON stringifies the bound value before hashing
* **Hex case** - letter case for hex output, either upper or lower case

</details>

## Data types: Database

<details>

<summary>Execute SQL - <code>TASKS.execute_sql</code></summary>

{% hint style="danger" %}
Execute SQL makes real, immediate changes to your database. There's no built-in undo, so a delete instruction written a bit too broadly could remove more than you meant to. Test carefully, and use Run Query if you only need to look something up.
{% endhint %}

This node lets your workflow change information stored in a database. It sends the database instruction that changes something. For example:

* Add something new, like a customer to the customer's table
* Update something, like change the customer's phone number
* Delete something, like remove an old record
* Change the. layout, like add a new column or tables

It works with three common database types: Postgres, MYSQL, and Microsoft SQL Server.  You need a database connection set up first so that Rewst can know where the database is and how to log in. Without that, this node won't run. Workflow information goes in separately from the instruction. This node works in conjunction with the other two nodes in this category: Run Query and Run Stored Procedure.

Configuration Fields

* **Database connection** - the saved database server connection to run this statement against; the connection must not be read-only, as read-only connections refuse write statements
* **SQL statement**- the write statement to run; use the schema-qualified table name
  * INSERT
  * DELETE
  * DDL

</details>

<details>

<summary>Run Query - <code>TASKS.run_query</code></summary>

Let your workflow look up information in a database without changing anything. This is the read-only counterpart to the Execute SQL node. Ask the database a question and have it hand back the matching record as a list of results. Later steps in your workflow can use those results. It works with three database types: Postgres, MYSQL, and Microsoft SQL Server.&#x20;

You need a database connection set up first so that Rewst can know where the database is and how to log in. Without that, this node won't run. Workflow information goes in separately from the instruction. This node works in conjunction with the other two nodes in this category: Execute SQL and Run Stored Procedure.

Configuration Fields&#x20;

* **Database connection -** the saved database server connection to run this query against; Run Query is read-only, and on PostgreSQL and MySQL it runs in a read-only transaction, with a read-only credential required for SQL Server
* **SQL query** - the SQL to run: use the schema-qualified table name
* **Query parameters** - enter a JSON array, an ordered list of values that fill the. placeholders in your query, in order

</details>

<details>

<summary>Run Stored Procedure - <code>TASKS.run_stored_procedure</code></summary>

Tell a database to run a saved set of instructions that already live inside it. Use it when someone has already built logic, to ensure consistency, and to make complex jobs simpler with one click instead of several steps. You provide the procedure name and any needed inputs. It sends results back, and can make changes. It works with three database types: Postgres, MYSQL, and Microsoft SQL Server.&#x20;

{% hint style="warning" %}
Since a stored procedure can change data, ask whoever built it what it actually does before you run it in a live workflow. Its name doesn't always tell the whole story.
{% endhint %}

Configuration Fields

* **Database connection**
* **Procedure name** - the name of the stored procedure to run, optionally schema-qualified; use a plain identifier as quoted/bracketed names and names with spaces aren't supported
* **Parameters** - optionally add an ordered list of positional INOUT values passed to the procedure in declaration order; values are bound as parameters, never string-interpolated, keeping the call safe from injection; OUTPUT parameters not supported

</details>

## Data types: Datastore Key-Value

<details>

<summary>Compare and Swap Key-Value - <code>TASKS.compare_and_swap_key_value</code></summary>

Save a piece of information in Rewst's built-in storage, but only if nobody else has changed it since you last checked. It stops two workflow runs from overwriting each other's work. The workflow path will proceed to either success or failure, if someone changed it first. On failure it will re-read the storage and try again, or stop. Use it to prevent double work, count and run totals, and reconcile checkpoints in records.

Configuration Fields

* **Scope** - who shares the storage
  * **Tenant** - set isolated to this organization
  * **MSP subtree (shared)** - share across the MSP org tree, with descendants being able to read and write
* **Namespace** - named storage area in Rewst
* **Key** - key for the storage area in Rewst
* **Expected version**&#x20;
* **Value** - what to put in the storage

</details>

<details>

<summary>Delete Key-Value - <code>TASKS.delete_key_value</code></summary>

{% hint style="danger" %}
Deleting can't be undone. If other workflows read the same storage space, make sure none of them still need it.
{% endhint %}

Empty one storage area in Rewst's built in storage. It uses the same storage as the Compare and Swap Key-Value node. You indicate what storage area to clear out, and the node does the work. It doesn't need to know what's inside. It just removes it. The success path in the workflow means the storage was cleared. Failure means the delete didn't work. Use this node to clean up when a job is finished, clear an old checkpoint and start fresh, or remove stale information before it causes confusion instead of waiting for it to expire.

Configuration Fields

* **Scope**
* **Namespace**
* **Key**

</details>

<details>

<summary>Get Key-Value - <code>TASKS.get_key_value</code></summary>

Open one area in Rewst's built-in storage and hand its contents to the rest of your workflow. You indicate which area and the node reads what is inside. Nothing gets changed. A workflow usually forgets everything once it finishes. This node lets it remember things from earlier runs. Use it to pick up where you left off, avoid double work, or quickly reference info.

Configuration Fields

* **Scope** - who shares the storage
  * **Tenant** - set isolated to this organization
  * **MSP subtree (shared)** - share across the MSP org tree, with descendants being able to read and write
* **Namespace**
* **Key**
* **Timeout (seconds)** - maximum execution time for datastore operation

</details>

<details>

<summary>Increment Key-Value - <code>TASKS.increment_key_value</code></summary>

**Add to a number saved in one of Rewst's storage areas**. It works like a tally counter: each time the workflow reaches this step, the number goes up. You tell it where and how much to add. The increment does the reading, adding, and saving in one unbreakable move.&#x20;

Configuration Fields

* **Scope** - who shares the storage
  * **Tenant** - set isolated to this organization
  * **MSP subtree (shared)** - share across the MSP org tree, with descendants being able to read and write
* **Namespace** - named storage area in Rewst
* **Key** - key for the storage area in Rewst
* **Increment by** - must be a whole integer

</details>

<details>

<summary>Set Key-Value - <code>TASKS.set_key_value</code></summary>

Put something in one of Rewst's storage spaces so your workflow can find it again later, even on a future run. It's the "save" step in this category of actions. If the space already has something in it, the old contents are replaced with a new value. If more than one copy of the workflow could update the same locker at the same moment, one update can be lost. For numbers, use Increment Key-Value. For other kinds of changes, use Compare and Swap Key-Value.

Configuration Fields

* **Scope** - who shares the storage
  * **Tenant** - set isolated to this organization
  * **MSP subtree (shared)** - share across the MSP org tree, with descendants being able to read and write
* **Namespace** - named storage area in Rewst
* **Key** - key for the storage area in Rewst
* **Value**

</details>

## Data types: Datastore Record

<details>

<summary>Aggregate Records - <code>TASKS.aggregate_records</code></summary>

Summarize a collection of records saved in Rewst's built-in storage. Instead of handing back every record, it hands back totals, counts, and averages, sorted into groups. If you've used a pivot table or a summary report in a spreadsheet, it's the same idea. Use it to answer questions like:

* "How many mismatches did we find for each customer?"
* "What's the total billing difference per month?"
* "What's the average number of fixes per technician?"

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2Ff6oT8FGMQ1YThdKoLYZ8%2FScreenshot%202026-09-23%20at%202.43.21%E2%80%AFPM.png?alt=media&amp;token=df9476c4-ba33-4a23-adc3-43fedd54fa90" alt="" width="563"><figcaption></figcaption></figure>

Configuration Fields

* **Scope** - Which storage area to look in: either just this organization, or the one your MSP organization shares with the customer organizations under it
* **Collection** - Which "spreadsheet" to summarize
* **Record key prefix** - another way to narrow things down, by only including records whose ID starts with certain text
* **Group by** - what to sort the rows into groups by, like customer, month, or status
* **Metrics** - what to calculate for each group: **count** (how many), **sum** (total), **average**, **min** (smallest), **max** (largest), or **count true** (how many are marked "yes")
* **Filters** - only include certain rows, like "only this month" or "only mismatches"
  * You can only group by and calculate on fields that are **indexed**, meaning fields the storage has been set up to search and sort quickly— if a field you want doesn't work here, it probably isn't one of the indexed fields
* **Order by** - sort the results, like "biggest totals first"
* **Limit** - Only return the top few groups, like "top 10 customers"
* **Timeout (seconds)** - maximum execution time for the datastore operation

</details>

<details>

<summary>Bulk Upsert Records - <code>TASKS.bulk_upsert_records</code></summary>

**Savea a whole batch of records into Rewst's built-in storage in one go**. It's the step that **fills up** the collections that Aggregate Records summarizes. For each record, the step either adds it if it's new or updates it if a record with the same ID already exists.&#x20;

Choose record keys carefully. Use something that truly identifies each item, like an account number. If two different items share a key, the second overwrites the first. If the same item gets a different key each run, you'll end up with duplicate rows instead of updates.<br>

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2Fq6PUlkKFH98dTulF1Bn2%2FScreenshot%202026-09-23%20at%202.51.44%E2%80%AFPM.png?alt=media&amp;token=3f8e3081-b834-40dd-9d12-2581dc4f202f" alt="" width="563"><figcaption></figcaption></figure>

Configuration Fields

* **Scope** - Which storage area to save to: either just this organization, or the one your MSP organization shares with the customer organizations under it
* **Collection** - Which area to save into
* **Items** - The list of records to save; each one has a record key and its data
* **Indexed fields** - which details to make searchable and summarizable, like customer, status or amount
  * Indexed Fields matter later; if you'll want a report "by customer," list the customer field here.&#x20;
* **TTL (seconds)** - how long to keep the records before they're cleared automatically; leave it blank or at 0 to keep them indefinitely
* **Timeout (seconds)** - maximum execution time for the datastore operation

</details>

<details>

<summary>Count Records - <code>TASKS.count_records</code></summary>

This node tells you how many records in a Rewst storage collection match what you're looking for. It gives back just the number, not the records themselves. Use it for:

* Decision-making: "If there are more than 10 mismatches, alert a manager. Otherwise, carry on quietly." Put an If/Else step after the count to do this.
* Quick reporting: drop a count into an email or ticket, like "12 accounts need review."
* Checking before doing work: "Are there any unprocessed records? If the count is 0, stop here."

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FayMzPjhEJbsptwt9vkx8%2FScreenshot%202026-09-23%20at%202.56.23%E2%80%AFPM.png?alt=media&amp;token=381250aa-bd7b-42e2-8986-4f70a85c4bfa" alt=""><figcaption></figcaption></figure>

Configuration Fields

* **Scope** - which storage area to look in: either just this organization, or the one your MSP organization shares with the customer organizations under it
* **Collection** - which area to count in
* **Record key prefix** - only count records whose ID starts with certain text, like every ID beginning with `acme-`
* **Filters** - only count rows that match certain conditions: require all of your conditions ("mismatch and Acme Corp") or any of them ("Acme Corp or Bright Dental"); Leave this empty to count everything
* **Timeout (seconds)** - maximum execution time for the datastore operation

</details>

<details>

<summary>Delete Record - <code>TASKS.delete_record</code></summary>

{% hint style="danger" %}
Deleting is permanent and immediate. There's no undo or recycle bin.
{% endhint %}

Permanently remove one saved item from Rewst's built-in storage. You can type the location in yourself, or have it come from an earlier step in the workflow, like "the ticket number we just got."

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FyKcJWru9ZCujpVFCGZ7O%2FScreenshot%202026-09-23%20at%203.04.49%E2%80%AFPM.png?alt=media&amp;token=1233f57d-9dac-4fd5-949c-a8e030eda377" alt="" width="563"><figcaption></figcaption></figure>

Configuration Fields

* **Scope** - which storage area to look in: either just this organization, or the one your MSP organization shares with the customer organizations under it
* **Collection** - which area to look in to find the record
* **Record key** - the label on the folder you want to delete, such as `cw_company_123`; you can type it in, or pull it from an earlier step, like a ticket number
* **Timeout (seconds)** - maximum execution time for the datastore operation

</details>

<details>

<summary>Get Record - <code>TASKS.get_record</code></summary>

Look up one saved record and bring its contents into your workflow so later steps can use it. It's the opposite of Delete Record: it reads the folder instead of throwing it away. It only reads and never deletes or makes changes. Use it to:

* Remember something from an earlier run, like "what did we last record for this customer?"
* Check before acting, like "have we already handled this ticket?"
* Look up a match, like finding which company in one system lines up with a company in another.

To search, filter, or fetch a list of records, use the Query Records node instead.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FaCu5FYoVA1gTVsU1aikZ%2FScreenshot%202026-09-23%20at%203.07.29%E2%80%AFPM.png?alt=media&amp;token=60ba75c7-742c-436b-9a27-d6b41071e3e7" alt=""><figcaption></figcaption></figure>

Configuration Fields

* **Scope** - which storage area to look in: either just this organization, or the one your MSP organization shares with the customer organizations under it
* **Collection** - the location to look in, such as `customer_map`
* **Record key** - the label of the folder you want, such as `cw_company_123`
* **Timeout (seconds)** - maximum execution time for the datastore operation

</details>

<details>

<summary>Query Records - <code>TASKS.query_records</code></summary>

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FOChNVBDup44eyJRXM1n7%2FScreenshot%202026-09-23%20at%203.08.46%E2%80%AFPM.png?alt=media&amp;token=1835a737-539c-443b-803b-126ce1dd1302" alt="" width="563"><figcaption></figcaption></figure>

Configuration Fields

* **Scope** - which storage area to look in: either just this organization, or the one your MSP organization shares with the customer organizations under it
* **Collection** - which area to count in
* **Record key prefix** - only count records whose ID starts with certain text, like every ID beginning with `acme-`
* **Filters** - only count rows that match certain conditions: require all of your conditions ("mismatch and Acme Corp") or any of them ("Acme Corp or Bright Dental"); Leave this empty to count everything
* **Timeout (seconds)** - maximum execution time for the datastore operation

</details>

<details>

<summary>Upsert Record - <code>TASKS.upsert_record</code></summary>

Upsert combines update and insert. When this node runs, it looks for a row with the ID you give it:

* If the row already exists, it updates that row with your new information.
* If it doesn't exist yet, it creates a new row.

This means you don't have to check first and then decide whether to create or update. The node takes care of both cases. Queries are cursor-paginated. Use this for reference data like mapping tables or small ledgers.&#x20;

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FDaziyLiNJcUcE1qMeoL6%2FScreenshot%202026-09-23%20at%203.18.49%E2%80%AFPM.png?alt=media&amp;token=555e7dd5-f83b-495c-b86c-f46a1588b670" alt="" width="563"><figcaption></figcaption></figure>

Configuration Fields

* **Scope** - which storage area to look in: either just this organization, or the one your MSP organization shares with the customer organizations under it
* **Collection** - which area to save into; if it doesn't exist yet, it's automatically created
* **Record key** - the unique ID for the row, like a name tag
* **Data** - the information you want stored in the row, such as status, owner or region
* **Indexed fields** - the fields you'll want to search or sort by later (for example `status`); listing them here makes it possible to filter on them with a "Query Records" node
* **TTL (seconds)** - how long to keep the records before they're cleared automatically; leave it blank or at 0 to keep them indefinitely
* **Timeout (seconds)** - maximum execution time for the datastore operation

</details>

## Data types: JSON Webtoken (JWT)&#x20;

<details>

<summary>Create JWT - <code>CTX.create_jwt</code></summary>

Build a JSON Web Token (JWT) to use as a digital pass your workflow can show to another system to prove who it is or what it's allowed to do. Use it for:&#x20;

* Connecting to certain cloud services or vendor APIs that require this kind of sign-in
* Giving another system a short-lived pass to access something
* Proving to a partner system that a request really came from you

Keep the signing key secret. Anyone who has it can make passes that look like yours. Store it somewhere protected, not typed out in plain view.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FeD43Lrfij8MeTxllZoR3%2FScreenshot%202026-09-23%20at%202.40.23%E2%80%AFPM.png?alt=media&amp;token=433a73fb-ceb7-458e-932a-87f82ef3273d" alt="" width="563"><figcaption></figcaption></figure>

Configuration Fields

* **Algorithm** - the signing algorithm: HS256/384/512 (shared secret) or

  RS/ES 256/384/512; A mismatch between algorithm and key hard-fails
* **Claims** - the JSON object of claims to sign
* **Signing key** - the HS secret or an RS/ES private key in PEM form
* **Key encoding** - how to decode the key: text, base64, base64url, hex, or pem
* **Claim options** - optional helpers for the `iat`, `exp`, `nbf`, and `jti` time claims

</details>

<details>

<summary>Decode JWT - <code>CTX.decode_jwt</code></summary>

Read what's written in a JSON Web Token (JWT) acting as a digital pass. Note that this node doesn't check whether the pass is genuine. Give the node a JWT and it turns that back into readable information. Use it for:

* Troubleshooting: see what's on a pass another system gave you, so you can work out why something isn't working.
* Checking the expiration time: see when a pass runs out, so the workflow can get a new one before it stops working.
* Pulling out a detail: grab something like a user ID or account name from a pass you already trust.

"Decoded" doesn't mean "genuine." Anyone can make a pass that decodes perfectly, so a successful decode proves nothing about who sent it. If the workflow is going to trust the pass, for example to decide whether to let a request through, use Verify JWT. Verify checks the signature and expiration and only sends valid passes down the "valid" path.

![](https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FbphW7akOCtejEBuFuSMQ%2FScreenshot%202026-09-23%20at%202.40.52%E2%80%AFPM.png?alt=media\&token=c221e986-1db3-4f49-b5f7-9c5e0a1505e4)\
\
Configuration Fields

* **Token** (required) - the JWT to decode.
* **Strictness** - how strictly to reject malformed structure (strict or lenient).
* **Return part** - which piece to return: payload (default), header, or both.

</details>

<details>

<summary>Verify JWT - <code>NONE.verify_jwt</code></summary>

**Check whether a JSON Web Token (JWT) digital pass is genuine** before your workflow trusts it. It reads the token, checks that it isn't a fake, checks that it hasn't expired, and then decides if access is deserved

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FZEJysVFKiBPntxoD6c2M%2FScreenshot%202026-09-23%20at%202.41.25%E2%80%AFPM.png?alt=media&amp;token=f2d3a9d4-bbb0-472b-bf5a-9261f6393220" alt="" width="563"><figcaption></figcaption></figure>

Configuration Fields

* **Token** - the JWT to verify
* **Allowed algorithms** - the algorithms you accept; never trust the token's own

  header alone; list the algorithms you expect here
* **Verification key** - the HS shared secret or the RS/ES public key PEM
* **Key encoding** - text, base64, base64url, hex, or pem
* **Strictness** - how strictly to reject malformed structure
* **Claim validation toggles**
  * **Require expiration** - reject passes that don't have an expiration time
  * **Require not before - r**eject passes that don't have a start time
  * **Expected issuer - o**nly accept passes from this sender, like "must come from Acme's system"
  * **Expected audience - o**nly accept passes meant for you; stop a pass made for another system from being reused on yours
  * **Required claims** - specific pieces of information that must be written on the pass
  * **Clock-skew tolerance in seconds** - allow a few seconds of leeway, in case the two systems' clocks don't match exactly

</details>

## Data types: Org Variables

<details>

<summary>Delete Org Variable - <code>TASKS.delete_org_variable</code></summary>

Delete an org variable. When deleting a shared MSP value, you can also cascade the deletion to child orgs.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FAzZ9QxSQA8zuFD3jzSLn%2FScreenshot%202026-09-23%20at%202.37.40%E2%80%AFPM.png?alt=media&amp;token=ba7fd3c5-7184-47aa-9616-b57a7f2356c7" alt="" width="563"><figcaption></figcaption></figure>

Configuration Fields

* **Name**
* **Scope**
  * **Tenant** - set isolated to this organization
  * **MSP subtree (shared)** - share across the MSP org tree; requires MSP-root permissions for shared write setting
  * **Timeout (seconds)** - maximum execution time for the datastore operation

</details>

<details>

<summary>Get Org Variable - <code>TASKS.get_org_variable</code></summary>

Read an org variable by name for the current organization. By default, it checks the org value first, then falls back the shared MSP parent org value if no local override exists.

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FAwK9rHUEehQN1Y1Elfyl%2FScreenshot%202026-09-23%20at%202.36.52%E2%80%AFPM.png?alt=media&amp;token=2b868d20-8a90-4cad-a01e-21b2e06a73e3" alt="" width="563"><figcaption></figcaption></figure>

Configuration Fields

* **Name**
* **Fallback** toggle - when enabled, check the org value first and then the parent MSP org value
* **Default**&#x20;
* **Timeout (seconds)** - maximum execution time for the datastore operation

</details>

<details>

<summary>List Org Variables - <code>TASKS.list_org_variables</code></summary>

List org variables for the current organization. The default all scope returns the merged effective view where organizatoin overrides win over shared MSP values.&#x20;

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2Fz1gX3OlPaC5jeTKKVzfK%2FScreenshot%202026-09-23%20at%202.38.08%E2%80%AFPM.png?alt=media&amp;token=cf2a900b-2315-4767-b528-82eb1af186a6" alt="" width="563"><figcaption></figcaption></figure>

Configuration Fields

* **Scope**
  * **All** - list the merged effective view across org and shared scopes
  * **Tenant** - set isolated to this organization
  * **MSP subtree (shared)** - share across the MSP org tree; requires MSP-root permissions for shared write setting
* **Category**
  * **General**
  * **Secret**
* &#x20;**Name prefix**&#x20;

</details>

<details>

<summary>Set Org Variable - <code>TASKS.set_org_variable</code></summary>

Create or update an org variable through the dedicated org variable service. Use cascade to write the shared MSP default instead of a child org-local value.&#x20;

<figure><img src="https://3039672601-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh0G0em3PH6aDfPoI5XpN%2Fuploads%2FKF1rfZCciTnj5mRed5at%2FScreenshot%202026-09-23%20at%202.37.18%E2%80%AFPM.png?alt=media&amp;token=73da448d-a9ef-4a8f-b858-d8d571722ae7" alt="" width="563"><figcaption></figcaption></figure>

Configuration Fields

* **Name**
* **Value**
* **Category**
  * **General**
  * **Secret**
* **Write Shared MSP value** toggle - when enabled, write hte shared MSP default instead of a child org-local value
* **Description** - optional human-readable description for operators

</details>

## Data types: Time & Date

<details>

<summary>Calculate Time - <code>CTX.aggregate_values</code></summary>

Take a timestamp, add or subtract an amount of time, or give a new timestamp. It has the same input and same output every time. Whereas Calculate Time node produces a new date, the Compare Times node tells you the relationship between two existing dates. If you're asking 'is this overdue,' use Compare Times. If you're asking 'when is this due,' use Calculate Time.&#x20;

* A bad input timestamp won't fail the node.
* &#x20;If a unit is mispelled or resolves to something unexpected, the node returns the input timestamp unchanged with no error at all.&#x20;
* Timezone handling depends entirely on what your Time Format pattern captures.&#x20;
* One operation is allowed per node. 'Plus 2 days and 4 hours' would need two nodes chained, or an expression node.

Configuration Fields

* **Input time** - the starting timestamp, usually a reference to upstream data
* **Time format** - how the input timestamp will be written
* **Operation** - **Add** or **Subtract**
* **Amount** - how many units, with a minimum of 0 in the field; don't use negative numbers
* **Unit** - **Milliseconds, Seconds, Minutes, Hours, Days, Weeks, Months** or **Years**
  * Months and Years are truncated to whole numbers
  * Month arithmetic can overshoot - for example, adding one month to January 31 doesn't give you February 28 and instead rolls into March

</details>

<details>

<summary>Compare Times - <code>NONE.compare_times</code></summary>

Take two timestamps and have the node tell you which is earlier. It routes the workflow down one of three parts, and reports how far apart they are. You could compare dates in an if/else, but that would rewire hand-writing date parsing in a template. The Compare Times node gives you the three routing paths natively, with a gap between the two times as a number you can use downstream, and a per-field format pattern.&#x20;

* Rounding decides the routing. The gap is computed, then rounded to your difference decimals, with the rounded value determining the branch.
* Don't expect a negative number to tell you the date is in the past. It's an absolute value.
* A bad timestamp will fail the node.&#x20;
* An unrecognized difference unit will become seconds.&#x20;
* There is no timezone handling beyond the patterns.

Configuration Fields

**Time A** - first timestamp, typically the thing being tested, for example a due date

**Time B** - second timestamp, typically the reference, for example now

**Time A format** - pattern for parsing time A

**Time B format** - pattern for parsing time B

**Difference unit** - unit for the reported gap: **Milliseconds**, **Seconds**, **Minutes**, **Hours**, **Days**, **Weeks**

**Difference decimals** - decimal precision for the gap: minimum of 0

</details>

<details>

<summary>Convert Time Format - <code>CTX.convert_time_format</code></summary>

Rewrite a timestamp from one text format into another. The moment in time doesn't change, only how it's written changes. Chain it after the Calculate Time node if you need a computed date in a different format.

* A bad timestamp does not fail the node. If the input doesn't match your input format, the node will continue the workflow down the success path, without notifying of failure.
* Converting a timestamp with milliseconds into a pattern without them discards precision from the time\_out. Use timestamp if you need the full value.
* There's no timezone conversion. It can't shift a timestamp between timezones.&#x20;
* Use strftime patterns only— %Y-%m-%d— not go layouts and not YYY-MM-DD tokens.

Configuration Fields

* **Input time** - the timestamp to convert
* **Input format** - the pattern describing how the input is currently written
* **Output format** - the pattern for how you want it written

Note that the two defaults differ: input assumes ISO 8601 with a Z, output defaults to a SQL-style space-separated timestamp. Left untouched, this node converts ISO to SQL format.

</details>

<details>

<summary>Get Current Time - <code>CTX.get_current_time</code></summary>

Return the current timestamp in whatever format you pick. There are no inputs.&#x20;

The output includes: value, format, category, timezone, timestamp, and unixMilliseconds.

* Everything is UTC. The node takes the workflow's clock and forces it to UTC before formatting.
* There is no timezone field.
* The clock is the workflow's, not the wall clock.
* A bad format fails the node.
* Custom pattern will be ignored unless format is set to custom.

Configuration Fields

* **Format** - which of the 16 output formats to use
  * │ ISO 8601 (UTC) │ 2025-12-31T23:59:59.000Z │ string │
  * │ ISO 8601 (UTC, no milliseconds) │ 2025-12-31T23:59:59Z │ string │
  * │ ISO 8601 (local offset) │ 2025-12-31T23:59:59.000-05:00 │ string │
  * │ RFC 3339 │ 2025-12-31T23:59:59.000Z │ string │
  * │ RFC 2822 (Email/HTTP) │ Wed, 31 Dec 2025 23:59:59 GMT │ string │
  * │ SQL Timestamp (UTC) │ 2025-12-31 23:59:59 │ string │
  * │ ISO Date │ 2025-12-31 │ string │
  * │ ISO Time │ 23:59:59 │ string │
  * │ Unix Timestamp (seconds) │ 1767225599 │ number │
  * │ Unix Timestamp (milliseconds) │ 1767225599000 │ number │
  * │ Unix Timestamp (microseconds) │ 1767225599000000 │ number │
  * │ Day of Week │ Monday │ string │
  * │ Day of Month │ 15 │ string │
  * │ Day of Year │ 365 │ string │
  * │ Week of Year │ 52 │ string │
  * │ Month │ December │ string │
  * │ Custom Format │ whatever your pattern produces │ string │
* **Custom pattern** - a pattern only used when format is set to custom

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.rewst.help/rewst-documentation/documentation/automations/nodes/nodes-data.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
