---
title: Rich text references · Tallyfy Pro
description: Tallyfy's API accepts specific HTML markup patterns for referencing form field answers, snippets, templates and people within rich text fields, where each reference type requires exact class names and identifiers read from the API to ensure chips survive editing and resolve correctly at render time.
lastUpdated: 2026-09-11T00:00:00.000Z
source_url:
  html: https://tallyfy.com/products/pro/integrations/open-api/rich-text-references/
  md: https://tallyfy.com/products/pro/integrations/open-api/rich-text-references/index.md
---

## Referencing form fields, snippets and people through the API

Several Tallyfy fields accept HTML rather than plain text, and inside that HTML you can point at something else: the answer someone gave to a form field, a saved snippet, another template, or a person. Each kind of reference is a small piece of markup with an identifier in it. Send the markup exactly as shown below and Tallyfy will recognise it in the template editor and in the running task.

Not every kind survives the trip into an email, though, and the ones that don’t are called out where they come up.

This page is the format reference. If you only need one thing from it, it is this: a form field reference is a `span` carrying the classes `insert-variable-tag fr-deletable`, and the field’s alias in double curly braces is the text inside it.

### Send the markup, not just the braces

Plain `{{alias}}` text with no wrapping `span` is the single most common mistake, and it’s hard to spot because it half works.

Tallyfy accepts it, and the person doing the task sees the right value, because the substitution that swaps in the answer matches the braces alone. But the template editor recognises a variable by the `span`, not by the braces. Without it, the reference shows as ordinary text that anyone editing the template can type into, split or delete without realising they’ve broken anything.

So the braces make it render. The `span` makes it survive editing. You want both.

## Which parameters accept references

| Parameter | Where it appears | Takes markup? |
| - | - | - |
| `summary` | The description on a step or a task. | Yes. |
| `guidance` | The help text on a form field. | Yes. |
| `default_value` | The pre-filled answer on a text or large text form field. | Yes. |
| `kickoff_description` | The instructions shown above a kick-off form. | Yes. |
| `title` | The name of a step or a task. | No. Plain text. |
| `name` | The name of a process. | No. Plain text. |
| `content` | The body of a comment. | Yes, but nothing resolves. See below. |

`title` and `name` hold text, not markup. Use the braces on their own there and leave the `span` out.

A process is named with `name`. It isn’t `title`, and sending `title` on a process does nothing at all.

Comments are the exception to this whole page. A comment keeps whatever HTML you put in `content`, but Tallyfy never swaps a form field answer into a comment, so `{{alias}}` there stays on the page as the literal text `{{alias}}`. Mentions are the one thing that does work in a comment, and the `+email` form works only there.

## The seven reference types

| Reference | Markup | Identifier it carries |
| - | - | - |
| Form field variable | `span.insert-variable-tag` | The field’s `alias`. |
| System variable | `span.insert-variable-tag` | One of four reserved names. |
| Snippet | `span.insert-snippet-tag` | A snippet `id`. |
| Embedded template | `span.insert-blueprint-tag` | A template `id`. |
| Inline document field | `editor-form-field` | A kick-off field `id`. |
| Person or group mention | `@[id]` in the text | A member or group `id`. |
| Email mention, comments only | `+email` in the text | An email address. |

The last two are not HTML at all. They are written straight into the text.

The `+email` one is narrower than it looks. It works in a comment and nowhere else, and it assigns the person rather than just naming them.

## Form field variable

This is the common one. It shows the answer somebody gave to a form field, wherever that text is read. Comments are the exception, as above.

```html
<span class="insert-variable-tag fr-deletable" contenteditable="false">{{customer-name-4821}}</span>&nbsp;
```

Three things matter here.

The two classes are both needed. `insert-variable-tag` is what marks it as a variable, and `fr-deletable` is what lets a person remove the whole chip in one keystroke instead of picking it apart character by character.

`contenteditable="false"` stops the editor putting a cursor inside the chip.

The text inside the `span` is the field’s `alias` in double curly braces. Read that alias from the API and never invent one. It’s returned on the form field object, and it usually ends in a few characters that make it unique, so guessing from the field’s label won’t work.

Put a space after the chip. Tallyfy’s own editor writes `&nbsp;`, which keeps the chip and the next word from running together.

Whitespace inside the braces is tolerated, so `{{ alias }}` resolves the same as `{{alias}}`. A zero-width no-break space (U+FEFF) immediately either side of the braces is tolerated too, because content written by Tallyfy’s older editor carries them. You don’t need to send one.

### Where to get the alias

Both kinds of form field carry an `alias`, and both are read from the template.

* **Kick-off fields** come back in the template payload, under `prerun`. You get these by default.
* **Step form fields** come back on each step, under `captures`. You only get these if you ask for the steps.

Ask for the steps with `?with=steps`:

```bash
curl "https://go.tallyfy.com/api/organizations/{org_id}/checklists/{checklist_id}?with=steps" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "X-Tallyfy-Client: APIClient"
```

Leave `?with=steps` off and there is no `steps` array in the response, so there are no `captures` either. The reply still looks complete. You get the template, its `prerun` array and all its settings, and nothing in it says the steps were left out. If you’re hunting for a step field’s alias and can’t find one, check the query string before you check anything else.

Each field object carries both identifiers you might need: `alias`, for the variable markup on this page, and `id`, for the inline document field further down. They are not interchangeable.

## System variable

Four names are reserved. They use the same `span` as a form field variable, with the reserved name in place of an alias.

| Name | What it resolves to |
| - | - |
| `DATE` | The date and time the process started. |
| `TEMPLATE_NAME` | The title of the template the process came from. |
| `current-process-id` | The id of the process the task belongs to. |
| `current-task-id` | The id of the task itself. |

```html
<span class="insert-variable-tag fr-deletable" contenteditable="false">{{TEMPLATE_NAME}}</span>&nbsp;
```

`DATE` and `TEMPLATE_NAME` are the broad pair. They work in task titles, task descriptions and process names, and in `kickoff_description`, `guidance` and `default_value` too.

`current-process-id` and `current-task-id` are narrower. They only work in task titles and descriptions. Anywhere else they stay on the page as literal text.

The names are matched exactly, so the capitalisation above is part of the contract.

## Snippet

A snippet is a saved block of text. Inside Tallyfy, the reference is swapped for the snippet’s current body when somebody opens the text, so editing the snippet updates every task that points at it.

```html
<span class="insert-snippet-tag fr-deletable" contenteditable="false" data-snippet-id="1042">[[Refund policy]]</span>&nbsp;
```

The `data-snippet-id` attribute is what resolves. The `[[Refund policy]]` text inside is the label.

### The swap only happens inside Tallyfy

The Tallyfy app does the swap. The server doesn’t, so nothing else does either.

Read that step back through the API and you get the markup exactly as you stored it. More importantly, when Tallyfy emails a task to somebody, the snippet body isn’t in that email. The `span` is just a wrapper in an email, so your reader sees the words inside it: `[[Refund policy]]`, and not the refund policy.

That changes what the label is for. Write it so it makes sense to somebody who will only ever see the label. “\[\[Refund policy]]” does that. “\[\[snippet 1042]]” doesn’t.

Snippet ids are numeric. List them from the text templates endpoint:

```bash
curl "https://go.tallyfy.com/api/organizations/{org_id}/text-templates" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "X-Tallyfy-Client: APIClient"
```

## Embedded template

This shows another template inside the text, expanded so the reader can see its steps.

```html
<span class="insert-blueprint-tag fr-deletable" contenteditable="false" data-blueprint-id="{checklist_id}">[[Employee onboarding]]</span>&nbsp;
```

`data-blueprint-id` holds a template `id`, the same id the templates endpoint returns.

This expands inside Tallyfy only, exactly like a snippet. In an email, or in anything reading the raw API, the bracketed text is all anyone sees. So write a label that stands on its own.

## Inline document field

Document templates are the exception to everything above. Instead of referencing a field, an inline document field *is* the field, placed in the middle of the document for someone to fill in.

It also has its own quoting rule, and that rule is the mistake that costs people an afternoon.

```html
<editor-form-field
  class="fr-fil fr-dib fr-draggable"
  contenteditable="false"
  draggable="true"
  data-editor-scope="this"
  data-field-id="'{prerun_id}'"
  data-field-label="'Signature date'"
  data-field-type="'date'"
></editor-form-field>&nbsp;
```

### Single-quote the values

Look closely at each value. There’s a single quote inside the double quotes: `data-field-id="'abc123'"`, not `data-field-id="abc123"`.

That isn’t a typo, and it isn’t optional. Tallyfy’s document editor reads these three attributes as expressions rather than as plain strings. The single quotes are what say “this is text”. Leave them off and the editor goes looking for something by that name, finds nothing, and the field never loads.

Do the same for `data-field-label` and `data-field-type`. All three take the quotes.

### Add `data-editor-scope="this"`

It’s how the chip finds the editor around it. Without it the chip can’t reach its field, so it shows the same reference error as a broken id even though your id is perfectly good. If you’re staring at that error on an id you’ve just checked, this attribute is the first thing to look for.

### The rest

`data-field-type` takes `text`, `textarea` or `date`.

Leave the element empty. The label comes from `data-field-label` and from the field itself, so anything you write between the tags is discarded.

`data-field-id` is the `id` the API returns on the kick-off field object. That’s the identifier to use, and it’s worth being careful here, because a field object carries several values that all look like plausible identifiers. Take `id` exactly as the API gives it to you. It stays the same as the template is edited over time, which is why it’s the one that works.

### The quotes matter a second time, much later

When somebody copies a document template, Tallyfy rewrites the field ids inside it so the copy points at the copy’s own fields.

That rewrite only recognises the single-quoted form. Markup written without the quotes sails through the copy untouched and then points at the **original** template’s fields. The copy looks fine. It fills in the wrong document.

This is also the one reference type that fails loudly rather than quietly. See the next section.

## Person, group and guest mentions

A mention is not HTML. It is written directly into the text.

```text
@[{user_id}] please review this before Friday.
```

The same form works for a group id. Use the ids returned by the members and groups endpoints.

The other form is a plus sign immediately followed by an email address:

```text
+someone@example.com is copied on this.
```

Two things about `+email` surprise people, and both matter more than the syntax does.

**It only works in a comment.** Put `+someone@example.com` in a step description, a task title or a kick-off description and nothing happens. It just sits there as ordinary text. Tallyfy reads this form when a comment is posted, and at no other moment.

**It assigns somebody. It doesn’t just name them.** The person becomes an assignee of the task or step that the comment is on. If the address belongs to a member of your organization, that member gets assigned. If it belongs to nobody yet, Tallyfy **creates a guest**, assigns them, and emails them an invitation.

So treat `+email` as a write, not a formatting choice. Guest invites are rate limited per organization, and a burst of them starts returning HTTP 429 with a `Retry-After` header.

## What happens when a reference stops resolving

Most of this is silent, which is what makes it worth knowing.

A reference can stop resolving for ordinary reasons. Someone deletes the form field, deletes the snippet, or removes the template. Nothing checks your markup at the moment you send it, and nothing warns anybody later.

| Reference | When it no longer resolves |
| - | - |
| Form field variable | Either blanked, or left on the page as `{{alias}}`. Depends where you’re reading it. |
| System variable | A name outside the four above counts as an unknown alias, so it behaves like the row above. |
| Snippet | The markup is stripped out of your stored text when the snippet is deleted. |
| Embedded template | Removed from the text when that template no longer exists. |
| Inline document field | Shows the visible text **Error - Reference does not exist**. |
| Person or group mention | Falls back to showing the raw id. |

Only the inline document field tells anyone something is wrong.

### A dead variable blanks in some places and stays visible in others

Two pieces of code sit behind this and they don’t agree. Which one runs depends on what you’re reading, not on what you wrote.

**It blanks** in a task’s `title` and `summary`. The sentence closes up. `Please call {{customer-name}} before Friday` becomes `Please call before Friday`, reads as though it was always written that way, and gives nobody a reason to look. This is the common case, and it’s the one that hurts.

**It stays visible**, as the literal text `{{customer-name}}`, in a form field’s `default_value` and in a template’s `guidance`, `summary` and `kickoff_description`. That’s ugly on the page, but it’s honest, and you’ll spot it in a second.

A process name is the third case. An unresolved variable blanks there, same as a task.

One more split worth knowing: `current-task-id` and `current-process-id` only resolve in a task’s title or description. Put either one in a `kickoff_description`, a `guidance` or a `default_value` and it stays on the page as literal text, because the code serving those columns only knows `DATE` and `TEMPLATE_NAME`.

### Permission is not the same as missing

A reader who can’t open an embedded template does **not** see the reference vanish. They see the bracketed label, with a note telling them they don’t have access.

Removal means something else: that template genuinely isn’t there any more. Tallyfy checks whether the id still exists, and that check says nothing about who may read it. So an embedded template that disappears is a deleted template. Chasing permissions is the wrong first move.

### Deleting a snippet rewrites your stored text

A snippet can’t be archived. There’s no archived state for one to sit in, and no way to bring a deleted one back.

Deleting one also reaches into every template and step that referenced it and strips the markup out of the stored content. The delete response lists what it changed, so read it. That edit is permanent, and recreating the snippet does not undo it.

Two consequences for anything you build.

Check the identifier exists before you write markup that carries it, because afterwards nothing tells you. If you’re copying a description from one template to another, remember that aliases and ids belong to the template they came from, so a copied reference will resolve in the original and blank out in the copy.

An empty render does not always mean the reference is broken. A form field that exists but has not been answered yet also renders as nothing, and the two cases look identical on the page.

## A worked example

A step description that greets somebody by name, pulls in a saved snippet, and mentions a colleague:

```json
{
  "title": "Welcome call",
  "summary": "<p>Call <span class=\"insert-variable-tag fr-deletable\" contenteditable=\"false\">{{customer-name-4821}}</span>&nbsp;to introduce yourself.</p><p><span class=\"insert-snippet-tag fr-deletable\" contenteditable=\"false\" data-snippet-id=\"1042\">[[Refund policy]]</span>&nbsp;</p><p>@[{user_id}] is your backup on this one.</p>"
}
```

Note the escaped quotes. The markup is a JSON string value, so every attribute quote needs escaping, and getting that wrong is a much easier mistake to make than getting the markup wrong.

## Checklist before you send

* Every alias and id was read from the API in this session, not remembered or guessed.
* Step field aliases came from a response you asked for with `?with=steps`.
* Variable chips carry both classes, `insert-variable-tag` and `fr-deletable`.
* Every chip carries `contenteditable="false"`.
* There is a space after each chip.
* Inline document fields single-quote their values, and carry `data-editor-scope="this"`.
* A process is named with `name`, not `title`.
* The ids belong to the template you are writing into.
* You opened the template in Tallyfy afterwards and saw chips, not plain text.

That last one takes ten seconds and is the only check that catches the failure this page exists to prevent.

## Related articles

[**Variables > Insert variables**](https://tallyfy.com/products/pro/documenting/templates/variables/how-can-i-use-insert-variables-in-tallyfy/)

Tallyfy lets you insert dynamic variables into step titles and descriptions by clicking the \[ ]…

[**Templates > Variables**](https://tallyfy.com/products/pro/documenting/templates/variables/)

Variables in Tallyfy are placeholders that automatically carry data entered in one process step…

[**Edit Task > The rich text editor**](https://tallyfy.com/products/pro/tracking-and-tasks/tasks/edit-task/how-can-i-use-tallyfys-rich-text-editor-for-tasks/)

Tallyfy’s built-in rich text editor lets you format text and add images and videos and dynamic…

[**Miscellaneous > Glossary**](https://tallyfy.com/products/pro/miscellaneous/glossary/)

A quick-reference glossary of Tallyfy platform terms. Covers templates, processes, automations…

## Was this helpful?
