2.2.4 | 1/29/2024
Calling from Apex | Examples | Using the Invocable Method | Bulk and Governor Considerations | Error Handling Summary
Mambo Merge: startMerge Usage Guide
MamboMerge.startMerge is the entry point for running a merge programmatically. It accepts a set of input parameters, validates them, and queues a batch job that performs the merge. The same logic is exposed two ways: a flexible Apex method that takes a parameter map, and an invocable wrapper for use in Flows.
Overview
Both entry points ultimately do the same thing: resolve a Routine (or build an ad-hoc one from a file), validate the inputs against that Routine’s configuration, and queue a batch job. The merge runs asynchronously. The return value tells you whether the job was queued successfully — not whether the merge itself completed. Final merge results are written to Custom Metadata and can be looked up later by job ID.
A few concepts that apply to both entry points:
- Routine vs. no Routine. If you pass a
routineKey, the merge runs according to that Routine’s saved configuration (which records to pull, which template, where to save output, etc.). If you omitroutineKey, you must pass afileIdand arecordId, and a minimal one-off merge is performed against that file and record. - Routines must be enabled for Apex. A Routine will only run through
startMergeif itsmergeFromApexflag is set. Otherwise initialization fails with “Routine not enabled for Mambo Merge from Apex”. - Asynchronous execution. Each successful call queues one batch job via
Database.executeBatch. Salesforce limits the number of batch jobs you can queue per transaction, so be deliberate about how many merges you kick off at once. - Edition and license requirements. The edition of Mambo Merge must be on Performance Edition (or higher), the running user must be licensed for Mambo Merge, and there must be an active subscription or trial. These checks are skipped in test context.
Calling from Apex ↵
Signature
global static Map<String, Object> startMerge(Map<String, Object> params)
Input parameters
The params map supports the following keys. All keys are optional at the map level — which ones are required depends on the Routine being run.
| Key | Type | Description |
|---|---|---|
routineKey |
String |
The Key of the Routine to run. Required if using a Routine. |
templateNumber |
Integer |
The 1-based index of the template within the Routine. Required for single-template (non-checkbox) Routines. |
fileId |
Id |
ContentDocument or ContentVersion ID of the file to merge. Required when not using a Routine, or for Routines configured to accept a file passed in (uploadToMerge). |
recordId |
Id |
A single record to merge. Required for Single Record Routines and when not using a Routine. |
recordIds |
List<Id> |
A list of record IDs. Required for Multiple Records Routines. |
mergeData |
List<sObject>, List<Map<String, Object>>, or String |
Records to merge, overriding any data the Routine would otherwise query. Required for Routines configured to use passed-in merge data. A String value is deserialized as JSON representing a list of records. |
Return value
Returns a Map<String, Object>. On success it contains:
| Key | Type | Description |
|---|---|---|
jobId |
Id |
The ID of the queued batch job. Use this to look up final results in Custom Metadata. |
batches |
Integer |
The number of batches the merge was split into. |
batchSize |
Integer |
The batch size used. |
recordsCount |
Integer |
The number of records to be merged. |
If the job could not be queued, the map instead contains:
| Key | Type | Description |
|---|---|---|
batchableError |
Map<String, String> |
Details about the exception that prevented queuing. Inspect the message (and type) keys for specifics. |
Because errors are returned in the result map rather than thrown, always check for the batchableError key rather than relying on a try/catch around the call.
Examples ↵
Running a Routine against a single record
Map<String, Object> result = MamboMerge.startMerge(
new Map<String, Object>{
'routineKey' => 'Account_Welcome_Letter',
'templateNumber' => 1,
'recordId' => acct.Id
}
);
if (result.containsKey('batchableError')) {
Map<String, String> err = (Map<String, String>) result.get('batchableError');
System.debug('Merge could not be queued: ' + err.get('message'));
} else {
System.debug('Queued job: ' + result.get('jobId'));
}
Running a Routine against multiple records
Map<String, Object> result = MamboMerge.startMerge(
new Map<String, Object>{
'routineKey' => 'Bulk_Statements',
'templateNumber' => 1,
'recordIds' => new List<Id>{ id1, id2, id3 }
}
);
A one-off merge without a Routine
When no routineKey is provided, supply both a fileId and a recordId. The template number defaults to 1 and an ad-hoc Routine is built around the file.
Map<String, Object> result = MamboMerge.startMerge(
new Map<String, Object>{
'fileId' => templateContentVersionId,
'recordId' => acct.Id
}
);
Supplying merge data directly
For Routines configured to use passed-in merge data, provide it as a list of sObjects, a list of maps, or a JSON string.
// As sObjects
List<Account> accounts = [SELECT Id, Name, Industry FROM Account LIMIT 5];
MamboMerge.startMerge(
new Map<String, Object>{
'routineKey' => 'Custom_Data_Merge',
'templateNumber' => 1,
'recordId' => parentId,
'mergeData' => accounts
}
);
// As maps (useful for synthetic data that isn't a real record)
List<Map<String, Object>> rows = new List<Map<String, Object>>{
new Map<String, Object>{ 'name' => 'Line 1', 'amount' => 100 },
new Map<String, Object>{ 'name' => 'Line 2', 'amount' => 250 }
};
MamboMerge.startMerge(
new Map<String, Object>{
'routineKey' => 'Custom_Data_Merge',
'templateNumber' => 1,
'recordId' => parentId,
'mergeData' => rows
}
);
Using the Invocable Method ↵
startMergeInvocable wraps startMerge for use in Flows. It accepts a list of structured request objects and returns a list of structured response objects, one per request, in the same order.
Method
@InvocableMethod(label='Mambo Merge: Start Merge' category='Mambo Merge')
global static List<MergeResponse> startMergeInvocable(List<MergeRequest> requests)
Request inputs (MergeRequest)
| Variable | Type | Description |
|---|---|---|
| Routine Key | String |
The Key of the Routine to run. Required if using a Routine. |
| Template Number | Integer |
1-based index of the template within the Routine. Required for non-checkbox Routines. |
| File ID | Id |
ContentDocument or ContentVersion ID. Required when not using a Routine or when the Routine expects a file passed in. |
| Record ID | Id |
Single record to merge. Required for Single Record Routines or when not using a Routine. |
| Record IDs | List<Id> |
List of record IDs. Required for Multiple Records Routines. |
| Merge Data (Single Record) | sObject |
A single record used as merge data. |
| Merge Data (List of Records) | List<sObject> |
A list of records used as merge data. |
| Merge Data (JSON) | String |
A JSON-serialized list of merge data records. |
Merge data precedence
The three merge-data inputs are mutually exclusive and evaluated in priority order. Only the first one provided is used:
- Merge Data (Single Record) — if set, it’s wrapped into a one-element list and used; the other two are ignored.
- Merge Data (List of Records) — used only if no single record was provided.
- Merge Data (JSON) — used only if neither of the above was provided.
Use the single-record or list inputs when your merge data consists of real Salesforce records — they’re typed, so Flow handles them natively with no serialization. Use the JSON input only when the data isn’t a list of real sObjects (for example, synthetic rows with custom keys that don’t map to any object).
Response outputs (MergeResponse)
| Variable | Type | Description |
|---|---|---|
| Job ID | String |
The ID of the queued batch job. Populated on success. |
| Batches | Integer |
The number of batches. Populated on success. |
| Batch Size | Integer |
The batch size used. Populated on success. |
| Records Count | Integer |
The number of records to be merged. Populated on success. |
| Error Type | String |
The type of error, if one occurred. |
| Error Message | String |
A human-readable error message, if one occurred. |
To determine success in a Flow, check whether Error Message is blank. If it’s populated, the merge was not queued and Job ID will be empty.
Using it in Flow Builder ↵
- Add an Action element to your Flow.
- Search for Mambo Merge: Start Merge (under the Mambo Merge category).
- Set the inputs. At minimum, provide a Routine Key and Template Number (for single-record Routines, also a Record ID; for multi-record Routines, a Record IDs collection).
- After the action, branch on the Error Message output: if it’s not blank, route to error handling; otherwise continue, optionally storing Job ID for later status lookups.
A typical record-triggered flow on an Account might set Routine Key to a literal string, Template Number to 1, and Record ID to {!$Record.Id}.
Bulk and Governor Considerations ↵
Every successful merge queues one batch job. Salesforce limits the number of batch jobs that can be queued within a single transaction, so:
- In Apex loops, don’t call
startMergeonce per record when a Routine supports multiple records. Instead, collect the IDs and make a single call with therecordIdslist. - In Flows, be cautious about invoking this action in a bulk record-triggered context. If the same action fires for many records in one transaction, each invocation queues its own batch and you can quickly exceed the per-transaction limit. Prefer driving a single invocation with a populated Record IDs collection over fanning out to many single-record invocations.
When a merge spans many records, the work is automatically split into batches; the returned batches and batchSize values tell you how it was divided.
Error Handling Summary ↵
| Where | How errors surface |
|---|---|
Apex (startMerge) |
Returned in the result map under the batchableError key. Check for the key; don’t rely solely on try/catch. |
Invocable (startMergeInvocable) |
Returned per-request in the Error Message and Error Type outputs. Check whether Error Message is blank. |
Common initialization errors include: a missing or unknown routineKey, a Routine not enabled for Apex, a required recordId/recordIds/fileId not supplied, a fileId that isn’t a ContentDocument or ContentVersion, a record whose object type doesn’t match the Routine’s primary object, and an out-of-range templateNumber. The error message states which condition failed.