Introduction: A Festive Integration Challenge
The decorations are up, and the holiday season is in full swing! Families are gathering, children are counting down the days on their Advent calendars, and here at The Integration Café, we've cooked up something special to celebrate.
This December, we're tackling a deliciously complex challenge: creating the perfect Glögi - that warming Finnish Christmas drink that's been bringing joy to winter celebrations for generations. But we're not just making any Glögi; we're using it as inspiration for a real-world integration scenario that many organizations face during the busy holiday season.
Just as traditional Glögi requires careful coordination of ingredients, timing, and technique, our integration scenario requires seamless coordination between two teams: the Kitchen team preparing festive Xmas drinks, and the Supplier team providing essential ingredients for the holiday feast.
This blogpost extends our Integration Café series, where we explore different integration approaches. Today, we're showing you how Exalate handles this festive challenge.
The Scenario: Kitchen Meets Supplier
The Challenge
Imagine running a bustling holiday operation where:
- The Kitchen Team uses Jira Service Management to manage requests for Xmas drinks (especially our star beverage, Glögi)
- The Supplier Team uses a separate Jira Service Management instance to manage ingredient requests and deliveries
- Both teams need to stay perfectly synchronized - when the Kitchen needs blackcurrants for the Glögi, the Supplier needs to know immediately!
Real-World Requirements
Our integration must handle three critical workflows:
- Request Creation: When the Kitchen sends a request to the Supplier (e.g., "We need 5kg of blackcurrants for tomorrow's Glögi batch!"), a corresponding request should automatically appear in the Supplier's system
- Comment & Attachment Syncing: When either team adds comments or attachments (like recipe adjustments or delivery confirmations), these updates should sync both ways in real-time
- Status Handover: When requests are handed over between Kitchen and Supplier, the status should update accordingly in both systems
This is the kind of scenario many organizations face: separate service desks that need to communicate seamlessly, especially during high-pressure periods like the holidays!
The Technical Setup
Our Two Jira Service Management Instances
We're working with two Jira Service Management Cloud instances:
- Kitchen Instance:
https://kitchen.atlassian.net - Supplier Instance:
https://supplier.atlassian.net
Each instance has its own projects, workflows, and teams, but they need to work together like ingredients in a perfect Glögi recipe.
Exalate: The Secret Ingredient
Exalate acts as the synchronization bridge that keeps these two systems in harmony. Think of it as the master chef who ensures every ingredient is added at the right time, in the right amount, creating a perfectly synchronized experience across both systems.
Unlike traditional integration platforms that focus on complex business logic and transformations, Exalate specializes in synchronization - ensuring that when something changes in one system, it's reflected in the other. This makes it particularly well-suited for scenarios where teams need to stay in sync across separate Jira instances.
Understanding Exalate
Before we dive into building the integration, let's understand Exalate - the real-time, bidirectional integration platform that enables synchronized data sharing between multiple business systems.
What is Exalate?
Exalate is a real-time, bidirectional integration platform designed for cross-team collaboration and cross-company integration scenarios. It enables synchronized data sharing between multiple business systems while maintaining complete control over what information is shared.
Exalate positions itself as a middle ground between rigid, template-based automation tools and expensive custom development, providing "the flexibility of a custom integration solution, with the convenience of a ready-to-use product."
Key Features of Exalate:
- Real-Time Bidirectional Sync: Changes in one system are immediately reflected in connected systems, enabling true real-time collaboration
- Multi-Platform Support: Connect diverse enterprise tools including Jira, ServiceNow, Azure DevOps, GitHub, Salesforce, Zendesk, Freshdesk, Freshservice, and Asana
- Flexible Scripting Engine: Use Groovy scripts for complex data transformation, conditional logic, and field mapping
- AI-Assisted Setup: Exalate AI helps streamline integration configuration and script generation
- Granular Control: Define exactly what data is shared and how it's transformed between systems
- Multiple Configuration Modes: Choose between Basic, Visual, or Script modes depending on complexity
- Script Helpers: Built-in utilities (
commentHelper,attachmentHelper,syncHelper) handle common synchronization patterns - Decentralized Architecture: Runs as apps installed directly on each platform, eliminating separate middleware infrastructure
Critical Installation Requirement
Important: For Exalate to work, the Exalate app MUST BE installed on both Jira instances involved in the synchronization:
- ✅ Install Exalate on
https://kitchen.atlassian.net - ✅ Install Exalate on
https://supplier.atlassian.net
This means you need two Exalate licenses - one for each instance. This is different from some middleware solutions where you only pay for the integration layer itself.
Building the Integration: Step by Step
Step 1: Setting Up Exalate
Let's walk through the complete Exalate setup process for connecting two Jira Cloud instances. This follows the Getting Started guide for Jira Cloud to Jira Cloud integration.
1.1 Install Exalate on Both Jira Instances
Following the Exalate installation guide, you need to install the Exalate app on both Jira Cloud instances:
For Kitchen Jira Instance:
- Log into
https://kitchen.atlassian.netas an administrator - Navigate to Apps → Find new apps (or visit the Atlassian Marketplace)
- Search for "Exalate"
- Click Get it now or Try it free
- Follow the installation prompts to add Exalate to your instance
- Accept the permissions and terms
For Supplier Jira Instance:
- Log into
https://supplier.atlassian.netas an administrator - Repeat the same installation process
- Install the Exalate app with appropriate permissions
Note: Each installation requires a separate license. Exalate offers trial periods to test the integration before committing to paid licenses.
1.2 Initiate the Connection (From Kitchen Side)
Following Step 1: Initiate a Connection in Script Mode:
On the Kitchen Jira Instance:
- Navigate to Apps → Exalate in the top menu
- Click Connections in the Exalate admin panel
- Click Initiate Connection
- Enter the URL of your Jira Cloud as the destination platform
- Choose Script Mode for configuration (gives us full control over synchronization logic)
- Provide a name for the connection: "Kitchen-Supplier Glögi Integration"
- Click Initiate
Exalate will generate the Invitation Code that you'll need to share with the Supplier instance.
1.3 Accept the Connection (From Supplier Side)
Following Step 2: Accept the Connection Invitation:
On the Supplier Jira Instance:
- Navigate to Apps → Exalate
- Click Connections
- Click Accept Invitation
- Paste the Connection URL or Invitation Code provided by the Kitchen instance
- Review the connection details
- Choose Script Mode to match the Kitchen configuration
- Click Accept
Once accepted, the connection is established and both sides can see it in their Exalate admin panel. The connection is now ready for configuration!
1.4 Verify Connection Status
On both instances, verify that the connection appears as Active in the Exalate connections list. You should see:
- Connection name: "Kitchen-Supplier Glögi Integration"
- Status: Active/Connected
- Remote instance details
- Configuration mode: Script Mode
Step 2: Configuring Triggers and Scripts
Unlike ScriptRunner Connect's event listeners, Exalate uses a different approach with Triggers and Outgoing/Incoming scripts.
Understanding Triggers
Triggers in Exalate are defined using JQL (Jira Query Language), which determines which issues should be synchronized. When an issue matches the JQL query, Exalate processes it through the outgoing and incoming scripts.
For our scenario, we have two directional triggers:
Kitchen → Supplier Trigger:
project = Kitchen
Supplier → Kitchen Trigger:
project = Supplier
These simple triggers ensure that any issue in the Kitchen project gets synchronized to Supplier, and vice versa. In production, you might add more specific conditions (e.g., project = Kitchen AND status != Done).
Understanding Outgoing and Incoming Scripts
Exalate uses Groovy scripts to transform data between systems:
- Outgoing Script: Runs on the source side, preparing data to send to the remote system
- Incoming Script: Runs on the destination side, receiving data and applying it to local issues
The replica object represents the data being synchronized, while the issue object represents the local Jira issue.
Let's configure scripts for both directions:
Kitchen → Supplier Configuration
Outgoing Script (from Kitchen):
def statusName = issue?.status?.name
def fieldSupplierKey = issue.customFields?."Supplier Key"
replica.statusName = statusName
replica.fieldSupplierKey = fieldSupplierKey
// Condition to create issue within Supplier
if(statusName == "Place order" && fieldSupplierKey?.value == null) {
replica.key = issue.key
replica.summary = issue.summary
replica.description = issue.description
}
// Send comments and attachments
if (fieldSupplierKey?.value != null) {
// Search for public comments with specific conditions
// Jira Cloud Automation used to assist in here
def publicComments = issue.comments.findAll{ comment ->
!comment.internal && comment.body?.trim()?.startsWith("[Sync Exalate] ")
}
// Send only public comments
replica.comments = publicComments
// All attachments are synced
replica.attachments = issue.attachments
}
Key observations:
- We only create a new Supplier issue when Kitchen status is "Place order" AND no Supplier key exists yet
- Comments are filtered to only sync those starting with "[Sync Exalate]" (we'll use Jira Automation to add this prefix)
- This filtering prevents infinite loops while allowing selective comment synchronization
- Attachments are synchronized when a link between issues already exists
Incoming Script (into Supplier):
// Condition to create reciprocal Work Item (formerly issue)
if (firstSync && replica.statusName == "Place order") {
issue.projectKey = "SUPPLIER"
issue.type = nodeHelper.getIssueType("Place your order", issue.projectKey)
issue.customFields."Request Type".value = "Place your order"
issue.summary = replica.summary
issue.description = replica.description
issue.customFields."Kitchen Key".value = replica.key
syncHelper.syncBackAfterProcessing()
}
// Synchronise comments
issue.comments = commentHelper.mergeComments(issue, replica, { comment ->
comment.body =
"[" + comment.author.displayName +
" <" + comment.author.email + ">]" +
" commented: \n" +
comment.body + "\n"
}
)
// Synchronise attachments
issue.attachments = attachmentHelper.mergeAttachments(issue, replica)
// Transition Work Item (formerly issue)
def remoteStatusName = replica?.statusName
if(issue?.status?.name != remoteStatusName) {
def statusMap = [
// "from replica": "into issue"
"Pending": "In Progress",
]
// Transition Work Item (formerly issue)
issue.setStatus(statusMap[remoteStatusName] ?: remoteStatusName)
}
Key features:
firstSyncflag ensures we only create the issue oncesyncHelper.syncBackAfterProcessing()triggers a reverse sync to update Kitchen with the Supplier keycommentHelper.mergeComments()handles comment synchronization with automatic loop preventionattachmentHelper.mergeAttachments()safely syncs attachments- Status mapping allows different status names between systems ("Pending" in Kitchen → "In Progress" in Supplier)
Supplier → Kitchen Configuration
Outgoing Script (from Supplier):
def statusName = issue?.status?.name
replica.key = issue.key
if(issue.customFields?."Kitchen Key"?.value) {
replica.statusName = statusName
}
Why so simple?
- We only need to send back the Supplier key and status updates
- All the heavy lifting (creating issues, syncing comments/attachments) happens in the Kitchen → Supplier direction
- This prevents duplicate synchronization and keeps the logic clean
Incoming Script (into Kitchen):
// Condition to return Supplier issue key to Kitchen
if(!issue?.customFields?."10128"?.value) {
issue?.customFields?."10128"?.value = replica.key
} else {
def remoteStatusName = replica?.statusName
if(issue?.status?.name != remoteStatusName) {
def statusMap = [
// "from replica": "into issue"
"Out for delivery": "Awaiting delivery",
]
// Transition Work Item (formerly Issue)
issue.setStatus(statusMap[remoteStatusName] ?: remoteStatusName)
}
}
What's happening:
- First sync: Store the Supplier key in Kitchen's custom field (field ID 10128 = "Supplier Key")
- Subsequent syncs: Update Kitchen's status when Supplier status changes
- Status mapping handles different workflow terminology ("Out for delivery" → "Awaiting delivery")
Step 3: Creating Jira Service Management Cloud Automation
Exalate has its own commentHelper script helper that work as a filtering strategy to prepend a marker to comments we want to synchronize.
In this scenario, we are using Jira Cloud Automation rule to prepend a marker to comments we want to synchronize instead of the
Why This Automation?
Remember in the Kitchen → Supplier outgoing script, we filter comments that start with [Sync Exalate]:
def publicComments = issue.comments.findAll{ comment ->
!comment.internal && comment.body?.trim()?.startsWith("[Sync Exalate] ")
}
This automation rule automatically adds that prefix, giving users control over which comments sync.
Setting Up the Automation Rule
In the Kitchen Jira instance, create a new automation rule:
Trigger:
- When: Work item commented
- Conditions:
- Comment Type is Comment is the main action (filters out automation-generated comments)
- Supplier key is not empty (only sync comments on linked requests)
Action:
- Then: Edit comment on work item
- Comment to edit: Last comment
- New comment body:
[Sync Exalate]
How it works:
- User adds a comment to a Kitchen request
- Automation immediately edits the comment to prepend
[Sync Exalate] - Exalate's outgoing script picks up the comment because it matches the filter
- Comment syncs to Supplier
Benefits:
- Users don't need to remember to add the prefix manually
- All comments on linked requests automatically sync
- Internal comments (not marked as main action) are excluded
- Clear visual indicator in both systems showing which comments were synchronized
Step 4: Testing and Publishing the Configuration
Following Step 4: Test and Activate:
Once you've configured your triggers and scripts, you need to test and activate the connection:
On Both Instances (Kitchen and Supplier):
1. Test the Configuration:
- Navigate to Apps → Exalate → Connections
- Select "Kitchen-Supplier Glögi Integration"
- Select a sample issue that matches your trigger (e.g., an issue in the Kitchen project)
- Run the test to see how the scripts execute
- Review the test results to verify data transformation
2. Review Script Execution:
- Check the outgoing script output (what data is being sent)
- Verify the incoming script behavior (how data is applied)
- Look for any errors or warnings in the test console
- Adjust scripts as needed based on test results
3. Publish/Activate the Connection:
- Once testing is successful, click Publish or Activate
- This makes the connection live and begins real-time synchronization
- Exalate will now monitor for issues matching your triggers
- When issues change, scripts will execute automatically
4. Monitor Active Synchronization:
- Use the Exalate admin panel to monitor sync activity
- Check the Sync Status or Activity Log to see recent synchronizations
- Review any errors or warnings that occur during live sync
- Access detailed logs for specific sync attempts if troubleshooting is needed
Managing the Connection
After activation, you can manage your connection through the Exalate interface:
- Edit Scripts: Update outgoing/incoming scripts as requirements change
- Modify Triggers: Adjust JQL queries to change which issues sync
- Pause/Resume: Temporarily disable synchronization without deleting the connection
- View Logs: Access detailed synchronization logs for troubleshooting
The connection configuration is managed directly within each Jira instance's Exalate app, not through an external console. This gives each side control over their own scripts and triggers while maintaining the bidirectional connection.
Testing the Integration: Does the Glögi Taste Right?
Just like you'd taste-test your Glögi before serving it to guests, we thoroughly tested our integration. However, unlike ScriptRunner Connect's local development options, Exalate testing happens entirely through the UI and connected Jira instances.
Test Scenario 1: Creating a New Request
Action: Kitchen creates a request for "5kg Fresh Blackcurrants for Glögi" and transitions it to "Place order"
Expected Result:
- Supplier request automatically created
- Summary and description copied correctly
- Kitchen Key stored in Supplier request
- Supplier Key synced back to Kitchen request
Actual Result: ✅ All expectations met!
Test Scenario 2: Comment Syncing
Action: Kitchen user adds comment: "Can we get organic blackcurrants instead?"
Expected Result:
- Automation prepends
[Sync Exalate]to the comment - Comment syncs to Supplier with author attribution
- Format:
[User Name <email>] commented: Can we get organic blackcurrants instead?
Actual Result: ✅ Perfect synchronization!
Test Scenario 3: Attachment Sharing
Action: Kitchen uploads "Updated Glögi Recipe v2.pdf"
Expected Result:
- Attachment syncs to Supplier request
- File integrity maintained
- Both teams can download and view
Actual Result: ✅ Flawless file transfer!
Test Scenario 4: Status Handover
Action: Supplier transitions request to "Out for delivery"
Expected Result:
- Kitchen request transitions to "Awaiting delivery" (per status mapping)
- Status synchronized within seconds
Actual Result: ✅ Smooth status synchronization!
Testing Constraints
Important to note:
- Testing can only be performed through the connected Jira Service Management instances
- The "Start Test Run" feature in SyncRoom helps validate script logic, but actual testing requires real Jira instances
- This differs from ScriptRunner Connect, where you can develop and test locally using IDEs
The Results: A Perfectly Brewed Integration
After implementing our Exalate integration, here's what the Kitchen and Supplier teams experienced:
Before Integration:
- ❌ Manual copying of request details between systems
- ❌ Risk of missing important comments or updates
- ❌ Status mismatches causing confusion
- ❌ Delays in communication during busy holiday rush
After Integration:
- ✅ Automatic request creation (saves ~10 minutes per request)
- ✅ Real-time comment and attachment syncing
- ✅ Synchronized status updates with configurable mappings
- ✅ Teams can focus on making great Glögi instead of manual data entry!
Note on Audit Trail: Unlike some integration approaches that maintain detailed audit logs of every sync operation, Exalate focuses on the synchronized data itself. The audit trail exists within the Jira issues (comments, history, attachments), but there isn't a separate detailed log of each synchronization event accessible to end users in the Jira or Exalate interface.
Key Takeaways: Exalate's Strengths
Through building this integration, we discovered several strengths of Exalate:
1. Synchronization-First Philosophy
Exalate excels at synchronization. The triggers, replica objects, and helper functions (commentHelper, attachmentHelper, syncHelper) are all designed specifically to keep systems in sync. You don't need to build synchronization logic from scratch - it's baked into the platform.
2. Powerful Script Helpers
The built-in script helpers like commentHelper.mergeComments() and attachmentHelper.mergeAttachments() handle complex scenarios automatically:
- Comment deduplication
- Attachment handling
- Loop prevention
- Conflict resolution
These helpers save significant development time and reduce the chance of synchronization bugs.
3. JQL-Based Triggers
Using JQL queries for triggers is intuitive for Jira administrators. Anyone familiar with Jira filters can define which issues should sync, without learning a new configuration language.
4. Direct Instance-to-Instance Connection
Unlike approaches requiring external management consoles, Exalate establishes direct connections between instances. Each side maintains control over their own configuration while participating in the synchronization.
5. Groovy Scripting Power
While simpler than ScriptRunner Connect's TypeScript approach, Groovy scripts in Exalate still provide substantial flexibility for data transformation, conditional logic, and field mapping. You can access the full Exalate object types and Jira fields and entities through the scripting API.
6. No Middleware Infrastructure
Since Exalate runs as apps installed on both Jira instances, there's no separate middleware server to maintain, monitor, or secure. This can simplify operations and reduce infrastructure costs.
7. Multi-Platform Capability
While our scenario uses Jira to Jira synchronization, Exalate supports diverse platforms (ServiceNow, Azure DevOps, Salesforce, Zendesk, etc.), making it valuable for heterogeneous integration landscapes.
Challenges and Considerations
To be fair, we should also mention challenges we encountered with Exalate:
1. Inconsistent Custom Field Handling
One frustrating aspect is the inconsistent API for custom fields:
// Sometimes using the custom field name:
issue.customFields."Supplier Key".value
// Other times using the custom field ID:
issue?.customFields?."10128"?.value
As noted in How to sync custom fields in Jira Cloud, the approach varies depending on context. This inconsistency creates confusion and requires trial-and-error during development.
2. Error Debugging Challenges
When errors occur, troubleshooting can be difficult:
- No Line Numbers: Error messages don't indicate which line of script failed
- Unhelpful Stack Traces: The stack trace often shows Exalate internals rather than your script context
- Navigation Required: Finding errors requires navigating through the Exalate admin interface
- Dependent on Support: For non-trivial errors, you often need to engage Exalate support for assistance
Error handling documentation provides some guidance, but debugging remains more challenging than in traditional development environments.
3. Learning Curve for Exalate
While Groovy is simpler than some languages, understanding Exalate's architecture requires learning:
- The replica object model
- Outgoing vs. incoming script responsibilities
- When to use which script helper
- How
firstSync,syncHelper.syncBackAfterProcessing(), and other mechanisms work
The Exalate object types and script helpers documentation helps, but expect a learning curve.
4. API Discovery Challenges
Finding the right way to access specific fields or perform operations can be difficult, having to rely on community forums and support tickets to tackle advanced scenarios.
5. Loop Prevention Logic
Exalate prevents looping out-of-the-box.
6. Maintenance Responsibility
Like any custom scripting solution, you own the code and its lifecycle:
- Groovy scripts need updates as Jira APIs evolve
- Business requirements change over time, requiring script modifications
- You're responsible for testing changes before deploying to production
This is the trade-off for flexibility - you have control, but also responsibility.
7. Testing Infrastructure
Testing happens entirely through the UI:
- No Unit Tests: Cannot write automated unit tests for Groovy scripts
- No Integration Tests: No local test harness or mock environment
- Manual Testing Only: Every change requires manual verification through actual Jira instances
- Test Data Management: Creating and maintaining test scenarios in live Jira requires careful data management
This differs significantly from modern development practices and can slow down iteration cycles.
8. License Requirements
Remember that you need separate Exalate licenses for each instance involved in the synchronization. For our two-instance scenario, this means two licenses, which should be factored into cost considerations.
Conclusion: The Perfect Holiday Recipe
Just as a perfect Glögi requires the right blend of ingredients, spices, and timing, our Kitchen-Supplier integration required the right platform, careful design, and thorough testing. Exalate proved to be a solid choice for this synchronization scenario, offering purpose-built features for keeping Jira instances in sync.
The combination of JQL-based triggers, Groovy scripting with powerful helpers, and SyncRoom's centralized management allowed us to build a reliable bidirectional synchronization. While we encountered some challenges around Jira Cloud beta status, error debugging, and testing infrastructure, the core synchronization functionality works well once configured.
Exalate shines brightest when your primary need is synchronization - keeping data consistent across systems. The Kitchen team can focus on brewing delicious Glögi, the Supplier team can efficiently manage ingredient deliveries, and both teams stay perfectly synchronized throughout the busy holiday season.
Comparing Approaches
Now that you've seen both Exalate and ScriptRunner Connect tackle the same Glögi integration challenge, you can appreciate the trade-offs:
- Exalate: Purpose-built for synchronization with powerful script helpers and Groovy scripting flexibility that can handle complex integrations, especially when synchronization is the primary goal
- ScriptRunner Connect: Maximum flexibility with TypeScript, full control over business logic, local development workflow, but requires more custom code
The best choice depends on your specific needs:
- Choose Exalate when synchronization is your primary goal and you want purpose-built tools
- Choose ScriptRunner Connect when you need custom business logic, complex workflows, or prefer modern development practices
The Integration Café Series
The Integration Café is an ongoing series exploring different integration platforms and approaches for connecting Atlassian products and beyond. Using relatable analogies (coffee, beverages, food), we make integration technology accessible and engaging while diving deep into real-world implementation details.
Want to see another integration challenge tackled? Have questions about this implementation? Let us know!
About the Author and Development Team
The insights shared in the blogpost and more come from the technical leadership of Rafael Pinto Sperafico, a seasoned Atlassian specialist with years of experience optimising and securing enterprise Jira environments. Rafael’s expertise in project management, agile methodologies, and compliance monitoring makes him the ideal guide for organisations looking to close security gaps while maintaining efficient workflows.
Rafael is an active member of Ambientia’s talented Atlassian development team, a group recognised for innovation, deep technical knowledge, and passion for delivering world‑class solutions. He works alongside fellow experts to design custom monitoring tools, automate complex workflows, and help ensure that integration platforms like Exalate and ScriptRunner Connect remain secure, performant, and aligned with each client’s business goals.
Together, they’ve built a reputation for turning compliance challenges into competitive advantages. Ambientia continues to push the boundaries of Atlassian technologies, providing expert support for clients who demand the highest standards of security, governance, and operational excellence in their integration journeys.
If you want to see how Ambientia’s Atlassian experts can help you achieve seamless, safe, and scalable integrations — or simply want a trusted partner to review and extend your existing setups — reach out today and let’s cook up a perfect solution together.
Subscribe to our content
Do you want our content in your email? Among other things, we offer information on service management and customer experience development
More related
Atlassian
Welcome to The Integration Café: ScriptRunner Connect vs. Exalate
ScriptRunner Connect’s new External Coding vs. Exalate — 8 key integration aspects compared. Ambientia helps you choose and implement.
Read more
Published 26.8.2025 | Updated 15.12.2025
Atlassian
Brewing the Perfect Glögi: ScriptRunner Connect's Holiday Integration Recipe
Learn how ScriptRunner Connect brews seamless JSM integrations with automated syncing, comments, and handovers—smooth as the perfect holiday glögi.
Read more
Published 15.12.2025 | Updated 15.12.2025
