Writing Scripts

Updated Nov 9, 2026
DataMagik Automate

The script editor

Open Script Engine › Scripts. The editor fills the page, with a toolbar across the top and side panels that slide in from the right. When a panel is open, the code moves over rather than being covered.

The toolbar

  • Select Script...: the script picker. Click it, or press Ctrl+K, to search.
  • ID: the script's ID. Click it to copy.
  • Webhook: the address other systems call to run this script. See Script webhooks.
  • Excel: publish the script to Excel and Power BI. See Scripts in Excel & Power BI.
  • + (New Script): create a script.
  • Modified: shown while the code has changes you have not saved.
  • Panel buttons: Version history, Script settings, Documentation, Context browser and Execution history.
  • Format Code and Validate (checks the code for syntax errors).
  • Test, Debug, Save and Run. See Testing a script below.
  • Git: compare the script with its file in your repository. It appears only when you have a Git connection. See Git integration.

The button in the editor's top corner, or Shift+F11, makes the editor full screen. Press Escape to leave.

Finding a script

Press Ctrl+K (Cmd+K on a Mac) or click the script picker. Type in Search scripts by name, ID, tag, or author...: every word you type must match. A number also matches a script ID, and #1363 matches the ID only. You can narrow the list by Category, Tags, type (Scripts or Reports) and Capabilities (AI Tool, Excel, OData, Write), and change the Sort. Use the arrow keys and Enter to open a script, and Escape to close the search.

Workflows appear in the list too, with a Workflow badge. Their code is generated from the canvas, so change them in the workflow editor, not here.

Problems and unsaved drafts

  • Problems appears below the code when something is wrong, such as a syntax error or a name the sandbox does not have. Click a problem to go to its line.
  • The editor keeps your unsaved code in this browser. If you come back to a script with changes from an earlier session, it offers Restore draft or Discard. The saved version is what runs until you save again.

Help while you type

  • Autocomplete. Type a name and a dot, such as helpers., to see what it offers, with a short description of each function and its arguments. Ctrl+Space opens the list at any point. A name the sandbox does not have, such as a misspelled odbc.excuteQuery, is underlined in red.
  • Names from your company. Inside the quotes of odbc.executeQuery(", credentials.get(", tables.get(", documents.generateSync(", scripts.run(" and similar calls, the list offers your real saved queries, credentials, lookup tables, document templates and scripts.
  • Snippets. Type one of these names and press Tab: main, main-async, main-odbc, main-document, try-catch, retry-fetch, for-each-async, daily-window and verify-webhook.
  • The Docs panel. Documentation opens the full reference beside your code, with a search box. Its Plex APIs tab searches the Plex Connect API catalog. The same reference is published as the Script API reference.
  • AI assistant. If your company uses DataMagik's AI assistant, its AI Assistant button opens a chat that can read the script you are editing. It proposes code changes, which you approve before they are applied. Ask AI on the Problems list, and Ask AI to fix this on an error message, open the chat with the problem already filled in.

main(context)

Every script needs a function called main. DataMagik calls it with one argument, context, and what it returns is the run's result.

function main(context) {
  const order = context.order_no;
  if (!order) {
    return { success: false, script_message: "No order number was given." };
  }
  console.log("Processing order", order);
  return { success: true, script_message: "Processed " + order, data: { order_no: order } };
}

main can also be async function main(context), so you can use await. An async script is allowed its full timeout.

What is in context

Every run gets three keys from DataMagik. They replace any key with the same name in the input.

KeyWhat it holds
company_idYour company.
user_idThe person the run is for. 0 when no person is involved, such as on a schedule.
triggered_byWhat started the run, such as test-run, manual, scheduler, app, automation, assistant, email, file_gateway or script.

The rest depends on what started the run:

  • Test and Run in the editor: exactly the JSON on the Test input tab.
  • A webhook or API call: the JSON body of the request, as top-level keys.
  • A schedule: nothing else. There is no schedule name and no scheduled time.
  • An AI assistant: context.parameters, the arguments the assistant chose.
  • Another script: the parent's context with the keys it passed laid over it.
  • Apps, automations, email, files, hooks and others: each sends its own keys. See the page for each, and the Triggers tab below.

The Context browser

Click Context browser to see what context will hold. It has three tabs:

  • Test input: the JSON your test runs use. Type it here. Validate JSON checks it, and Clear empties it.
  • Past runs: the context a real earlier run received. Pick a run from the list.
  • Triggers: every way a script can be started and the keys each one sends.

Fields your code reads are marked read by this script; fields it reads that the chosen context does not have are marked read but missing. Click or drag a field into the code to insert it. Use as test input copies a past run's or a trigger's context into the Test input, which is the easiest way to rehearse a real start.

What a script returns

Return an object. Only success is required.

FieldWhat it does
successtrue if the script did its job, false if not. A run that returns false counts as a failure on the Executions page.
script_messageThe sentence the person who started the script reads.
script_titleA heading above that message.
notification_level"success", "warning", "error" or "info". Sets the message's colour. Anything else is treated as "info".
dataAny data for whatever called the script: an app, a webhook caller, a parent script. It is not shown to anyone.
errorWhy it failed. Use it with success: false.
documentsFiles the run produced, one entry per file: { url, filename, format }.
download_urlOne file.
_navigationSend the browser to a page when the script finishes.
_effectsActions in an Application Designer app, such as showing a dialog or refreshing a component.

Write script_message for the person who will read it on the shop floor. "No price for part 44-9912 in Part Pricing" tells them what to fix; "Failed" does not.

Where each field is shown

Different places read different fields. A script written for one place can look silent in another.

Started fromReads
The browser extension (Plex toolbar and automations)script_title, script_message and notification_level as a pop-up message, plus documents, download_url and _navigation.
An Application Designer status indicatorstatus (success, warning, error or neutral), text (or message, or script_message), detail and download_url. One file only: it ignores documents.
An app calling the script from its own codedata only.
A webhook or API callThe whole object.
A parent script, through scripts.runThe whole object.

A script that drives a status indicator should return status and text:

return {
  success: true,
  status: "success",
  text: "Order SO-1001 created",
  detail: "3 lines"
};

A hook script returns its own shape, such as { veto: true, reason: "…" }. See the hook's page.

Two common mistakes: returning message to the browser extension, which only shows script_message; and putting a file's URL inside data, where nothing opens it. Use documents or download_url for files.

Logging

console.log, console.info, console.warn, console.error and console.debug write lines to the run's log. Objects are written as JSON. You see the log on the run's Console Logs tab in the editor, live while it runs, and on the Executions page afterwards.

  • A run keeps up to 5,000 lines. After that the log says [truncated] and further lines are dropped.
  • A line longer than 10,000 characters is cut short.
  • Credentials are never put in context, so logging context does not reveal them. Do not log a credential's value yourself.

Testing a script

ButtonRunsNotes
TestThe code in the editor, saved or not, with the Test input as context.Does real work: emails are sent and Plex writes happen.
DebugThe code in the editor, stopping at breakpoints.Emails are captured, not sent. The run is allowed at least 30 minutes so you can step through it.
RunThe last saved version, with the Test input as context.The same as a real run started by a person. Unsaved changes are not used.

When a run starts, the Execution history panel opens. Each run has tabs:

  • Console Logs: the run's log, live while it runs.
  • Return Value: what main returned.
  • Generated Documents: files the run made, if any.
  • Error: why it failed, if it did.

The message at the bottom of the screen says whether the run finished, not what it returned. A script that returns success: false still shows Test execution completed, so check Return Value.

Test runs appear on the Executions page as test-run. See Script executions.

Debugging step by step

  1. Click just left of a line number, or put the cursor on a line and press F9, to set a breakpoint. With no breakpoints, Debug stops on the first line.
  2. Click Debug. When the run stops, the line is highlighted and a panel shows its local variables.
  3. Use Continue (F8), Step over (F10), Step into (F11), Step out or Stop.

Saving and versions

Click Save or press Ctrl+S. Each save creates a new numbered version. The newest version is what every real run uses from then on: schedules, webhooks, apps, Excel and the rest. Test and Debug do not need a save.

Click Version history to see the versions, newest first, with the current one marked CURRENT. For each version you can:

  • View Code.
  • Compare with Previous: show what changed from the version before.
  • Revert: save that version's code again as a new version. Nothing is deleted; the versions in between stay in the history.

Script settings

Click Script settings. Change what you need and click Save Changes, which also saves the code.

SettingWhat it does
Script Name and DescriptionHow the script is found and called. scripts.run calls a script by its name, so renaming one breaks callers that use the old name.
TagsGroup scripts in the search and in Integrations. Press Enter or comma after each tag.
Part ofThe integrations this script belongs to. Add to integration adds it to one. See Integrations.
CategoryA free-text group, used by the search's Category filter.
Priority (1-20)When work is waiting, a higher number runs sooner. Default 5.
Timeout (s)How long one run may take before it is stopped. Default 30 seconds, at most 2,700 (45 minutes).
Memory (MB)How much memory one run may use, from 64 to 256. Default 128. A run that needs more is stopped.
SchedulesThe schedules that run this script. Manage opens the Schedules page.
Assistant ToolLet AI assistants call the script. Turn on Expose as assistant tool, describe what it does, and optionally give a Parameters schema (Generate proposes one from the context keys your code reads). Tick Writes / mutates data if the script changes anything. Click Save tool registration. The schema also sets the inputs offered for Excel links.
Credentials and Allowed DomainsShortcuts to your company's credentials and to the list of outside sites scripts may call. Both are shared by every script in the company.
Delete ScriptStops the script from running. Its versions and run history are kept.

Sandbox rules and limits

  • No modules. There is no require or import, and no npm packages. Use the built-in tools, or share your own code with scripts.include.
  • No browser or Node.js objects. window, document, process and XMLHttpRequest do not exist. Use fetch for web requests.
  • No timers and no eval. setTimeout, setInterval, eval and new Function are not available.
  • Modern JavaScript works: async/await, classes, destructuring, ?., ??, Map, Set and regular expressions.
  • Outside sites must be allowed. Every host a script calls with fetch belongs on your company's Allowed Domains list. List each host exactly, or use *.example.com to allow every host under it. A call to a host that is not listed writes an [allowed-domains] warning to the run's console, and will be refused once enforcement is switched on; see Script credentials. DataMagik's own address is always allowed. Addresses inside a private network, and anything other than http and https, are always refused.
  • Web request limits. Each fetch waits up to 30 seconds and reads at most 10 MB of response.
  • Calls are rate-limited. A script that makes calls too fast gets an error back.
  • Secrets stay in credentials. Get them with credentials.get("NAME"); never type a password or key into the code. See Script credentials.

fetch, odbc.executeQuery and scripts.run wait for their answer before the script carries on, so wrapping them in Promise.all still runs them one at a time. To run several at once, use fetchAsync, odbc.executeQueryAsync or scripts.runAsync with await Promise.all(...).

Calling other scripts and sharing code

CallWhat it doesReturns
scripts.run(name, input)Runs another script's saved version on its own, separate from this one. Its context is this script's context with input laid over it.Everything the other script returned. If it could not run (not found, never saved, threw an error, timed out), { success: false, error: "…" }.
scripts.runAsync(name, input)The same, but several can run at once with await Promise.all(...). Each child gets its own run record.A promise of what the other script returned. If it fails, the promise rejects, so use try/catch.
scripts.include(name, includeData)Loads another script into this one, then calls its main. Functions it defines become available here. It receives includeData as context.includeData.What the included script's main returned.

Use scripts.include for a library of shared functions, and scripts.run for a separate job whose result you need.

function main(context) {
  scripts.include("Shared Formatting");       // defines formatPartNo()

  const check = scripts.run("Validate Order", { order_no: context.order_no });
  if (!check.success) {
    return { success: false, script_message: "Validation failed: " + (check.error || check.script_message) };
  }
  return { success: true, data: { part: formatPartNo(context.part_no), checked: check.data } };
}

Handling errors

Some tools report a failure in what they return, and some throw an error. plex.execute, fetch and email.send return a result you check; odbc.executeQuery throws. The Script API reference says which each one does. A pattern that covers both:

function main(context) {
  if (!context.part_no) {
    return { success: false, script_message: "part_no is required." };
  }

  try {
    const result = odbc.executeQuery("Part Lookup", { part_no: context.part_no });
    if (result.rowCount === 0) {
      return { success: false, script_message: "No part " + context.part_no + " in Plex." };
    }
    return { success: true, script_message: "Found " + context.part_no, data: { part: result.rows[0] } };
  } catch (error) {
    console.error("Part Lookup failed:", String(error));
    return { success: false, script_message: "Could not read Plex: " + String(error), notification_level: "error" };
  }
}

A run that throws, runs out of time or runs out of memory is recorded as failed, with the reason on its Error tab.

Keyboard shortcuts

KeysDoes
Ctrl+KSearch scripts.
Ctrl+SSave.
Ctrl+EnterRun the last saved version (the same as Run, not Test).
Shift+F11 / EscapeFull-screen editor on / off.
Shift+Alt+FFormat the code.
Ctrl+SpaceShow autocomplete.
Ctrl+/Comment or uncomment the line.
Ctrl+DSelect the next match of the selected text.
Ctrl+Shift+KDelete the line.
F9Set or clear a breakpoint on the current line.
F8 / F10 / F11While a debug run is paused: continue / step over / step into.

On a Mac, use Cmd in place of Ctrl.

Good habits

  • Check the input first. Return a clear script_message when a required key is missing, rather than failing halfway through.
  • Rehearse the real start. Use Past runs or Triggers and Use as test input, so your test sees the same context as the real thing. Remember a scheduled run gets almost nothing.
  • Keep company-specific values out of the code. Use lookup tables or a workflow's constants, and credentials for anything secret.
  • Use saved queries. Save SQL in the SQL Editor and call it with odbc.executeQuery, rather than writing SQL in the script.
  • Send email from templates. Use email.sendWithTemplate with a saved email template, so the wording can change without a new script version.
  • Log what helps the next person. A line at each important step makes a failed run easy to read on the Executions page; logging every row of a large loop hides the useful lines.
  • Test before you save. Saving changes what every schedule and caller runs next.
Was this page helpful?