Scripting
Cyclr supports Javascript as its scripting language, allowing you to manipulate data before it’s sent as well as after it’s been retrieved. This can be useful when moving data between applications as what’s valid in one, may not be valid in another.
Also, sometimes data just doesn’t quite “fit”.
Inline Script
Inline Script is used to make small changes to data, directly in a mapping field.
For Inline Script, you must prefix the Javascript code with “=” (an equals sign), e.g.:
=(100 * 2)
or
=`[Mergefield]` === '' ? 'no value' : `[Mergefield]`;
It’s best to use ` characters (backticks) around string values being merged in as that will prevent carriage returns and any quote characters from breaking your Script.
Note: [Mergefield] above represents fields inserted by Cyclr in Step Setup when choosing Type a Value and selecting from the dropdowns.
If you’re finding your inline script is becoming complex, or it’s being used on multiple fields, you may want to consider using Step Script instead. Beyond just the added readability, there may also be a performance advantage.
Step Script
Step Script is used when you want to want to make more complex changes to data.
If you’re working on a Cycle in the Builder and need to perform a change to some data, click the Step Setup button on a Step then expand the Advanced Settings area and enter some Script to tie in to Cyclr’s Events as described below.
This is generally easier to read than multiple inline scripts and as mentioned above, there may be a performance advantage to using one set of Step Script instead of multiple inline scripts.
Connector Script
If you’re building a Custom Connector you also have the option to add script directly to the Connector’s definition.
This is done in the Script section of the Connector builder, either at the top level or within individual methods.
Event Handlers
Events are triggered at certain points when a Cycle runs, allowing you to modify data using “event handlers” which are simply Javascript functions.
To add an event handler, put a Javascript function at the Connector or Method level, or in the Advanced Settings area of a Step in the Cycle Builder, using the event name as the name of the function, e.g.:
function before_action() {
/* Handle event here */
return true;
}
When working on a Custom Connector, event handlers entered at the Connector level will be called for all of its Methods. Event handlers entered at the Method level will only be called for that Method. Event handlers entered through a Step’s Step Setup will only be called for that one Step.
If you need to pass a value from a before_action handler to an after_action handler and you’re not able to put it in the method_request object as part of the Request (the API being called might object to it), you can use the method_request_mergefields object as it’s persisted across those two events. The script_parameters object, for example, is not persisted across any events.
Event Handler Order
If an event handler exists at more than one level for the same event, i.e. Connector level as well as Method level, all of those event handlers are called.
This is useful if common processing of the data is required across all Methods using a Connector level after_action handler, but some Methods need further processing so an additional Method level after_action handler can also be used.
The order that Cyclr calls handlers for the same event is as follows:
Events beginning with “before” (such as before_action):
Method -> Connector -> Builder Step
All other events (such as after_action):
Connector -> Method -> Builder Step
General Objects
script_execution_context: (string) Contains a value that can be used to identify the context your Script is being executed in. Its value will be
RUNNING_TRANSACTION
,CONNECTOR_TESTING
orSTEP_TESTING
depending on where it's being executed.method_response_fields: Array containing all the Response Fields defined on a Method.
method_response_fields_in_use: Array containing the Response Fields defined on a Method that have been mapped on subsequent Steps.
Events
before_webhook
Called when a webook request has been received and before anything else is done. Method is used to decide if the request should be continued or return a custom message to the caller.
Global objects
method_endpoint: (string) The webhook request URL.
method_request_headers: (object) The webhook request headers.
method_request: (object) The received webhook request body.
method_raw_request: (string) A string representing the received webhook request body exactly as Cyclr received it. Useful when writing Script to validate requests as genuine when a sending system has added a signature.
method_request_parameters: (object) The webhook request parameters.
method_response_headers: (object) The response headers for the request.
method_response: (object) The response body for the request.
script_parameters: (object) Contains any available script parameters from the connector and method. Note: Changes are not persisted.
return: true for the webhook to continue normal execution, false to stop execution of the request and send the response body/headers to the caller
after_webhook
Called immediately after a Request to a Webook has been received, whether the Cycle is currently running or stopped.
Global objects
method_response: (object) The data that was POSTed to the Cyclr webhook
cycle_variables: (object) Allows access to Cycle variables. Changes are not persisted.
cycle_step_id: (string) ID of the step that is executing the script.
cycle_id: (string) The ID of the cycle the script is running in
cyclr_account_id: (string) The internal ID of the account the script is running in
external_account_id: (string) The external ID of the account the script is running in
return: true for the webhook to continue normal execution, false to ignore the webhook request
before_action
Called before Cyclr makes a request to an external API.
If a Method uses Paging, this function is called before each page is retrieved.
Global objects
method_request_headers: (object) HTTP headers for the request.
method_request_parameters: (object) Querystring parameters for the request.
method_request: (object) Data that will be posted to the third party API.
method_request_mergefields: (object) Mergefields for the request.
cycle_variables: (object) Allows access to Cycle variables. Changes are not persisted.
cycle_step_id: (string) ID of the step that is executing the script.
cycle_id: (string) ID of the cycle the script is running in
cyclr_account_id: (string) The internal ID of the account the script is running in
external_account_id: (string) The external ID of the account the script is running in
last_successful_run_date: (string) Time value indicating when a Step last ran without error.
action_data: (object) An object used to persist data between some event handler functions, allowing data to be passed between them. Accessible in before_action, after_action, after_action_paging, action_condition, after_error, before_oauth2_authorise, before_oauth2_token and after_oauth2_token.
script_parameters: (object) An object that contains any available script parameters from the connector and method. Note: Changes are not persisted.
return: true to continue with the request to the third party API, false to abort the request (use throw for a more useful step error message)
after_action
Function is called when Cyclr has a response from an external API.
If a Method uses Paging, this function is called after each page is retrieved.
Global objects
method_endpoint: (string) The URL of the original request
method_request: (object) Data that was posted to the third party API
method_request_mergefields: (object) Mergefields for the request
method_response_headers: (object) Response headers for the request
method_response: (object) Data that was received from the third party API. If the Method uses paging, this contains only the current page’s Response.
method_raw_response: (string) A string representing the received Response Body exactly as Cyclr received it.
cycle_variables: (object) Allows access to Cycle variables. Changes are not persisted.
cycle_step_id: (string) ID of the step that is executing the script.
cycle_id: (string) ID of the cycle the script is running in
cyclr_account_id: (string) Internal ID of the account the script is running in
external_account_id: (string) External ID of the account the script is running in
action_data: (object) An object used to persist data between some event handler functions, allowing data to be passed between them. Accessible in before_action, after_action, after_action_paging, action_condition, after_error, before_oauth2_authorise, before_oauth2_token and after_oauth2_token.
statusCode: (number) The response status code.
reasonPhrase: (string) The response reason phrase.
script_parameters: (object) Contains any available script parameters from the connector and method. Note: Changes are not persisted.
return: true
after_action_paging
If this function is provided, it is called once after all pages of data have been retrieved, whether Paging has been implemented or not.
The Paging referred to here is Inbound. This function doesn’t wait for Outbound paging to complete.
Global objects
method_request_headers: (object) The response headers for the request
method_request_parameters: (object) Parameters for the request
method_request_mergefields: (object) Mergefields for the request
method_response: (object) Contains all of the Response data.
cycle_variables: (object) Allows access to Cycle variables. Changes are not persisted.
cycle_step_id: (string) ID of the step that is executing the script.
cycle_id: (string) ID of the cycle the script is running in
cyclr_account_id: (string) Internal ID of the account the script is running in
external_account_id: (string) External ID of the account the script is running in
next_last_successful_run_date: (string) Assign to this variable to set the last_successful_run_date value a Step will use on its next run.
action_data: (object) Used to persist data between some event handler functions, allowing data to be passed between them. Accessible in before_action, after_action, after_action_paging, action_condition, after_error, before_oauth2_authorise, before_oauth2_token and after_oauth2_token.
script_parameters: (object) Contains any available script parameters from the connector and method. Note: Changes are not persisted.
return: true
after_error
Function is called when Cyclr received an error from an external API.
Global objects
method_error: (object) Details of the error, see: Handle Errors from Third Party APIs further down for more information on handling errors
cycle_variables: (object)Allows access to Cycle variables. Changes are not persisted.
cycle_step_id: (string) ID of the step that is executing the script.
cycle_id: (string) ID of the cycle the script is running in
cyclr_account_id: (string) Internal ID of the account the script is running in
external_account_id: (string) External ID of the account the script is running in
action_data: (object) Used to persist data between some event handler functions, allowing data to be passed between them. Accessible in before_action, after_action, after_action_paging, action_condition, after_error, before_oauth2_authorise, before_oauth2_token and after_oauth2_token.
script_parameters: (object) Contains any available script parameters from the connector and method. Note: Changes are not persisted.
return: true
action_condition
Function is used to essentially combine a Method with a Decision Step, allowing a test to be performed that directs a Transaction down either the True or False exit points. If this function is included in a method, Cyclr will add True and False exit points.
Global objects
method_response: (object) object that was received from the third party API.
cycle_variables: (object) Allows access to Cycle variables. Changes are not persisted.
cycle_step_id: (string) ID of the step that is executing the script.
cycle_id: (string) ID of the cycle the script is running in
cyclr_account_id: (string) Internal ID of the account the script is running in
external_account_id: (string) External ID of the account the script is running in
action_data: (object) Used to persist data between some event handler functions, allowing data to be passed between them. Accessible in before_action, after_action, after_action_paging, action_condition, after_error, before_oauth2_authorise, before_oauth2_token and after_oauth2_token.
script_parameters: (object) Contains any available script parameters from the connector and method. Note: Changes are not persisted.
return: true for the Transaction to exit on the “True Route”, false to exit on the “False Route”
before_oauth2_authorise
Function is called before Cyclr makes an OAuth 2 authorise request.
Global objects
method_endpoint: (string) URL for the OAuth authorise endpoint
cycle_variables: (object) Allows access to Cycle variables. Changes are not persisted.
action_data: (object) Used to persist data between some event handler functions, allowing data to be passed between them. Accessible in before_action, after_action, after_action_paging, action_condition, after_error, before_oauth2_authorise, before_oauth2_token and after_oauth2_token.
return: true
before_oauth2_token
Called before Cyclr makes an OAuth 2 access token request.
Global objects
method_request_headers: (object) HTTP headers for the request
method_request: (object) Object that is going to be sent to the OAuth 2 access token endpoint
cycle_variables: (object) Allows access to Cycle variables. Changes are not persisted.
action_data: (object) Used to persist data between some event handler functions, allowing data to be passed between them. Accessible in before_action, after_action, after_action_paging, action_condition, after_error, before_oauth2_authorise, before_oauth2_token and after_oauth2_token.
script_parameters: (object) Contains any available script parameters from the connector and method. Note: Changes are not persisted.
return: true
after_oauth2_token
Called after Cyclr makes an OAuth 2 access token request.
Global objects
method_response: (object) response object that was received from the OAuth 2 access token request
cycle_variables: (object) Allows access to Cycle variables. Changes are not persisted.
script_parameters: (object) Contains any available script parameters from the connector and method. Note: Changes are not persisted.
action_data: (object) Used to persist data between some event handler functions, allowing data to be passed between them. Accessible in before_action, after_action, after_action_paging, action_condition, after_error, before_oauth2_authorise, before_oauth2_token and after_oauth2_token.
return: true
before_oauth2_refresh
Called before Cyclr makes an OAuth 2 refresh token request.
Global objects
method_request_headers: (object) HTTP headers for the request
method_request: (object) request object that is going to be sent to the OAuth 2 refresh token request
cycle_variables: (object) Allows access to Cycle variables. Changes are not persisted.
script_parameters: (object) Contains any available script parameters from the connector and method. Note: Changes are not persisted.
return: true
after_oauth2_refresh
Called after Cyclr makes an OAuth 2 refresh token request.
Global objects
method_response: (object) response object that was received from the OAuth 2 refresh token request.
cycle_variables: (object) Allows access to Cycle variables. Changes are not persisted.
script_parameters: (object) Contains any available script parameters from the connector and method. Note: Changes are not persisted.
return: true
Functions
http_request
Function to make external HTTP requests.
When calling the http_request
function, you provide a JSON object with the following properties:
method: HTTP method, e.g. GET, POST, DELETE, PUT
url: URL for the HTTP request
parameters: Querystring parameters
headers: HTTP headers
data: HTTP request data. If sending JSON, you should use JSON.stringify() to serialize it.
Example:
function after_action() {
var response = http_request(
{
'method': 'POST',
'url': 'https://someapi.com/createsomething',
'headers':
{
'Authorization': 'Bearer ' + method_auth_value,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
'data': JSON.stringify( { "MyData": "some value" } )
}
);
return true;
}
The Response from an http_request
call is returned as a JSON object with these properties:
status_code: the HTTP Status code returned
headers: any HTTP headers
content: the Response body
request: details of the Request that was made
btoa
Function to encode a string to Base64 using a specified destination character set. Note: If no character set is provided the default will be UTF-8
Supported character sets which can be supplied: ASCII
, ISO-8859-1
, UTF-7
, UTF-8
, UTF-16
, UTF-16LE
, UTF-16BE
, UTF-32
, UTF-32LE
, UTF-32BE
var Utf8Base64Encoded = btoa("Hĕllō Wōrld"); // SMSVbGzFjSBXxY1ybGQ=
var AsciiBase64Encoded = btoa("Hĕllō Wōrld","ascii"); // SD9sbD8gVz9ybGQ=
var IsoBase64Encoded = btoa("Hĕllō Wōrld","iso-8859-1"); // SGVsbG8gV29ybGQ=
atob
Function to decode a Base64 encoded string, using a specified source character set, back to its original value. Note: If no character set is provided the default will be UTF-8
Supported character sets which can be supplied: ASCII
, ISO-8859-1
, UTF-7
, UTF-8
, UTF-16
, UTF-16LE
, UTF-16BE
, UTF-32
, UTF-32LE
, UTF-32BE
var Utf8Base64Decoded = atob("SMSVbGzFjSBXxY1ybGQ="); // Hĕllō Wōrld
var AsciiBase64Decoded = atob("SD9sbD8gVz9ybGQ=","ascii"); // H?ll? W?rld
var IsoBase64Decoded = atob("SGVsbG8gV29ybGQ=","iso-8859-1"); // Hĕllō Wōrld
cyclr_encrypt
Function to generate a hash from a value.
Parameter | Description |
---|---|
algorithm | The hashing algorithm to use.
|
data | The input data to generate a hash from. |
base64Encoded | Whether the |
Example:
var algorithm = 'sha512';
var valueToHash = 'This is the string to hash.';
var hash = cyclr_encrypt(algorithm, valueToHash);
cyclr_sign
Function to sign a string.
For example,
var algorithm = 'HMAC-SHA1';
var signingKey = 'This is the signing key.';
var valueToSign = 'This is the string to sign.';
var signature = cyclr_sign(algorithm, signingKey, valueToSign);
Supported algorithms are: HMAC-SHA1
, HMAC-SHA256
, HMAC-SHA512
, RSA-SHA1
, RSA-SHA224
, RSA-SHA256
, RSA-SHA384
, RSA-SHA512
.
cyclr_csv_parse
Function to parse a CSV string.
var csv = '1,2,3\na,b,c';
var delimiter = ',';
var hasHeader = false;
var csvRecords = cyclr_csv_parse(csv, delimiter, hasHeader);
cyclr_xml_serialize
Function to convert JSON to XML.
var jsonObj = {
"note": {
"to": "Tove",
"from": "Jani",
"heading": "Reminder",
"body": "Dont forget me this weekend!"
}
};
var jsonObjAsXml = cyclr_xml_serialize(jsonObj);
// Output:
//<note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Dont forget me this weekend!</body></note>
cyclr_xml_deserialize
Function to convert XML to JSON.
var xmlStr = '<note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Dont forget me this weekend!</body></note>';
var xmlAsJson = cyclr_xml_deserialize(example);
// Output:
// {
// "note": {
// "to": "Tove",
// "from": "Jani",
// "heading": "Reminder",
// "body": "Dont forget me this weekend!"
// }
// }
Storage Functions
Cyclr provides several storage functions available for use in Script that can be used when developing a Connector, or on a Step in a Template or Cycle.
Data they work against is locked to the Connector they’re called on. i.e. if you write data using cyclr_storage_set()
on a Step from one Connector, you cannot access that same data using cyclr_storage_get()
on a Step from a different Connector.
The functions come in 2 flavours:
cyclr_storage_...()
and cycle_storage_...()
The cyclr_storage_...()
functions access the same data on any Steps in any Cycles for a particular Connector.
The cycle_storage_...()
functions work in the same way, but their data is further restricted to the context of a particular Cycle. If you write data in one Cycle, you cannot access it in another;
The storage functions available in their cyclr_
versions are shown below.
Change cyclr_
to cycle_
to use their Cycle-restricted versions.
cyclr_storage_list_values()
cyclr_storage_delete_all()
cyclr_storage_delete(key)
cyclr_storage_get(key)
cyclr_storage_set(key, value)
cyclr_storage_append(key, value)
cyclr_storage_list_keys()
cyclr_storage_increment(key, amount)
cyclr_storage_decrement(key, amount)
Exceptions
AuthRefreshException
Exception to force the OAuth 2 authentication token to be refreshed.
This is useful when the OAuth 2 endpoint doesn’t return a definite token expiry time.
Upon getting this exception, Cyclr will call the OAuth 2 Access Token URL to get a new access token.
For example, an API returns 200 with an error code in the response when the token becomes invalid:
function after_action() {
if (typeof method_response.error !== 'undefined' &&
method_response.error === 'invalid_grant') {
throw new AuthRefreshException();
}
return true;
}
If an API returns a non-2xx HTTP status code when the auth token becomes invalid, you should throw AuthRefreshException in after_error:
function after_error() {
if (method_error.statusCode === 403) {
throw new AuthRefreshException();
}
return true;
}
AuthSessionException
Exception to force the authentication session to be refreshed.
Upon getting this exception, Cyclr will call the Post Install Property Value Lookup Method to start a new session.
For example, an API returns 200 with an error code in the response when the session expires:
function after_action() {
if (typeof method_response.error_code !== 'undefined' &&
method_response.error_code === 'You are not logged on.') {
throw new AuthSessionException();
}
return true;
}
If an API returns a non-2xx HTTP status code when the auth session expires, you should throw AuthSessionException in after_error:
function after_error() {
if (method_error.statusCode === 403) {
throw new AuthSessionException();
}
return true;
}
Libraries
The following libraries are available within Cyclr’s script engine:
It is not necessary to load these with a require
call as they are automatically available.
Moment.js
Library Name: moment
Description: Parse, validate, manipulate, and display dates and times in JavaScript. Cyclr also supports the Moment Timezone extension, which enables formatting and converting of dates in any timezone.
External Documentation: https://momentjs.com/ , https://momentjs.com/timezone/
CryptoJS
Library Name: crypto-js
Description: JavaScript library of crypto standards.
Warning: The output of encrypted data is always in a hex string. Formatting options CryptoJS.enc
are not supported when calling toString
.
External Documentation: https://github.com/brix/crypto-js
Connector scripting examples
Make External Requests
You can write a script to call external API endpoints. This is especially useful if the API returns a URL which contains the real response object.
For example, a webhook returns the following object to Cyclr:
{
"event": "object.updated",
"api_url": "http://httpbin.org/get"
}
Use http_request
to call api_url
and replace the webhook response with the updated object:
function after_webhook() {
var request = {
'method': 'GET',
'url': method_response.api_url,
'headers': {
'Accept': 'application/json'
}
};
var content = http_request(request).content;
method_response = content;
return true;
}
After calling api_url
, Cyclr will then replace method_response
with the content of the HTTP call.
Return false
in the after_webhook
function will stop Cyclr from running the webhook. You can use this trick to filter webhook events.
Transform Key Value Pairs
Making use of key value pair responses requires the use of scripting, consider an API that returns the below representation of a contact.
{
"properties": [{
"key": "email",
"value": "example@example.com"
}]
}
To access the email field we would add a field in the method response with a connector location of properties.email. However this would not work as the cyclr is looking in the response for a properties object with a property named email to get the value from. To solve the issue we would add the below function into the method scripts, this function will transform the properties array into an object with properties for each key value pair.
function after_action() {
var original = method_response.properties;
method_response.properties = {};
for (var i = 0; i < original.length; i++) {
var item = original[i];
if (item['key'] == void(0))
continue;
var val = item['value'];
if (val == void(0))
continue;
method_response.properties[item['key']] = val;
}
return true;
}
Now when cyclr runs the method if will get the following result back and the properties.email field will work as expected.
{
"properties": {
"email": "example@example.com"
}
}
For a corresponding request method, e.g. adding a contact, we would need the below function in the method scripts to perform the data transformation in reverse.
function before_action() {
var original = method_request.properties;
method_request.properties = [];
for (var p in original) {
method_request.properties.push({
'key': p,
'value': original[p]
});
}
return true;
}
Modify Parameters
Besides the HTTP request body, you can also use scripting to modify HTTP headers (method_request_headers
) and query string parameters (method_request_parameters
).
function before_action() {
var xmlData = '<Records><Record>';
for (var p in method_request) {
xmlData += '<Field val=""' + p + '"">' + method_request[p] + '</Field>';
}
xmlData += '</Record></Records>';
method_request_parameters.xmlData = xmlData;
return true;
}
In this example, we transformed the method request body to a XML string and saved the string as a new parameter called xmlData
.
Action Condition
To add True/False exits to a method, you can use the action_condition
event.
// Any records that pass the condition will continue down the green "True" path.
// Those that do not will take the red "False" path.
function action_condition() {
if ([some test])
return true;
return false;
}
// If you want to send errored transactions (as opposed to successful calls that
// fail the condition) down the false path, you will need to add after_error script.
Handle Errors from Third Party APIs
The scripting engine can be used to catch and handle errors returned from third party APIs.
Cyclr exposes a received error response in the after_error
function through the method_error
object, which has these properties:
statusCode – (number) the HTTP status code returned by the third party API.
reasonPhrase – (string) the reason phrase returned by the third party API.
content – (string) the body content of the response from the third party API. Could contain JSON or XML.
isError – indicates that the error is an error. default: true, set to false if using isWarning or isSuccess.
isWarning – set to true for Cyclr to log the error as a warning.
isSuccess – set to true to change the error to success, then update
method_error.content
to contain the success step data.
Example: change an error to a warning
function after_error() {
if (method_error.statusCode != null &&
method_error.statusCode === 400 &&
method_error.reasonPhrase == 'Email Address not valid') {
method_error.isError = false;
method_error.isWarning = true;
}
return true;
}
Example: change an error to a success
function after_error() {
if (method_error.statusCode != null &&
method_error.statusCode === 400 &&
method_error.reasonPhrase == 'Email Address not valid') {
method_error.isError = false;
method_error.isSuccess = true;
method_error.content = '{}';
}
return true;
}
Limitations
Script used in Event Handler functions will execute for a maximum of 60 seconds before Cyclr times it out and returns an error.
Exceptions to this are:after_action
- times out after 90 seconds and runs separately for each page of data retrieved.after_action_paging
- times out after 90 seconds multiplied by the number of pages of data retrieved.
External HTTP requests: for security reasons, we will use the same authentication method as the connector and the same authentication value when the connector was installed by the user. You cannot use the script to access or modify the authentication value.
The cycle_variables object is only available through a Step’s Advanced Settings area, and not through Inline Script. Also, any changes made to it and its properties are not persisted.