How to Sync Custom Fields in Xurrent

    This guide explains how to sync custom fields between Xurrent and remote systems using Exalate.

    Overview

    Xurrent custom fields are defined in UI Extensions attached to Request Templates. Each template can have its own set of custom fields with different types and validation rules.

    Prerequisites

    • API token must have ui_extensions permission to read custom field definitions
    • Know the templateId of the request (available as entity.templateId or replica.templateId)

    Outgoing Sync (Xurrent → Remote System)

    To send custom fields from Xurrent to the remote system:

    // Send all custom fields
    replica.customFields = entity.customFields
    
    // Send specific custom fields by name
    replica.customFields."Distribution Center" = entity.customFields."Distribution Center"
    replica.customFields."Story Points" = entity.customFields."Story Points"
    
    //Send specific custom fields by name
    replica.customFields."Story Points" = entity.customFields."story_points"
    
    // Access custom field value directly
    replica.myCustomValue = entity.customFields."Priority Level"?.value
    

    Converting Select Field IDs to Labels

    Xurrent API returns internal IDs for select fields (e.g., value_1). To get the display label:

    // Get display label for a select field value
    def internalValue = entity.customFields."Company"?.value  // Returns: "value_2"
    def displayLabel = nodeHelper.getCustomFieldValueLabel(entity.templateId, "company", internalValue)
    // Returns: "Acme Corporation"
    
    replica.companyName = displayLabel
    

    Incoming Sync (Remote System → Xurrent)

    To receive custom fields from the remote system and set them in Xurrent:

    This method validates field names and values automatically:

    // Text fields
    entity.customFields."Description" = nodeHelper.getCustomField(entity.templateId, "Description", "Task details here")
    
    // Number fields
    entity.customFields."Story Points" = nodeHelper.getCustomField(entity.templateId, "Story Points", 5)
    entity.customFields."Cost Estimate" = nodeHelper.getCustomField(entity.templateId, "Cost Estimate", 1234.56)
    
    // Select fields (can use display label OR internal ID)
    entity.customFields."Priority" = nodeHelper.getCustomField(entity.templateId, "Priority", "High")
    entity.customFields."Company" = nodeHelper.getCustomField(entity.templateId, "Company", "value_1")  // Internal ID also works
    entity.customFields."company" = nodeHelper.getCustomField(entity.templateId, "company", "value_2")  // Internal ID for field name and value also works 
    
    // Date fields (must use YYYY-MM-DD format)
    entity.customFields."Due Date" = nodeHelper.getCustomField(entity.templateId, "Due Date", "2025-12-31")
    
    // DateTime fields (must use UTC format)
    entity.customFields."Meeting Time" = nodeHelper.getCustomField(entity.templateId, "Meeting Time", "2025-12-31T14:30:00Z")
    
    // Time fields (must use HH:mm format)
    entity.customFields."Start Time" = nodeHelper.getCustomField(entity.templateId, "Start Time", "09:30")
    
    // Email fields
    entity.customFields."Contact Email" = nodeHelper.getCustomField(entity.templateId, "Contact Email", "john.doe@company.com")
    
    // Rich text fields
    entity.customFields."Custom Description" = nodeHelper.getCustomField(entity.templateId, "Custom Description", "**Bold** and __italic__ text")
    entity.customFields."Custom Description" = nodeHelper.getCustomField(entity.templateId, "Custom Description", nodeHelper.convertJiraWikiToXurrent(replica.description)) // in case the remote is jira 
    entity.customFields."Custom Description" = nodeHelper.getCustomField(entity.templateId, "Custom Description", nodeHelper.convertHTMLToXurrent(replica.description)) // in case the remote is system which supports HTML fomatting 
    
    
    
    // Clear/reset a field (set to null or empty)
    entity.customFields."Optional Field" = nodeHelper.getCustomField(entity.templateId, "Optional Field", null)
    entity.customFields."Optional Field" = nodeHelper.getCustomField(entity.templateId, "Optional Field", "")
    



    Supported Field Types

    TypeFormatExample Value
    textAny string"Task details here"
    text area
    Any multiline string"Task details here for more details"
    rich_textXurrent rich text format"**bold** and __italic__"
    numberInteger or decimal42 or 1234.56
    checkbox
    boolean valuetrue or false
    selectOption label or internal ID"High" or "value_1"
    dateYYYY-MM-DD"2025-12-31"
    date_timeYYYY-MM-DDTHH:mm:ssZ (UTC)"2025-12-31T14:30:00Z"
    timeHH:mm"09:30"
    emailValid email address"user@example.com"

    Validation Rules and Expected Errors

    Select Fields

    Values must match an existing option (by label or internal ID).

    // Valid
    entity.customFields."Priority" = nodeHelper.getCustomField(templateId, "Priority", "High")
    entity.customFields."Priority" = nodeHelper.getCustomField(templateId, "Priority", "value_1")
    
    // Invalid - throws error
    entity.customFields."Priority" = nodeHelper.getCustomField(templateId, "Priority", "SuperHigh")
    

    Error:

    Invalid value 'SuperHigh' for custom field 'Priority'.
    Available options: "Low" (id: value_1), "Medium" (id: value_2), "High" (id: value_3)
    

    Number Fields

    Values must be valid integers or decimals.

    // Valid
    entity.customFields."Points" = nodeHelper.getCustomField(templateId, "Points", 5)
    entity.customFields."Points" = nodeHelper.getCustomField(templateId, "Points", "5")
    entity.customFields."Cost" = nodeHelper.getCustomField(templateId, "Cost", 123.45)
    
    // Invalid - throws error
    entity.customFields."Points" = nodeHelper.getCustomField(templateId, "Points", "five")
    

    Error:

    Invalid number value 'five' for custom field 'Points'.
    Expected a valid number (integer or decimal).
    

    Email Fields

    Values must be valid email addresses.

    // Valid
    entity.customFields."Contact" = nodeHelper.getCustomField(templateId, "Contact", "user@example.com")
    
    // Invalid - throws error
    entity.customFields."Contact" = nodeHelper.getCustomField(templateId, "Contact", "not-an-email")
    

    Error:

    Invalid email format 'not-an-email' for custom field 'Contact'.
    Expected a valid email address (e.g., user@example.com).
    

    DateTime Fields

    Values must be in UTC format: YYYY-MM-DDTHH:mm:ssZ

    // Valid
    entity.customFields."Meeting" = nodeHelper.getCustomField(templateId, "Meeting", "2025-12-31T14:30:00Z")
    entity.customFields."Meeting" = nodeHelper.getCustomField(templateId, "Meeting", "2025-12-31T14:30:00.123Z")
    
    // Invalid - throws error
    entity.customFields."Meeting" = nodeHelper.getCustomField(templateId, "Meeting", "2025-12-31 14:30:00")
    entity.customFields."Meeting" = nodeHelper.getCustomField(templateId, "Meeting", "12/31/2025")
    

    Error:

    Invalid datetime format '2025-12-31 14:30:00' for custom field 'Meeting'.
    Expected UTC format: yyyy-MM-ddTHH:mm:ssZ (e.g., 2025-12-02T10:11:00Z).
    Note: Xurrent expects datetime in UTC. The UI will display in user's timezone based on profile settings.
    

    Date Fields

    Values must be in format: YYYY-MM-DD

    // Valid
    entity.customFields."Due Date" = nodeHelper.getCustomField(templateId, "Due Date", "2025-12-31")
    
    // Invalid - throws error
    entity.customFields."Due Date" = nodeHelper.getCustomField(templateId, "Due Date", "12/31/2025")
    entity.customFields."Due Date" = nodeHelper.getCustomField(templateId, "Due Date", "31-12-2025")
    

    Error:

    Invalid date format '12/31/2025' for custom field 'Due Date'.
    Expected format: yyyy-MM-dd (e.g., 2025-12-03).
    

    Time Fields

    Values must be in format: HH:mm

    // Valid
    entity.customFields."Start Time" = nodeHelper.getCustomField(templateId, "Start Time", "09:30")
    entity.customFields."Start Time" = nodeHelper.getCustomField(templateId, "Start Time", "14:00")
    
    // Invalid - throws error
    entity.customFields."Start Time" = nodeHelper.getCustomField(templateId, "Start Time", "9:30 AM")
    entity.customFields."Start Time" = nodeHelper.getCustomField(templateId, "Start Time", "9:30")
    

    Error:

    Invalid time format '9:30 AM' for custom field 'Start Time'.
    Expected format: HH:mm (e.g., 12:30 or 09:05).
    

    Field Not Found

    When the field name doesn't exist in the template:

    entity.customFields."NonExistent" = nodeHelper.getCustomField(templateId, "NonExistent", "value")
    

    Error:

    Custom field 'NonExistent' not found in template 12345.
    Available fields: "Priority" (id: priority), "Description" (id: description), "Due Date" (id: due_date)
    

    No Custom Field Definitions

    When the template has no UI extension or API token lacks permissions:

    entity.customFields."Field" = nodeHelper.getCustomField(templateId, "Field", "value")
    

    Error:

    No custom field definitions found for template 12345.
    Ensure the template has a UI extension with custom fields defined,
    and your API token has permission to access ui_extensions.
    

    Helper Methods Reference

    getCustomField(templateId, fieldName, value)

    Creates a validated custom field object.

    def cf = nodeHelper.getCustomField(entity.templateId, "Priority", "High")
    entity.customFields."Priority" = cf
    

    Troubleshooting

    "No custom field definitions found"

    1. Verify the template has a UI extension attached
    2. Check API token has ui_extensions permission
    3. Verify the templateId is correct

    "Invalid value 'X' for custom field"

    1. For select fields, check available options in Xurrent UI
    2. Use the exact option label or internal ID
    3. Check for typos or extra whitespace

    DateTime displaying wrong time

    • Xurrent expects UTC format (Z suffix)
    • The UI displays time in user's timezone based on profile settings
    • Always send UTC, Xurrent handles timezone conversion

    Important Notes

    1. Date Format: Date fields must use YYYY-MM-DD format
    2. DateTime Format: DateTime fields must use UTC format YYYY-MM-DDTHH:mm:ssZ
    3. Time Format: Time fields must use HH:mm format (24-hour, zero-padded)
    4. Select Fields: Values must match existing options exactly (label or internal ID)
    5. Null/Empty Values: Setting null or empty string clears/resets the field
    6. Permissions: API token needs ui_extensions permission for field validation

    More information

    Have more questions? Ask the community