π Autologyx β Merge Fields Guide β
Merge fields let you dynamically insert values from Object Records into documents, emails, API Actor parameters, and other resources.
π Table of Contents β
- Introduction
- Accessing Record Fields
- Field Types & Formatting
- Conditional Logic
- Record properties
- Images and Document Fields
- User and User Group Fields
- Related Records
- Loops and Iteration
- Filtering Records
- Images and Documents
- Tasks
- Date & Time Formatting
- Syntax Errors
π§© Introduction β
Merge fields (aka template tags) are used to dynamically access field values of Object Records using Jinja2 syntax. They are supported in:
- Document templates (e.g., DOCX),
- Email content and subject lines,
- API Actor parameter inputs,
- And any field where Object Record data is available.
π Accessing Record Fields β
To access a field value from a record, use:
{{ record.field_<alias> }}Example: β
If the field Date of Birth has alias date_of_birth, use:
{{ record.field_date_of_birth }}π§· Field Types & Formatting β
| Field Type | Merge Field Example | Output Example |
|---|---|---|
| String | {{ record.field_text }} | John |
| Integer | {{ record.field_int }} | 123 |
| Float | {{ record.field_float }} | 123.45 |
| Boolean | {{ record.field_bool }} | True / False |
| Enum | {{ record.field_enum }} | Apple |
| Set | {{ record.field_set }} | ['Apple', 'Pear'] |
{{ record.field_email }} | user@example.com | |
| Phone | {{ record.field_phone }} | 123456789 |
| Date | {{ record.field_date }} | 2023-04-17 |
| DateTime | {{ record.field_datetime }} | 2023-04-17 12:37:00+02:00 |
| Time | {{ record.field_time }} | 12:37:00 |
| URL | {{ record.field_url }} | https://autologyx.com |
| JSON | {{ record.field_json }} | {"key": "value"} |
| Document | {{ record.field_document }} | List of documents (with URLs) |
| User Field | {{ record.field_<alias>.users }} | List of user objects |
| Group Field | {{ record.field_<alias>.user_groups }} | List of groups |
INFO
π Complex types such as Document, User, and Group require a detailed description of their structure and how to access their properties. Detailed information about these types can be found in the following sections of this guide.
You can format the output using filters. These are applied by appending a pipe (|) and the filter name to the field.
| Filter | Example | Output Example |
|---|---|---|
date | {{ record.field_date | date('%d %B %Y') }} | 17 April 2023 |
datetime | {{ record.field_datetime | datetime('%H:%M') }} | 12:37 |
default | {{ record.field | default('N/A') }} | If field is empty β N/A |
join | {{ record.field_set | join(', ') }} | Apple, Pear |
length | {{ record.field_set | length }} | 2 |
lower / upper | {{ record.field_text | upper }} | JOHN |
capitalize | {{ record.field_text | capitalize }} | John |
replace | {{ record.field_text | replace('a', 'b') }} | Replaces a with b |
π§ͺ Conditional Logic β
You can use if statements to show or hide parts of the template based on field values.
Basic condition β
{% if record.field_status == 'active' %}
Status: Active
{% endif %}If / Else β
{% if record.field_price > 0 %}
Paid: {{ record.field_price }} β¬
{% else %}
Free
{% endif %}Nested conditions β
{% if record.field_status %}
{% if record.field_status == 'archived' %}
Archived
{% else %}
Active
{% endif %}
{% endif %}You can also use in, not in, and, or, etc.
{% if record.field_status in ['new', 'open'] and record.field_priority == 'high' %}
Urgent!
{% endif %}π§Ύ Record Properties β
The following Object Record properties can be accessed using merge fields in templates:
| Property | Merge Field Syntax | Type |
|---|---|---|
| ID | {{ record.id }} | Integer |
| Created | {{ record.created_at }} | Date/time |
| Modified | {{ record.modified_at }} | Date/time |
βΉοΈ Notes β
The shorthand
{{ record }}will be automatically substituted with the record.id property.
INFO
π Jinja merge fields do not support referencing the record identifier field using the syntax <<record.identifier>>.
π Images & Documents β
Image Fields
πΌοΈ Related records containing image fields can be processed using dedicated image filters. See Image Processing for details.
Document fields store files (PDF, DOCX, images, etc.) and are accessible via:
{{ record.field_<alias_document> }}π€ Example Output β
[
{
"id": 53,
"name": "template.docx",
"size": 10151,
"url": "https://url.to.the.file",
"mimetype": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
},
{
"id": 54,
"name": "certificate.png",
"size": 2016000,
"url": "https://url.to.the.file",
"mimetype": "image/png"
},
{
"id": 55,
"name": "smash.gif",
"size": 112296,
"url": "https://url.to.the.file",
"mimetype": "image/gif"
}
]ποΈ Document Object Structure β
Each document field returns an array of document objects with the following properties:
| Property | Type | Description |
|---|---|---|
id | integer | Unique document ID |
name | string | File name with extension |
size | integer | File size in bytes |
url | string | Download URL |
uuid | string | |
mimetype | string | Type and file format |
base64 | string | Base64 encoded content - hidden |
π― Accessing Document Properties β
{{ record.field_document[0].name }}
{{ record.field_document[0].url }}
{{ record.field_document[0].mimetype }}
{{ record.field_document[0].size }}
{{ record.field_document[0].base64 }}π‘ Examples β
Generate download links:
{% for doc in record.field_contracts %}
- [Download {{ doc.name }}]({{ doc.url }}) ({{ doc.size }} bytes)
{% endfor %}Output:
- [Download contract_2023.pdf](https://url.to.the.file) (245760 bytes)
- [Download agreement_final.docx](https://url.to.the.file) (89432 bytes)
- [Download terms_conditions.pdf](https://url.to.the.file) (156890 bytes)Accessing Base64 Content:
The base64 property contains the Base64-encoded content of the document file, which allows you to embed or process the actual file data.
{{ record.field_document[0].base64 }}Output:
JVBERi0xLjQKJcfsj6IKNSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0KL0NvdW50IDEKL01lZGlhQm94IFswIDAgNTk1IDg0Ml0KPj4KZW5kb2JqCjMgMCBvYmoK...Embed image directly in HTML:
{% for image in record.field_photos %}
<img src="data:image/{{ image.name.split('.')[-1] }};base64,{{ image.base64 }}" alt="{{ image.name }}" />
{% endfor %}Output:
<img src="data:image/jpg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k=" alt="profile_photo.jpg" />
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChAGA4nRuCwAAAABJRU5ErkJggg==" alt="avatar.png" />
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="animation.gif" />Embed image directly in HTML:
{% for csv in record.field_attachments %}
<a href="data:text/csv;base64,{{ csv.base64 }}" download="{{ csv.name }}">
Download {{ csv.name }}
</a>
{% endfor %}Output:
<a href="data:text/csv;base64,TmFtZSxBZ2UsQ2l0eQpKb2huLDI1LE5ldyBZb3JrCkphbmUsIDMwLCBMb3MgQW5nZWxlcwpCb2IsIDM1LCBDaGljYWdv" download="employees.csv">
Download employees.csv
</a>
<a href="data:text/csv;base64,UHJvZHVjdCxQcmljZSxRdWFudGl0eQpBcHBsZSwxLjUwLDEwMApCYW5hbmEsMC43NSw1MApPcmFuZ2UsMi4wMCwyNQ==" download="inventory.csv">
Download inventory.csv
</a>
<a href="data:text/csv;base64,RGF0ZSxSZXZlbnVlLEV4cGVuc2VzCjIwMjMtMDEtMDEsMTAwMDAsMjAwMApASDMjLTAyLTAxLDE1MDAwLDMwMDA=" download="financial_report.csv">
Download financial_report.csv
</a>β οΈ Important Notes
- Empty document fields return an empty array
[] - Accessing invalid indices or non-existing properties returns an empty string
- Base64 property is only accessible through direct indexing:
{{ record.field_document[0].base64 }} - Legacy format
<<object_record.field_document>>is supported but cannot be mixed with new syntax
π€ User and π₯ User Groups β
User-type fields in Autologyx can contain references to both users and user groups. These fields support two different approaches for accessing data: ID-based access for compatibility with existing systems, and object-based access for enhanced functionality.
π’ ID-Based Access (Legacy Compatibility) β
The traditional approach returns lists of IDs, maintaining compatibility with existing configurations:
{{ record.field_user }}Returns an object containing both user IDs and user group IDs.
π Example Output: β
{ "users": [123, 456, 789], "user_groups": [10, 20] }{{ record.field_user.user_groups }}Returns an array of user group IDs only.
π― Object-Based Access (Enhanced Functionality) β
For accessing full user and group objects with all their properties, use the .meta syntax:
{{ record.field_user.meta.users }}Returns an array of user objects only.
{{ record.field_user.meta.meta.user_groups }}Returns an array of user group objects only.
π€ User Object Properties β
When using .meta.users, each user object contains:
| Property | Type | Description |
|---|---|---|
id | integer | User ID |
first_name | string | User's first name |
last_name | string | User's last name |
username | string | Email address |
company_name | string | Company name |
phone | string | Phone number |
mobile | string | Mobile phone number |
is_deleted | boolean | Deletion flag - hidden |
account_type | enum | Account type enum - hidden |
π Complete User Object Example: β
[
{
"id": 525,
"first_name": "Bridget",
"last_name": "Marquardt",
"username": "bridget.marquardt826@example.com",
"company_name": "",
"phone": "16253372",
"mobile": "27363737"
},
{
"id": 591,
"first_name": "Abelardo",
"last_name": "Gutkowski",
"username": "abelardo.gutkowski752@example.com",
"company_name": "",
"phone": "76235342",
"mobile": "93833722"
},
{
"id": 795,
"first_name": "Aaron",
"last_name": "Dalton",
"username": "aaron@example.domain",
"company_name": "",
"phone": "999383833",
"mobile": "0002923832"
}
]π Example usage: β
{% for user in record.field_assignees.meta.users %}
- {{ user.first_name }} {{ user.last_name }} ({{ user.username }})
{% endfor %}π Indexing Users β
You can access specific users by index:
{{ record.field_assignees.users[0] }}
{{ record.field_assignees.users[0].username }}
{{ record.field_assignees.users[1].first_name }}π΅οΈ Hidden Properties β
Some properties are not returned by default but can be accessed explicitly:
{{ record.field_assignees.users[0].is_deleted }}
{{ record.field_assignees.users[0].account_type }}π« Deleted Users Handling β
When a user is deleted from the system:
- Only the
idproperty is returned - All other properties are anonymized for privacy
- The user object will look like:
{"id": 525}
π Iteration Examples β
Basic User Loop β
{% for users in record.field_usertype.users %}
User ID: {{ users.id }}
Account type: {{ users.account_type }}
{% endfor %}Safe Property Access β
{% for user in record.field_assignees.users %}
{% if user.first_name %}
Active User: {{ user.first_name }} {{ user.last_name }}
{% else %}
Deleted User (ID: {{ user.id }})
{% endif %}
{% endfor %}π₯ User Group Object Properties β
When using .meta.user_groups, each group object contains:
id- User Group IDname- User Group namenum_of_members- Number of group membersmembers- User Group members (Property is hidden and direct access via .members is required)
π Complete User Group Object Example: β
[
{
"id": 525,
"name": "Team ABC",
"num_of_members": 20
},
{
"id": 999,
"name": "Lawyers united",
"num_of_members": 400
},
{
"id": 1249,
"name": "Research team",
"num_of_members": 6
}
]When using .meta.user_groups[index].members, each member object contains:
| Property | Type | Description |
|---|---|---|
id | integer | User ID |
first_name | string | User's first name |
last_name | string | User's last name |
username | string | Email address |
company_name | string | Company name |
phone | string | Phone number |
mobile | string | Mobile phone number |
is_deleted | boolean | Deletion flag - hidden |
account_type | enum | Account type enum - hidden |
π User Group members example: β
[
{
"id": 525,
"first_name": "Bridget",
"last_name": "Marquardt",
"username": "bridget.marquardt826@example.com",
"company_name": "",
"phone": "16253372",
"mobile": "27363737"
},
{
"id": 591,
"first_name": "Abelardo",
"last_name": "Gutkowski",
"username": "abelardo.gutkowski752@example.com",
"company_name": "",
"phone": "76235342",
"mobile": "93833722"
},
{
"id": 795,
"first_name": "Aaron",
"last_name": "Dalton",
"username": "aaron@example.domain",
"company_name": "",
"phone": "999383833",
"mobile": "0002923832"
}
]π Example: β
{% for group in record.field_teams.meta.user_groups %}
- {{ group.name }} ({{ group.num_of_members }} members)
{% endfor %}π Indexing User Groups β
You can access a specific user group by index:
{{ record.field_usertype.user_groups[0] }}
{{ record.field_usertype.user_groups[0].name }}
{{ record.field_usertype.user_groups[0].num_of_members }}π Mixed Access Example β
You can combine both users and groups in a single iteration:
{% for item in record.field_assignees.meta %}
{% if item.username %}
User: {{ item.first_name }} {{ item.last_name }}
{% else %}
Group: {{ item.name }} ({{ item.num_of_members }} members)
{% endif %}
{% endfor %}βοΈ Supported Contexts β
User-type merge fields work in:
- Document templates
- Sequencer actors (API Call, Send Message, Local Variable)
- Related records merge fields
- All other contexts where merge fields are supported
β οΈ User and Group Filed Error Handling β
- Invalid index:
{{ record.field_users.users[999] }}β returns empty string - Non-existing property:
{{ record.field_users.users[0].invalid_prop }}β returns empty string - Empty field: If no users are assigned, the array will be empty
[]
π Related Records β
Related records provide access to connected objects based on relationships defined in the Object Model. The same merge field syntax works for retrieving records at any relationship level β parents, grandparents, children, grandchildren, etc.
π― Basic Concept β
Related records are available based on the relationships defined in the Object Model for the Object Class of a given record. The relationship level doesn't affect the syntax β only the target Object Class ID matters.
π Syntax β
{{ record.related_records_<class_id> }}Where <class_id> represents the ID of the related Object Class, which may be related to the current record by any degree of separation.
ποΈ Data Structure β
When processed, the merge field returns an array of Record objects that can be:
- Displayed directly: Shows comma-separated record representations
- Indexed: Access specific records using array notation
- Iterated: Use loops to process multiple records
- Chained: Access related records of related records
π‘ Basic Examples β
Direct Access β
{{ record.related_records_2 }}
{{ record.related_records_1 }}
{{ record.related_records_4 }}Indexed Access β
{{ record.related_records_1[0] }}
{{ record.related_records_2[1] }}Field Access β
{{ record.related_records_1[0].field_first_name }}
{{ record.related_records_2[0].field_company_name }}π Nested Related Records β
You can access related records of related records using chained syntax:
{{ record.related_records_2[0].related_records_1 }}
{{ record.related_records_2[0].related_records_1[0].field_name }}π Iteration Examples β
Basic Loop β
{% for related_record in record.related_records_4 %}
ID: {{ related_record.id }} Name: {{ related_record.field_name }}
{% endfor %}Output:
ID: 42 Name: Project Alpha ID: 43 Name: Project BetaNested Loop with Related Records β
{% for parent in record.related_records_2 %}
Parent: {{ parent.field_name }}
{% for grandparent in parent.related_records_1 %}
- Grandparent: {{ grandparent.field_name }}
{% endfor %}
{% endfor %}Output:
- Grandparent: Company HQ Parent: Department B
- Grandparent: Company HQβ οΈ Error Handling β
- If the variable record is missing or misspelled, the merge field is removed (substituted by the empty string) from the generated document.
- If an undefined attribute is used record.<unknown_attr> , the merge field is removed (substituted by the empty string) from the generated document.
- If delimiters
{{ }}contain syntax error (e.g. one of them is missing), the document is not generated. The sequence will stop executing.
π― Use Cases β
Document Templates β
Contract between {{ record.field_company_name }} and:
{% for client in record.related_records_3 %}
- {{ client.field_name }} ({{ client.field_email }})
{% endfor %}Output:
Contract between Acme Corporation and:
- Smith & Associates (contact@smith-associates.com)
- Global Solutions Ltd (info@globalsolutions.com)
- Tech Innovations Inc (hello@techinnovations.com)API Responses β
{
"main_record": "{{ record.field_name }}",
"related_items": "{{record.related_records_5 }}"
}Output:
{
"main_record": "Project Alpha",
"related_items": "[101, 102, 103]"
}Email Templates β
Dear {{ record.field_contact_name }},
Your order includes the following items:
{% for item in record.related_records_6 %}
- {{ item.field_product_name }}: ${{ item.field_price }}
{% endfor %}
Total: ${{ record.field_total_amount }}Output:
Dear John Smith,
Your order includes the following items:
- Wireless Headphones: $149.99
- Bluetooth Speaker: $89.99
- Phone Case: $24.99
Total: $264.97Relationship Levels
π The same syntax works for any relationship level β whether accessing immediate parents/children or records several degrees removed in the relationship hierarchy.
Performance Consideration
β‘ Retrieving related records can be expensive for records with many relationships. Consider using filtering to fetch only the records you need.
Syntax Errors
π₯ Missing or malformed delimiters will cause document generation to fail and stop sequence execution entirely.
π Filtering Records β
Traversing relations and fetching related records from the database can be expensive β especially when a record has thousands of parents, grandparents, or children. Performance tests included in this spec have shown that unrestricted queries can result in significant delays.
Therefore, itβs crucial to fetch only the records you need, rather than retrieving all related records and filtering them later using {% if %} conditions.
To address this, a custom Jinja2 filter called filter_by is introduced.
π§ Syntax β
The filter_by filter allows passing any number of named parameters that correspond to field values. The filter returns only the records that match the given parameters.
record.related_records_<class_id> | filter_by(field1='value1', field2='value2')π§ Allowed parameters β
Only Recordβs properties and fields are accepted.
π Chaining Filters β
Multiple filter_by filters can be chained:
record.related_records_<class_id>
| filter_by(field1='value1')
| filter_by(field2='value2')Chained filters use AND logic β meaning the record must match all conditions across the chained filters.
π Example 1 β
{% for item in record.related_records_4
| filter_by(status='active', is_flagged=True)
| filter_by(category='urgent') %}
- {{ item.name }} ({{ item.status }}, {{ item.category }})
{% endfor %}In this example:
- The first filter_by matches records with either status == 'active' or is_flagged == True.
- The second filter_by limits results further to only those with category == 'urgent'.
Thus, the result includes only records that:
- Have either status 'active' or are flagged
and
- Belong to category 'urgent'
π Example 2 β
For a record of Object Class A, retrieve children of Object Class D, where:
- field_country == "UK" or field_country == "USA"
and
- field_status == "Active"
{{ record.related_records_4
| filter_by(field_country="UK", field_country="USA")
| filter_by(field_status="Active") }}This fetches only children of class D that are from the UK or USA and have status set to Active.
INFO
π This approach ensures efficient database queries and significantly reduces processing time for large record sets.
π Tasks β
Returns a list of task IDs ordered by ID descending (newest first).
{{ record.tasks_<template_id> }}π Example Usage β
Display task IDs from template ID 5
{% for task_id in record.tasks_5 %}
Task ID: {{ task_id }}
{% endfor %}Output:
Task ID: 1234
Task ID: 1233
Task ID: 1225π Date and Time Formatting β
You can format date and time fields in your templates using the strftime filter, which is part of Jinja2βs standard functionality.
This allows you to display dates in a human-readable or locale-specific format.
π€ Syntax β
{{ record.field_<alias>|strftime("%Y-%m-%d") }}field_<alias>β the field that contains a date/time value (e.g., field_due_date, created_at, modified_at).strftime(...)β a formatting function that takes a format string compatible with Python'sdatetime.strftime().
β Syntax Errors β
In the Autologyx Platform, MF syntax errors are handled in a practical and context-aware way, depending on where and how the rendering is triggered.
βοΈ General Behavior β
- If a merge field doesn't exist (e.g., incorrect name or missing field), the platform usually replaces it with an empty string (
"") instead of failing. - If there's an invalid Jinja syntax (e.g., unclosed tag, bad logic), an error is raised explicitly during rendering.
π§ͺ Where Errors Are Handled β
| Context | Behavior |
|---|---|
| Synchronous API test calls (e.g., βTestβ button) | The syntax error is returned in the API response, so it can be seen immediately. |
| Background task rendering (e.g., sequences) | The error is not shown to the user directly but is instead reported to Sentry for monitoring and debugging. |
| Missing field or safe failure | Returns "" (empty string), so templates don't break for missing but optional values. |
π§΅ Internal Logic β
- Merge field like
will not break the template β it renders as an empty string.{{ record.unknown_field }} - Syntax error like
{{ record.field_nameor{% if record.status = "Active" %}will raise an error. - If rendering occurs in background, errors go to Sentry logs.
- If rendering happens via manual trigger (like API), the error is included in the response.
π Example β
Invalid field name (safe fail):
Hello {{ record.fake_field }}!β Output:
Hello !Invalid syntax (error):
{{ record.nameβ Output (API response or Sentry):
TemplateSyntaxError: unexpected end of template, expected '}}'π§ Notes for Users β
WARNING
- π Always test templates using the βTestβ button or API call before deploying them in sequences.
- π Monitor Sentry for silent background rendering failures.
- π Avoid relying on automatic empty fallback if the field is critical.