DataMagik Script Engine

Updated Mar 28, 2026
DataMagik Automate

Script Engine User Guide

Complete reference for automating workflows, generating documents, and integrating with external systems using DataMagik's JavaScript-based Script Engine.

Table of Contents

  1. Getting Started
  2. Return Values & Notifications
  3. Document Generation
  4. User Defined Tables
  5. Serial Number Generation
  6. Calling Other Scripts
  7. Credentials Management
  8. HTTP Requests
  9. Manufacturing & Printing
  10. ZPL Label Templates
  11. Helper Functions
  12. Script Schedules
  13. Keyboard Shortcuts
  14. Best Practices

1. Getting Started

Every script in the Script Engine must have a main(context) function. This function receives input data and returns a result object.

Your First Script

function main(context) {
  console.log("Hello from Script Engine!");
  
  return {
    success: true,
    script_message: "Script executed successfully!",
    data: { result: "your data here" }
  };
}

Key Concepts:

  • context — An object containing all input data passed to your script
  • return object — Must include at minimum a success boolean
  • console.log() — Outputs appear in the execution history for debugging

Testing Your Script

Use the Test Run button to execute your script before saving. You can provide test input context using the Test Input Context panel.

Script Versions

Each script maintains a version history. When you save changes, a new version is created. You can view previous versions and their code from the script's version panel.

2. Return Values & Notifications

The return object from your main() function controls what happens after execution and what the user sees.

Return Object Properties

PropertyTypeDescription
successbooleanRequired. Indicates if the script succeeded
script_messagestringUser-facing message shown in UI notifications
script_titlestringOptional title for toast notifications
notification_levelstring"success", "warning", "error", or "info"
dataobjectAny additional data to return to the caller
errorstringError message if success is false

Toast Notification Examples

Success Notification:

return {
  success: true,
  script_title: "Order Processed",
  script_message: "Order #12345 was created successfully",
  notification_level: "success"
};

Warning Notification:

return {
  success: true,
  script_title: "Missing Data",
  script_message: "Customer code not provided, using default",
  notification_level: "warning"
};

Error Notification:

return {
  success: false,
  script_title: "Processing Failed",
  script_message: "Unable to connect to external API",
  notification_level: "error"
};

3. Document Generation

Generate PDF documents using the global documents object. Documents are processed asynchronously through a worker queue.

Available Methods

MethodDescription
documents.generate(template, fields)Queue async generation, returns request ID
documents.generateSync(template, fields, opts?)Generate and wait for completion
documents.getStatus(requestId)Check status of pending generation

Async Generation (Fire & Forget)

function main(context) {
  const reqId = documents.generate(
    "template-uuid-or-name",
    {
      customerName: context.name,
      orderDate: "2025-12-05",
      items: context.lineItems
    }
  );

  console.log("Document queued:", reqId);
  
  return { 
    success: true, 
    script_message: "Document generation started",
    data: { document_request_id: reqId } 
  };
}

Synchronous Generation (Wait for Result)

function main(context) {
  const result = documents.generateSync(
    "Invoice Template",
    { 
      customerName: context.name, 
      total: context.total 
    },
    { 
      returnType: "url",    // "url" or "binary" (base64)
      timeout: 60000        // milliseconds to wait
    }
  );

  if (result.success) {
    return {
      success: true,
      data: { url: result.documentUrl }
    };
  } else {
    return {
      success: false,
      error: result.error
    };
  }
}

Checking Status

const status = documents.getStatus(requestId);
// status = {
//   status: "pending" | "processing" | "completed" | "failed",
//   document_url: "...",     // if completed
//   error_message: "...",    // if failed
//   file_size_bytes: 12345
// }

4. User Defined Tables

User Defined Tables (UDTs) allow you to store and retrieve customer-specific configurations, mappings, and data. Access them using the tables object.

Note: Manage tables via Manufacturing → User Defined Tables in the navigation menu.

Available Methods

MethodDescription
tables.get(table, key1, [key2])Get full entry by key(s), includes metadata
tables.getValue(table, key1, [key2])Get just the value (shorthand)
tables.exists(table, key1, [key2])Check if entry exists, returns boolean
tables.set(table, key1, [key2], value)Create or update an entry (upsert)
tables.list(table, [key1])List all entries, optionally filtered by key1

Reading Data

function main(context) {
  // Full entry lookup (includes metadata)
  const customer = tables.get("customer_settings", context.customerCode);
  const templateId = customer ? customer.value.template_id : null;
  
  // Direct value lookup (simpler)
  const config = tables.getValue("customer_settings", context.customerCode);
  const template = config ? config.template_id : "default";
  
  // Composite key lookup (e.g., customer + location)
  const shippingDoc = tables.getValue(
    "customer_shipping_docs",
    context.customerCode,
    context.shipToCode
  );
  
  // Check existence for blocklists
  if (tables.exists("blocklist", context.ip)) {
    return { success: false, script_message: "Blocked" };
  }
  
  return { success: true, data: { template: templateId } };
}

Writing Data

function main(context) {
  // Update order status (creates if doesn't exist)
  tables.set("order_status", context.orderId, {
    status: "processed",
    updated_at: new Date()
  });

  // Get all shipping locations for a customer
  const allLocations = tables.list(
    "customer_shipping_docs",
    context.customerCode
  );
  
  return { 
    success: true, 
    data: { locations: allLocations } 
  };
}

Tip: Table functions are synchronous. Use tables.getValue() for cleaner code when you only need the value object.

5. Serial Number Generation

Generate and manage serial numbers using the serial object. Serial number patterns are configured in Manufacturing → Traceability.

Available Methods

MethodDescription
serial.next(series, [context])Generate next serial (increments counter)
serial.preview(series, [context])Preview next serial (no increment)
serial.info(series)Get pattern details (format, counter)
serial.batch(series, count, [context])Generate multiple serials at once
serial.list()List all available serial patterns

Basic Usage

function main(context) {
  // Generate next serial number
  const sn = serial.next("WorkOrders", {
    plant: "DET",
    line: "L1"
  });
  
  // Preview without consuming
  const nextSn = serial.preview("WorkOrders", {
    plant: "DET",
    line: "L1"
  });
  
  return {
    success: true,
    data: { serial_number: sn }
  };
}

Batch Generation

function main(context) {
  // Get pattern information
  const info = serial.info("batch_serial");
  // info = { name, format, description, current_value, prefix, suffix }
  
  // Generate multiple serials for a batch run
  const serials = serial.batch("part_serial", 5, { line: "L1" });
  // serials = ["SN-2025-00001", "SN-2025-00002", ...]
  
  // List all available patterns
  const patterns = serial.list();
  
  return {
    success: true,
    data: { 
      batch_serials: serials, 
      available_patterns: patterns.length 
    }
  };
}

Tip: Use serial.batch() for bulk operations to ensure atomic serial number allocation.

6. Calling Other Scripts

Organize your code by calling other scripts or including shared utility functions.

Available Methods

MethodDescription
scripts.run(name, input)Execute another script and get its result
scripts.include(name)Include shared code/functions (like import)

Execute Another Script

function main(context) {
  // Call another script by name
  const result = scripts.run("SharedUtility", {
    data: context.rawData
  });
  
  // scripts.run returns the 'data' object from the child script's return
  
  return {
    success: true,
    data: { processed: result }
  };
}

Include Shared Code

// In your main script:
function main(context) {
  // Include shared utility functions
  scripts.include("SharedHelpers");
  
  // Now you can use functions defined in SharedHelpers
  const formatted = formatCustomerName(context.customer);
  const validated = validateOrder(context.order);
  
  return { 
    success: validated, 
    data: { name: formatted } 
  };
}

// SharedHelpers script contains:
// function formatCustomerName(c) { return c.first + " " + c.last; }
// function validateOrder(o) { return o.items && o.items.length > 0; }

Tip: Use scripts.include() for shared utilities, and scripts.run() when you need a full script's output.

7. Credentials Management

Access securely stored API keys and secrets using the credentials object. Credentials are configured in Settings → Credentials.

Credential Types

TypeDescription
API KeySingle API key value
Basic AuthUsername and password pair
OAuth2OAuth2 client credentials
Custom JSONArbitrary JSON object for complex credentials

Using Credentials

function main(context) {
  // Get API key stored in credentials
  const apiKey = credentials.get("PLEX_API_KEY");
  
  // Use in your API calls
  return {
    success: true,
    data: { hasKey: !!apiKey }
  };
}

Security Note: Never hardcode API keys or secrets in your scripts. Always use the credentials system.

8. HTTP Requests

Make external API calls using the http object. Only domains configured in the allowed list can be accessed.

function main(context) {
  // Synchronous GET request
  const resp = http.get("https://api.example.com/data");

  // Response structure:
  // {
  //   status: 200,
  //   statusText: "OK",
  //   data: { ... } // Parsed JSON body
  // }

  if (resp.status === 200) {
    return {
      success: true,
      data: resp.data
    };
  } else {
    return {
      success: false,
      error: resp.statusText
    };
  }
}

Allowed Domains

Only whitelisted domains can be accessed from scripts. Configure permitted domains in Settings → Allowed Domains.

  • Add domains to allow HTTP requests to external services
  • Remove domains to revoke access
  • All subdomains of allowed domains are also permitted

9. Manufacturing & Printing

Access printers and send print jobs using the manufacturing object. Printers must be registered through your site's connector.

Available Methods

MethodDescription
manufacturing.getPrinters()List all available printers
manufacturing.getPrinter(name)Get details of a specific printer
manufacturing.printLabel(printer, zpl)Send raw ZPL to a printer
manufacturing.printFromTemplate(printer, template, data)Print using a ZPL template
manufacturing.printBatch(printer, template, items)Print multiple labels in one job

List and Print

function main(context) {
  // List available printers
  const printers = manufacturing.getPrinters();
  console.log("Available printers:", printers.map(p => p.name));
  
  // Get specific printer details
  const printer = manufacturing.getPrinter("Line1-Zebra");
  if (!printer) {
    return { success: false, error: "Printer not found" };
  }
  
  // Print raw ZPL
  const result = manufacturing.printLabel(
    "Line1-Zebra", 
    "^XA^FO50,50^A0N,50,50^FDHello World^FS^XZ"
  );
  
  return {
    success: result.success,
    data: { job_id: result.job_id }
  };
}

Template-Based Printing

function main(context) {
  // Print using a template
  manufacturing.printFromTemplate(
    "Shipping-Printer",
    "ShippingLabel",
    {
      orderNumber: context.order_id,
      customerName: context.customer,
      address: context.ship_to
    }
  );
  
  // Batch print multiple labels
  const batchResult = manufacturing.printBatch(
    "Line1-Zebra",
    "PartLabel",
    context.parts.map(p => ({
      partNumber: p.number,
      serialNumber: p.serial,
      quantity: p.qty
    }))
  );
  
  return {
    success: true,
    data: {
      batch_jobs: batchResult.job_ids,
      labels_printed: batchResult.count
    }
  };
}

Note: Printers must be registered in your site's connector. Configure in Connectors → Printers.

10. ZPL Label Templates

Render ZPL label templates with data substitution using the zpl object.

function main(context) {
  // Render a ZPL template to a string (without printing)
  const zplCode = zpl.fromTemplate("PartLabel", {
    partNumber: "PN-12345",
    description: "Widget Assembly",
    serialNumber: serial.next("PartSerial"),
    barcode: context.barcode_data
  });
  
  // Print it
  manufacturing.printLabel("Zebra-01", zplCode);
  
  return {
    success: true,
    data: { zpl: zplCode }
  };
}

Tip: Use zpl.fromTemplate() to preview or modify ZPL before printing.

11. Helper Functions

Common utility functions are available via the helpers object.

Available Methods

MethodDescription
helpers.formatDate(date, format)Format date to string
helpers.parseDate(str, format)Parse string to Date object
helpers.formatNumber(num, decimals)Format number with decimal places
helpers.formatCurrency(num, currency)Format as currency
helpers.deepClone(obj)Deep copy an object
helpers.uuid()Generate a new UUID
helpers.hash(str, algo)Hash string (sha256, md5)
helpers.base64Encode(str)Encode string to Base64
helpers.base64Decode(str)Decode Base64 to string

Date & Number Formatting

function main(context) {
  const now = new Date();
  
  // Format dates (Go-style format: 2006-01-02 15:04:05)
  const dateStr = helpers.formatDate(now, "2006-01-02");  // "2025-12-05"
  const timeStr = helpers.formatDate(now, "15:04:05");    // "14:30:00"
  const fullStr = helpers.formatDate(now, "Jan 2, 2006"); // "Dec 5, 2025"
  
  // Parse dates
  const parsed = helpers.parseDate("2025-12-25", "2006-01-02");
  
  // Format numbers
  const price = helpers.formatNumber(1234.567, 2);     // "1234.57"
  const usd = helpers.formatCurrency(1234.56, "USD"); // "$1,234.56"
  const eur = helpers.formatCurrency(1234.56, "EUR"); // "€1,234.56"
  
  return { 
    success: true, 
    data: { date: dateStr, price: usd } 
  };
}

Date Format Reference

DataMagik uses Go-style format patterns:

PatternMeaning
2006Year (4 digits)
01Month (2 digits)
02Day (2 digits)
15Hour (24-hour, 2 digits)
04Minute (2 digits)
05Second (2 digits)

Other Utilities

function main(context) {
  // Generate UUID
  const id = helpers.uuid();
  
  // Deep clone (safe copy)
  const copy = helpers.deepClone(context.data);
  copy.modified = true;  // Won't affect original
  
  // Hashing
  const hash = helpers.hash("secret", "sha256");
  
  // Base64
  const encoded = helpers.base64Encode("Hello World");
  const decoded = helpers.base64Decode(encoded);
  
  return { 
    success: true, 
    data: { id, hash } 
  };
}

12. Script Schedules

Run scripts automatically on a recurring schedule using cron expressions.

Creating a Schedule

Navigate to DataMagik → Script Schedules to manage scheduled script executions.

FieldDescription
NameSchedule display name
ScriptScript to execute
Cron ExpressionWhen to run (e.g., 0 9 * * MON-FRI)
Input ContextJSON data passed to the script's context
EnabledToggle the schedule on/off

Common Cron Patterns

ExpressionDescription
*/15 * * * *Every 15 minutes
0 9 * * MON-FRI9 AM on weekdays
0 */2 * * *Every 2 hours
0 0 1 * *Midnight on the 1st of each month
0 6,18 * * *6 AM and 6 PM daily

Managing Schedules

  • Enable/Disable — Toggle schedules without deleting them
  • Execution History — View past executions with status, duration, and output
  • Cancel Queued — Cancel pending executions that haven't started yet
  • Validate Cron — Use the cron validator to preview when your schedule will run next

13. Keyboard Shortcuts

Speed up your development with these keyboard shortcuts:

ShortcutAction
Ctrl+SSave script
Ctrl+EnterExecute script (Test Run)
Shift+F11Toggle fullscreen editor
EscapeExit fullscreen
Ctrl+SpaceShow autocomplete suggestions
Ctrl+/Toggle line comment
Ctrl+DSelect next occurrence
Ctrl+Shift+KDelete line

Tip: Type main in the editor and press Tab for a template snippet.

14. Best Practices

Code Organization

  • Validate context early — Check required fields exist before using them
  • Use User Defined Tables — Don't hardcode customer-specific values
  • Store secrets in credentials — Never hardcode API keys in scripts
  • Add console.log statements — They appear in execution history for debugging
  • Return meaningful messages — Use script_message for user visibility
  • Test before saving — Use Test Run to avoid breaking production scripts

Error Handling Pattern

function main(context) {
  try {
    if (!context.orderId) {
      return {
        success: false,
        error: "Order ID is required",
        notification_level: "error"
      };
    }
    
    const result = processOrder(context.orderId);
    
    return {
      success: true,
      script_message: "Order processed successfully",
      data: result
    };
    
  } catch (error) {
    console.error("Script failed:", error);
    return {
      success: false,
      script_title: "Processing Error",
      script_message: String(error),
      notification_level: "error"
    };
  }
}

Complete Example: Customer-Specific Document Generation

function main(context) {
  // Look up customer's preferred template
  const customer = tables.get("customer_templates", context.customerCode);
  
  // Use customer template or fallback to default
  const templateId = customer 
    ? customer.value.template_id 
    : "default-invoice-template";
  
  // Queue document generation
  documents.generate(templateId, {
    customerName: context.customerName,
    orderNumber: context.orderNumber,
    items: context.lineItems
  });
  
  return {
    success: true,
    script_message: "Document queued for " + context.customerCode
  };
}
Was this page helpful?