JavaScript Scripts
JavaScript scripts execute custom logic in a sandboxed JavaScript engine. A script can be defined inline or loaded from a .js file in the repository.
Definition
{
"name": "calculatePremium",
"type": "javascript",
"scope": "OBJECT",
"trigger": "UPDATE",
"javascriptFile": "scripts/calculatePremium"
}
| Property | Type | Description |
|---|---|---|
javascriptFile | string | Path to a .js file in the repository (without extension). |
javascript | string | Inline JavaScript source. Use javascriptFile for anything non-trivial. |
Inline vs file-based
For short scripts, define the JavaScript inline with javascript. For anything non-trivial, use javascriptFile to reference a .js file in the repository:
my-project/
├── index.json
├── scripts/
│ └── calculatePremium.js
{
"name": "calculatePremium",
"type": "javascript",
"scope": "OBJECT",
"trigger": "UPDATE",
"javascriptFile": "scripts/calculatePremium"
}
Function signature
Every script file must define a function named execute:
function execute(api, dataObject, params) {
// your logic here
}
| Argument | Description |
|---|---|
api | The script API — read and write data, log messages, send notifications. See below. |
dataObject | The current object as a plain JavaScript map. All field values are accessible by their camelCase names. The special field _reference holds the object's URI and can be passed directly to API methods. |
params | Resolved script parameters as a key-value map. |
The api object
Reading data
api.get(uri)
Returns a single object by URI, or null if not found.
var company = api.get(dataObject.company);
api.query(typePluralName, filters)
api.query(typePluralName, filters, sortBy)
Returns all objects of a given type matching the filters. filters is a key-value map of field names to values — pass null for no filters. Optionally sort by a field name.
var activeContracts = api.query('employmentAgreements', { status: 'ACTIVE' });
var sorted = api.query('invoices', null, 'invoiceDate');
api.getRelatedObjects(uri, fromTypePluralName, typePluralName)
api.getRelatedObjects(uri, fromTypePluralName, typePluralName, filters, sortBy)
Returns all related objects of a given type for the object at uri. fromTypePluralName is the type that owns the relation definition — a data object can have multiple types, and the relation may be defined on a different type than the one in the URI.
var lines = api.getRelatedObjects(
dataObject._reference,
'invoices', // type that owns the 'lines' relation
'invoiceLines' // type to retrieve
);
With filters and sorting:
var expenseLines = api.getRelatedObjects(
dataObject._reference,
'invoices',
'invoiceLines',
{ type: 'EXPENSE' },
'amount'
);
Writing data
api.create(typePluralName, data)
Creates a new object and returns the created record as a map.
var task = api.create('tasks', {
name: 'Follow up with ' + dataObject.name,
dueDate: dataObject.expiryDate,
assignedTo: dataObject.accountManager
});
api.update(uri, data)
Patches an existing object. Only the provided fields are updated; all other fields are left unchanged.
api.update(dataObject._reference, {
status: 'COMPLETED',
completedDate: new Date().toISOString().slice(0, 10)
});
api.saveMany(records)
Creates or updates multiple objects in a single batch. Each entry must have either:
_reference— patches the existing object at that URI_type— creates a new object of that plural type name
Background recalculations are deduplicated across the batch, making this more efficient than calling create / update in a loop.
// Batch update
var updates = lines.map(function(line) {
return { _reference: line._reference, processed: true };
});
api.saveMany(updates);
// Batch create
api.saveMany([
{ _type: 'tasks', name: 'Task A', dueDate: '2025-06-01' },
{ _type: 'tasks', name: 'Task B', dueDate: '2025-06-15' }
]);
api.remove(uri)
Deletes the object at the given URI.
api.remove(obsoleteTask._reference);
Utilities
api.runScript(scriptName, dataObjectMap, parameters)
Runs another script by name. Pass the object map for OBJECT-scope scripts, or null for GENERAL-scope scripts.
api.runScript('sendConfirmationEmail', dataObject, { template: 'welcome' });
api.createBinary(fileName, contentType, content)
Creates a binary file from a UTF-8 string and returns its URI. The returned URI can be assigned directly to a FILE-typed field.
var csv = 'name,amount\nLine A,100\nLine B,200';
var fileUri = api.createBinary('export.csv', 'text/csv', csv);
api.update(dataObject._reference, { exportFile: fileUri });
api.stripHtml(html)
Removes HTML tags and decodes HTML entities. Useful when processing TEXTBLOCK values before including them in generated documents.
var plainText = api.stripHtml(dataObject.description);
api.log(message)
Logs a message to the server log, visible in application logs.
api.log('Processing ' + dataObject._reference);
api.notify(message, level)
Sends a notification to the user who triggered the script. Levels: INFO, WARNING, ERROR.
api.notify('No matching records found.', 'WARNING');
Example: set a completion date on status change
A script on my-project.task that records the date when a task is completed. Using triggerValues ensures it only runs when the status field changes to COMPLETED.
{
"name": "setCompletedDate",
"type": "javascript",
"scope": "OBJECT",
"trigger": "UPDATE",
"triggerValues": ["COMPLETED"],
"javascriptFile": "scripts/setCompletedDate"
}
function execute(api, dataObject, params) {
if (dataObject.completedDate) return; // already set, don't overwrite
api.update(dataObject._reference, {
completedDate: new Date().toISOString().slice(0, 10)
});
}
Example: recalculate a total from related objects
If the total only depends on field values of related objects, a formula using sum is simpler and more efficient — it recalculates automatically without a manual trigger or script overhead.
Use a JavaScript script for this pattern only when the logic cannot be expressed as a formula, for example when the calculation involves external data or conditional branching that cannot be established using sumIf.
A script on my-project.invoice that sums the amounts of all invoice lines and writes the total back to the parent invoice.
function execute(api, dataObject, params) {
var lines = api.getRelatedObjects(
dataObject._reference,
'invoices',
'invoiceLines'
);
var total = 0;
for (var i = 0; i < lines.length; i++) {
total += lines[i].amount ? lines[i].amount.amount : 0;
}
api.update(dataObject._reference, {
totalAmount: { amount: total, currency: 'EUR' }
});
api.log('Invoice total updated: ' + total);
}
Example: manual action with parameters
A script triggered manually by the user. Parameters are resolved from the current object before the script runs.
{
"name": "sendReminder",
"type": "javascript",
"scope": "OBJECT",
"trigger": "MANUAL",
"javascriptFile": "scripts/sendReminder",
"parameters": [
{ "name": "recipientEmail", "dataType": "EMAIL", "formula": "emailAddress" },
{ "name": "dueDate", "dataType": "DATE", "formula": "expiryDate" }
],
"preconditions": ["emailAddress != null"]
}
function execute(api, dataObject, params) {
var email = params.recipientEmail;
var due = params.dueDate;
if (!email) {
api.notify('No email address on this record.', 'WARNING');
return;
}
api.create('reminderLogs', {
sentTo: email,
sentAt: new Date().toISOString(),
dueDate: due,
contract: dataObject._reference
});
api.notify('Reminder sent to ' + email, 'INFO');
}