Skip to main content

Xurrent

All Xurrent functions automatically retry failed requests based on the rules described here.

addApprover​

Add approver person with id "personId" to the approval Task with id "taskId". Both parameters are mandatory. There is no check if the task is a approval task.

addApprover(taskId, personId, [account]);

Example:

let taskId = 172;
let personId = 123;
addApprover(taskId, personId);

addNote​

add the note "new text" to module "requests" on the element with the id request.id.

addNote(module, id, text, [account]);

Example:

addNote("requests", request.id, "new text");

checkExportState​

check the state of an export that was started with initExport

checkExportState(token, account_name);

Example:

let account_name = "wdc";
let result = initExport("organizations", account_name);

let state_result = null;

for (let counter = 0; counter < 50; counter++) {
state_result = checkExportState(result.token, account_name);

log(`state result ${counter} : `, state_result);
if (state_result.state == "done" || state_result.state == "error") {
break;
}
sleep(2000);
}

let final_results = loadFileToString(state_result.url);

log("final_results", final_results);
let list = csvToObjectList(final_results);
log("list", list);

checkImportState​

check the state of an import that was started with import_csv

checkImportState(token, account_name);

Example:

let account_name = "wdc";
let upload_csv = "Source,Source ID,Name,Disabled";
let upload_lines = [];

for (let x = 1; x < 20; x++) {
upload_lines.push(`wdc-import,import_org_sourceID${x},import org name${x},1`);
}

upload_csv = upload_csv + "\n" + upload_lines.join("\n");

let result = import_csv("organizations", upload_csv, account_name);
log("result", result);

let state_result = null;

for (let counter = 0; counter < 50; counter++) {
state_result = checkImportState(result.token, account_name);

log(`state result ${counter} : `, state_result);
if (state_result.state == "done" || state_result.state == "error") {
break;
}
sleep(2000);
}

let final_results = loadFileToString(state_result.logfile);

log("final_results", final_results);

create​

Create a new element in Xurrent.

create(recordType, data, [account]);

The recordType parameter is used as a URL path on the Xurrent REST API. Besides a plain record type such as "requests", two other forms are supported:

  • A module name followed by a predefined filter: "cis/active", "tasks/open".
  • The path of a subresource, a collection nested under a single record: `tasks/${taskId}/tags`.

These module paths are also supported by all other REST API functions: fetch, fetchAll, fetchFilter, update and deleteItrp.

Example 1:

let result = create("workflows", {
template_id: 13,
manager_id: 147995,
});

Create a workflow with the workflow template with ID 13 and with manager with person ID 147995 The new element is accessible by result variable.

Example 2:

let result = create("workflows", {
member_id: 147995,
workflow_type: "application_workflow",
justification: "correction",
subject: "by Xurrent script",
});

Create a workflow using the given field values. The new element is accessible by result variable.

Example 3:

const pdfBuffer = create_pdf({ content: "Very important document" });

const result = create(
"requests",
{
note: "PDF Document upload",
status: "assigned",
template_id: 13,
note_attachments: [{ content: pdfBuffer, fileName: "Document.pdf" }],
},
"account-name",
);

Create a request with a PDF attached to its note. See Attachments for more information on adding attachments.

Example 4:

const taskId = 172;
const tag = create(`tasks/${taskId}/tags`, {
name: "hardware_replaced",
});

Add a tag to a task by posting to its subresource path.

customFieldsToObject​

Converts a list of custom fields to a plain object.

The first parameter can be either a Xurrent object with a custom_fields attribute, or an array of custom fields with id and value attributes.

The result is at least an empty object.

let plain_custom_data = customFieldsToObject(custom_fields);

Example 1: Convert list of custom fields to object.

let plain_custom_data = customFieldsToObject([
{ id: "email_1", value: "a@b.com" },
{ id: "priority", value: "high" },
]);
// Result: { email_1: 'a@b.com', priority: 'high' }

Example 2: Convert Xurrent object with custom fields to object.

let plain_custom_data = customFieldsToObject(request);

objectToCustomFields​

Converts a plain object into a custom_fields array with id and value attributes.

The result is at least an empty array.

let custom_fields = objectToCustomFields(plain_custom_data);

Example 1: Convert plain object to list of custom fields.

let custom_fields = objectToCustomFields({ email_1: "a@b.com", priority: "high" });
// Result: [
// { id: 'email_1', value: 'a@b.com' },
// { id: 'priority', value: 'high' }
// ]

getCustomFieldsValue​

Returns the value of the custom field with the given id. If there is no such custom field, or if its value is null, returns the default value, or null if no default value is given.

The first parameter can be either a Xurrent object with a custom_fields attribute, or an array of custom fields with id and value attributes.

let value = getCustomFieldsValue(custom_fields, 'id')
let value = getCustomFieldsValue(custom_fields, 'id', 123);

Example 1: Return value of email_1 custom field.

let value = getCustomFieldsValue(request.custom_fields, "email_1");

Example 2: Return value of email_1 custom field out of Xurrent request.

let value = getCustomFieldsValue(request, "email_1");

Example 3: Return value of email_1 custom field, or default value dummy@test.com if not set.

let value = getCustomFieldsValue(request, "email_1", "dummy@test.com");

setCustomFieldsValue​

Sets the custom field with the given id to the given value. If the custom field does not yet exist, it is added to the list.

The first parameter can be either a Xurrent object with a custom_fields attribute, or an array of custom fields with id and value attributes.

setCustomFieldsValue(custom_fields, 'id', value);

Example 1: Set the value of the email_1 custom field on a Xurrent request.

setCustomFieldsValue(request, "email_1", "new@example.com");

Example 2: Fetch request, update custom field priority to high and update request in Xurrent.

let request = fetch("requests", 1234);
setCustomFieldsValue(request, "priority", "high");
update("requests", request.id, { custom_fields: request.custom_fields });

hasCustomFieldId​

Checks if a custom field with the given id exists.

Also returns true if the custom field exists and its value is null.

The first parameter can be either a Xurrent object with a custom_fields attribute, or an array of custom fields with id and value attributes.

let exists = hasCustomFieldId(custom_fields, 'id');

Example 1: Update email_1 custom field on a Xurrent request, but only if such a custom field exists.

if (hasCustomFieldId(request, "email_1")) {
setCustomFieldsValue(request, "email_1", "new@example.com");
}

deleteItrp​

Deletes a Xurrent record. Account name is optional and defaults to the account that triggered the package.

Example 1: remove a relation between two configuration items

const recordType = "cis";
const endpoint = ciId + "/ci_relations/" + ciRelationId;
const account_name = "wdc";
deleteItrp(recordType, endpoint, account_name);

Example 2: remove a tag from a task, using a subresource path (see create)

const taskId = 172;
deleteItrp("tasks", `${taskId}/tags/123`);

exportPromise​

initiate an export and return a promise

exportPromise(type, account_name);

Example:

let account_name = "wdc";
let promise = exportPromise("organizations", account_name);
let result = waitForPromise(promise);

log("result", result);
log("promise", promise);
log("promise.content", promise.content);

fetch​

Fetch data from Xurrent Module if id is known

let result = fetch("module_name", element_id, [account]);

Example 1: fetch workflow with id 123

let workflow = fetch("workflows", 123);

Example 2: fetch organization with id 123

let organization = fetch("organizations", 123);

Example 3: fetch person with id 123

let person = fetch("people", 123);

Example 4: fetch request with id 123

let request = fetch("requests", 123);

Example 4: fetch task with id 123

let task = fetch("tasks", 123);

Example 5: fetch a configuration item with id 1 from the active predefined filter

let activeCi = fetch("cis/active", 1);

Example 6: fetch a single tag with id 123 of a task, using a subresource path (see create)

const taskId = 172;
const tag = fetch(`tasks/${taskId}/tags`, 123);

fetchAll​

Fetch all elements of a module.

!IMPORTANT! Avoid this for mass data like requests, tasks, workflows, audit entries, ...

let results = fetchAll("module_name", [account]);

Example 1: get all workflow templates

let allWorkflowTemplates = fetchAll("workflow_templates");

for (let template of allWorkflowTemplates) {
log("Template : ", template.subject);
}

Example 2: get all configuration items from the active predefined filter

let activeCis = fetchAll("cis/active");

Example 3: list all tags of a task, using a subresource path (see create)

const taskId = 172;
const tags = fetchAll(`tasks/${taskId}/tags`);

fetchFilter​

Fetch data from Xurrent Module with URL filter.

let results = fetchFilter("module_name", filter_value, [account]);

Example 1: Filter workflow templates by subject

let filter = "subject=" + encodeURI("Standard Purchase without Approval");
let elements = fetchFilter("workflow_templates", filter);
for (let item of elements) {
log("item", item);
}

Example 2: Filter configuration items in the active predefined filter by name

let activeCisNamedFoo = fetchFilter("cis/active", "name=foo");

import_csv​

Start import of csv data

import_csv(entity, csv_data, account_name, [uploaded_file_name]);

import_csv returns a token that can be checked with checkImportState.

In Xurrent the import state can be viewed in system logs - import state.

Example:

let account_name = "wdc";
let upload_csv = "Source,Source ID,Name,Disabled";
let upload_lines = [];

for (let x = 1; x < 20; x++) {
upload_lines.push(`wdc-import,import_org_sourceID${x},import org name${x},1`);
}

upload_csv = upload_csv + "\n" + upload_lines.join("\n");

let result = import_csv("organizations", upload_csv, account_name, "uploaded.csv");
log("result", result);

let state_result = null;

for (let counter = 0; counter < 50; counter++) {
state_result = checkImportState(result.token, account_name);

log(`state result ${counter} : `, state_result);
if (state_result.state == "done" || state_result.state == "error") {
break;
}
sleep(2000);
}

let final_results = loadFileToString(state_result.logfile);

log("final_results", final_results);

initExport​

Export data from the platform.

initExport(data_type, account_name);

Example:

let account_name = "wdc";
let result = initExport("organizations", account_name);

let state_result = null;

for (let counter = 0; counter < 50; counter++) {
state_result = checkExportState(result.token, account_name);

log(`state result ${counter} : `, state_result);
if (state_result.state == "done" || state_result.state == "error") {
break;
}
sleep(2000);
}

let final_results = loadFileToString(state_result.url);

log("final_results", final_results);
let list = csvToObjectList(final_results);
log("list", list);

getMetaData​

Returns the metadata associated with the result of a fetch request. For Xurrent fetch functions such as fetchFilter, the metadata contains pagination and rate-limit information.

let info = getMetaData(xurrentObject);

The returned object has the following properties:

  • headers — The raw HTTP response headers returned by Xurrent.
  • linkFilter — Object containing the next, prev and first URLs extracted from the Link header. Each property only contains the query string of the corresponding URL, e.g. per_page=100&search_after=xyz.
  • info — Informational message. null for a normal result; 'NO METADATA' when the object carries no metadata.
  • error — Error message, or null when no error occurred while reading the metadata.
  • currentPage — The current page number (from the x-pagination-current-page header), or -1 if not provided.
  • totalPages — The total number of pages (from the x-pagination-total-pages header), or -1 if not provided.
  • rateLimitLimit — The maximum number of requests allowed in the current rate-limit window (from x-ratelimit-limit), or -1 if not provided.
  • rateLimitRemaining — The number of requests remaining in the current window (from x-ratelimit-remaining), or -1 if not provided.
  • rateLimitReset — When the rate-limit window resets (from x-ratelimit-reset), or -1 if not provided.
  • rateLimitRetryAfter — The number of seconds to wait before retrying (from the retry-after header), or -1 if not provided.

If the object has no metadata, returns { info: 'NO METADATA', headers: {}, linkFilter: {}, error: null }.

Example 1: Inspect the metadata of a fetch result.

let services = fetchFilter("services", "disabled=0", account);
log("count", services.length);
log("meta", getMetaData(services));

Example 2: Manual paging through a large result set.

The Xurrent fetch functions page through results automatically, but only up to 100 pages (10.000 records). Beyond that, they return a "Too many total records" error.

However, using getMetaData it's still possible to manually walk through the entire collection. To retrieve such a larger set, (or, better, to process results one page at a time):

  • Include per_page= in the filter to opt out of automatic paging.
  • Use getMetaData to retrieve the linkFilter.next property.
  • Follow linkFilter.next until it becomes null to walk the whole collection.
let services = [];
let filter = "disabled=0&per_page=100";

while (filter != null) {
const page = fetchFilter("services", filter, account);
services.push(...page);

const { currentPage, totalPages, linkFilter } = getMetaData(page);
log(`Fetched page ${currentPage}/${totalPages}`);

filter = linkFilter.next;
}

log(`Fetched ${services.length} services`);

Link two modules in Xurrent.

link(from_module_name, from_element_id, to_module_name, to_element_id, [account]);

Example:

let workflowId = 172;
let requestId = 123;
link("workflows", workflowId, "requests", requestId);

mergeAudit​

Merges audit information into the given Xurrent object.

mergeAudit(xurrent_object);
mergeAudit(xurrent_object, audit_line_id);

This can be used for any Xurrent record type (request, workflow, task, ...) that has audit entries. This command adds audit_... attributes to the given Xurrent object:

  • obj.audit_id
  • obj.audit_user
  • obj.audit_action
  • obj.audit_created_at

In addition, for each field 5 additional attributes are added that contain audit information about the field:

  • obj.audit_is_changed_...: true if the field was changed
  • obj.audit_old_...: contains the value before the change
  • obj.audit_new_...: contains the value after the change
  • obj.audit_unchanged_...: contains a value ONLY if value is not changed
  • obj.audit_changed_...: contains a value ONLY if value is changed

E.g. for the request.status field following fields are added:

  • request.audit_is_changed_status
  • request.audit_old_status
  • request.audit_new_status
  • request.audit_unchanged_status
  • request.audit_changed_status

If the audit_line_id parameter is given, the audit information is taken from that specific audit entry.

Otherwise, if the given Xurrent object is the one that triggered the package execution via a webhook, then the audit information is taken from the audit line specified in the payload[audit_line_id] attribute of the [webhook payload](https://developer.xurrent.com/v1/webhooks/#webhook-contents.

Otherwise, the audit information is taken from the most recent audit entry of that Xurrent object.

Example:

const request = fetch("requests", 1234);
mergeAudit(request);
log("request", request);

update​

Update Xurrent objects.

let result = update(recordType, recordId, data, [account]);

The Attachments section describes how to add attachments to a Xurrent object.

Example 1:

let workflowId = 173;

let result = update("workflows", workflowId, {
subject: "new subject text",
});

Example 2:

let requestId = 173;

let result = update("requests", requestId, {
subject: "new subject text",
});

waitForPromise​

wait for a promise initiated by an exportPromise call

waitForPromise(promise);

Example:

let account_name = "wdc";
let promise = exportPromise("organizations", account_name);
let result = waitForPromise(promise);

log("result", result);
log("promise", promise);
log("promise.content", promise.content);

Attachments​

To add attachments to a rich text field, they need to be specified in an attribute that has the same name as the rich text field plus _attachments.

For example, the attachments for the note of a request are specified in note_attachments, for the internal note in internal_note_attachments, and for the instructions of a task in instructions_attachments.

The Xurrent fields reference has a complete overview of the available attachment attributes for each record type.

The easiest way to add an attachment is by specifying the contents of the file, the filename and, optionally, the content type and content length. The automator takes care of uploading the file to Xurrent storage and the other logic described in the Xurrent developer documentation.

const attachments = [{
content: report, // required: the file, as a buffer or a string
fileName: "Report.pdf", // the name to store it under
contentType: "application/pdf", // optional
length: report.length, // optional: defaults to the length of content
}];

// Add note with attachments to given Xurrent request.
update("requests", request.id, {
note: "See the attached file.",
note_attachments: attachments,
});
warning

It is also possible to upload attachments via the following two legacy attributes:

  • attachments writes to the "main" rich text field of the record type, for example note_attachments for a request, remarks_attachments for an organization, and information_attachments for a person.
  • internal_attachments writes to internal_note_attachments (only available for Xurrent requests).

Don't use these attributes in new packages and use the officially documented *_attachments attributes instead.

Referring to an uploaded file​

An entry that has a key instead of content refers to a file that is already in the storage facility, and is passed to Xurrent unchanged. Use this to attach a file that is already on another record, or one you uploaded yourself.

update("requests", 173, {
note: "The same report as on the previous request.",
note_attachments: [{ key: "attachments/5/.../Report.pdf", filesize: "10241" }],
});

Inline images and videos​

An inline attachment is shown within the rich text rather than listed below it. Mark the attachment as inline and refer to it from the text with ![](<file name>). The file name is replaced by the storage key during the upload.

const logo = loadFromUri("https://example.com/logo.png", "buffer");

update("requests", 173, {
note: "Our logo:\n![](logo.png)\nLooking good.",
note_attachments: [{ fileName: "logo.png", content: logo.content, inline: true }],
});

Attaching a file to a custom field​

An attachment on a custom field goes in custom_fields_attachments, with the ID of the custom field it belongs to. Its value is set to the storage key of the uploaded file, so there is no need to also list the field in custom_fields.

update("requests", 173, {
custom_fields_attachments: [{ fileName: "Report.pdf", content: report, custom_field_id: "report" }],
});

Removing an attachment​

Refer to the attachment by its key and mark it with _destroy:

update("people", 123, {
information_attachments: [{ key: "attachments/5/.../Report.pdf", _destroy: true }],
});