Skip to content

πŸ“„ 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 ​

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:

jinja
{{ record.field_<alias> }}

Example: ​

If the field Date of Birth has alias date_of_birth, use:

jinja
{{ record.field_date_of_birth }}

🧷 Field Types & Formatting ​

Field TypeMerge Field ExampleOutput 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']
Email{{ 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_&lt;alias&gt;.users }}List of user objects
Group Field{{ record.field_&lt;alias&gt;.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.

FilterExampleOutput 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 ​

jinja
{% if record.field_status == 'active' %}
  Status: Active
{% endif %}

If / Else ​

jinja
{% if record.field_price > 0 %}
  Paid: {{ record.field_price }} €
{% else %}
  Free
{% endif %}

Nested conditions ​

jinja
{% if record.field_status %}
  {% if record.field_status == 'archived' %}
    Archived
  {% else %}
    Active
  {% endif %}
{% endif %}

You can also use in, not in, and, or, etc.

jinja
{% 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:

PropertyMerge Field SyntaxType
ID{{ record.id }}Integer
Created{{ record.created_at }}Date/time
Modified{{ record.modified_at }}Date/time

ℹ️ Notes ​

The shorthand

jinja
{{ 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:

jinja
{{ record.field_<alias_document> }}

πŸ“€ Example Output ​

json
[
  {
    "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:

PropertyTypeDescription
idintegerUnique document ID
namestringFile name with extension
sizeintegerFile size in bytes
urlstringDownload URL
uuidstring
mimetypestringType and file format
base64stringBase64 encoded content - hidden

🎯 Accessing Document Properties ​

jinja
{{ 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:

jinja
{% for doc in record.field_contracts %}
- [Download {{ doc.name }}]({{ doc.url }}) ({{ doc.size }} bytes) 
{% endfor %}

Output:

text
- [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.

jinja
{{ record.field_document[0].base64 }}

Output:

text
JVBERi0xLjQKJcfsj6IKNSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0KL0NvdW50IDEKL01lZGlhQm94IFswIDAgNTk1IDg0Ml0KPj4KZW5kb2JqCjMgMCBvYmoK...

Embed image directly in HTML:

jinja
{% for image in record.field_photos %}
    <img src="data:image/{{ image.name.split('.')[-1] }};base64,{{ image.base64 }}" alt="{{ image.name }}" />
{% endfor %}

Output:

text
<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:

jinja
{% for csv in record.field_attachments %}
<a href="data:text/csv;base64,{{ csv.base64 }}" download="{{ csv.name }}">
    Download {{ csv.name }}
</a>
{% endfor %}

Output:

text
<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:

jinja
{{ record.field_user }}

Returns an object containing both user IDs and user group IDs.

πŸ“˜ Example Output: ​

json
{ "users": [123, 456, 789], "user_groups": [10, 20] }
jinja
{{ 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:

jinja
{{ record.field_user.meta.users }}

Returns an array of user objects only.

jinja
{{ 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:

PropertyTypeDescription
idintegerUser ID
first_namestringUser's first name
last_namestringUser's last name
usernamestringEmail address
company_namestringCompany name
phonestringPhone number
mobilestringMobile phone number
is_deletedbooleanDeletion flag - hidden
account_typeenumAccount type enum - hidden

πŸ“˜ Complete User Object Example: ​

json
  [
    {
      "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: ​

jinja
{% 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:

jinja
{{ 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:

jinja
{{ 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 id property is returned
  • All other properties are anonymized for privacy
  • The user object will look like: {"id": 525}

πŸ”„ Iteration Examples ​

Basic User Loop ​

jinja
{% for users in record.field_usertype.users %} 
    User ID: {{ users.id }}
    Account type: {{ users.account_type }}
{% endfor %}

Safe Property Access ​

jinja
{% 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 ID
  • name - User Group name
  • num_of_members - Number of group members
  • members - User Group members (Property is hidden and direct access via .members is required)

πŸ“˜ Complete User Group Object Example: ​

json
    [
    {
      "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:

PropertyTypeDescription
idintegerUser ID
first_namestringUser's first name
last_namestringUser's last name
usernamestringEmail address
company_namestringCompany name
phonestringPhone number
mobilestringMobile phone number
is_deletedbooleanDeletion flag - hidden
account_typeenumAccount type enum - hidden

πŸ“˜ User Group members example: ​

json
  [
    {
      "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: ​

jinja
{% 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:

jinja
{{ 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:

jinja
{% 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 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 ​

jinja
{{ 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 ​

jinja
{{ record.related_records_2 }}
{{ record.related_records_1 }}
{{ record.related_records_4 }}

Indexed Access ​

jinja
{{ record.related_records_1[0] }}
{{ record.related_records_2[1] }}

Field Access ​

jinja
{{ record.related_records_1[0].field_first_name }}
{{ record.related_records_2[0].field_company_name }}

You can access related records of related records using chained syntax:

jinja
{{ record.related_records_2[0].related_records_1 }}
{{ record.related_records_2[0].related_records_1[0].field_name }}

πŸ” Iteration Examples ​

Basic Loop ​

jinja
{% for related_record in record.related_records_4 %} 
    ID: {{ related_record.id }} Name: {{ related_record.field_name }} 
{% endfor %}

Output:

text
ID: 42 Name: Project Alpha ID: 43 Name: Project Beta
jinja
{% 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:

text
- 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 ​

jinja
Contract between {{ record.field_company_name }} and: 
{% for client in record.related_records_3 %}
- {{ client.field_name }} ({{ client.field_email }}) 
{% endfor %}

Output:

text
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 ​

jinja
{ 
    "main_record": "{{ record.field_name }}", 
    "related_items": "{{record.related_records_5 }}" 
}

Output:

json
{ 
    "main_record": "Project Alpha", 
    "related_items": "[101, 102, 103]" 
}

Email Templates ​

jinja
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:

text
Dear John Smith,

Your order includes the following items:
- Wireless Headphones: $149.99
- Bluetooth Speaker: $89.99
- Phone Case: $24.99

Total: $264.97

Relationship 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.

jinja
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:

jinja
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 ​

jinja
{% 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"
jinja
{{ 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).

jinja
{{ record.tasks_<template_id> }}

πŸ“˜ Example Usage ​

Display task IDs from template ID 5

jinja
{% for task_id in record.tasks_5 %}
    Task ID: {{ task_id }}
{% endfor %}

Output:

text
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 ​

jinja
{{ record.field_<alias>|strftime("%Y-%m-%d") }}
  • field_&lt;alias&gt; – 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's datetime.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 ​

ContextBehavior
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 failureReturns "" (empty string), so templates don't break for missing but optional values.

🧡 Internal Logic ​

  • Merge field like {{ record.unknown_field }} will not break the template β€” it renders as an empty string.
  • Syntax error like {{ record.field_name or {% 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):

jinja
Hello {{ record.fake_field }}!

βœ… Output:

Hello !

Invalid syntax (error):

jinja
{{ 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.