Table of Contents
- xyOps SDK for Node.js
- Installation
- Job Runtime SDK
- Complete Job Example
- API Client
- API Catalog
- License
The xyOps SDK is a Node.js client library for xyOps, a workflow automation, job scheduling, and server monitoring platform. It provides a friendly JavaScript interface for two common use cases: controlling xyOps remotely through its REST API, and communicating with xyOps from inside a running job.
The package provides two independent interfaces:
apiis a wrapper around the xyOps REST API. It handles request formatting, authentication, and response parsing for you. Use it from applications, services, command-line scripts, integrations, or even from inside an xyOps job. See API Client for details.jobis a runtime toolkit for Node.js code launched by xyOps. It reads the job input, provides access to parameters, data, files, secrets, performance metrics, and optional structured logging, and sends progress updates and final results back to xyOps. It handles the JSON-over-STDIO wire protocol for you. See Job Runtime SDK for details.
You can use either interface by itself, or use both together inside a job. Import them using CommonJS:
const { api, job } = require('@pixlcore/xyops-sdk');Or using ESM:
import { api, job } from '@pixlcore/xyops-sdk';The SDK is included with xySat (xyOps Satellite) v1.0.34 and later. This means your custom xyOps Event Plugins, and scripts running through the built-in Shell Plugin, can use the SDK automatically by requiring it, without a separate installation step.
npm install @pixlcore/xyops-sdkThe job interface is designed for a custom Node.js Event Plugin or a Node.js script running through the built-in Shell Plugin. It reads the job document from STDIN and writes newline-delimited XYWP JSON to STDOUT.
Always call and await job.read() before accessing job input:
const { api, job } = require('@pixlcore/xyops-sdk');
(async function() {
await job.read();
let params = job.getParams();
console.log('My param: ' + params.myparam);
job.finalSuccess('Job successful');
})();If you are developing an ESM module, you can use import syntax with top-level await (with Node.js v22+):
import { api, job } from '@pixlcore/xyops-sdk';
await job.read();
let params = job.getParams();
console.log('My param: ' + params.myparam);
job.finalSuccess('Job successful');Normal output that does not contain XYWP JSON is written to the job log. Every helper update is flushed immediately to STDOUT.
Once you call job.finalSuccess() or job.finalError(), the SDK disables further job updates. Make the final call the last operation in your script.
Async function which reads all JSON from STDIN and merges the job properties into the job object.
await job.read();
console.log(job.id);For more details about what is included, see Job Input.
Returns all Event Plugin parameters.
let params = job.getParams();
console.log(params);Returns one Event Plugin parameter by its name.
let mode = job.getParam('mode');Returns the input.files metadata array. Input files are already downloaded into the job's current working directory.
let files = job.getFiles();
for (let file of files) console.log(file.filename);For more details, see Input Files.
Returns all input.data, or one top-level value when you provide a key.
let data = job.getData();
let customerId = job.getData('customer_id');Returns all shared workflow data, or one top-level value. Outside a workflow this returns an empty object or undefined for a missing key.
let shared = job.getWorkflowData();
let batchId = job.getWorkflowData('batch_id');For more details, see Sharing Data Between All Nodes.
Returns all user data for the current server, or one top-level value.
let serverData = job.getServerData();
let region = job.getServerData('region');For more details, see Server User Data.
Returns all assigned Secret Vault variables.
let secrets = job.getSecrets();For more details, see Secrets.
Returns one assigned Secret Vault variable by its name.
let password = job.getSecret('DB_PASSWORD');Do not print secrets to STDOUT or STDERR because ordinary output is captured in the job log.
These helpers let your job encrypt and decrypt its own values locally. They use the same encryption format used internally by xyOps: AES-256-GCM authenticated encryption, with a unique random salt and initialization vector for every call. The passphrase is processed with scrypt to derive the encryption key.
The value may be an object, array, string, number, boolean, or null. In other words, it can be any value which can safely make a JSON round trip. Values with special JSON behavior may not come back in their original form. For example, a Date becomes a string, properties containing undefined are omitted, and circular objects or values containing BigInt cannot be serialized.
You supply and manage the passphrase. A long, randomly-generated passphrase from an xyOps Secret Vault variable is strongly recommended. Do not hard-code it, write it to the job log, or store it beside the encrypted record.
Both helpers also accept optional additional authenticated data, or AAD. AAD is context which is authenticated along with the ciphertext but is not encrypted or included in the returned record. It is useful for binding an encrypted value to a particular customer, record, or purpose. For example, an AAD value such as customer:CUSTOMER_ID prevents that ciphertext from being successfully decrypted in a different customer context. AAD can be public, but decryption must receive the exact same string or Buffer. If you omit it during encryption, omit it during decryption too.
The return value is one Base64-encoded string containing the ciphertext and all encryption metadata. You can store it directly in a spreadsheet cell, text field, environment variable, or any other system which accepts plain strings. Internally, the binary encryption fields are also Base64-encoded before the entire record is encoded. This extra Base64 layer is for portability only and does not add encryption.
Because each encryption uses a random salt and initialization vector, encrypting the same value twice produces different strings.
Encrypts a JSON-serializable value using your passphrase and optional AAD, then returns a single Base64-encoded string.
await job.read();
let passphrase = job.getSecret('SECRET_PASSPHRASE');
if (!passphrase) return job.finalError('missing_passphrase', 'Encryption passphrase is not available');
let encrypted = job.encryptValue({
username: 'jsmith',
password: '12345'
}, passphrase);The returned value is an opaque plain string which can be stored without any additional serialization. Pass it back to job.decryptValue() exactly as returned.
Accepts a Base64-encoded string previously returned by job.encryptValue(), then decrypts and returns the original JSON value.
let passphrase = job.getSecret('SECRET_PASSPHRASE');
let encrypted = job.getData('protected_value');
try {
let value = job.decryptValue(encrypted, passphrase);
console.log('Decrypted value for user: ' + value.username);
}
catch (err) {
job.finalError('decrypt_failed', 'Could not decrypt the protected value');
}This method throws an error if the input cannot be decoded, if the passphrase or AAD does not match, if the encrypted string was modified or damaged, or if the decrypted content is not valid JSON. Wrap calls in try / catch, and avoid logging the decrypted value or the underlying error if either could expose sensitive information.
Adds freeform output data for downstream jobs. Multiple updates are shallow-merged by xyOps, and top-level arrays are concatenated.
job.addData({ records_processed: 125, result: 'ok' });For more details, see Output Data.
Adds shared workflow data. xyOps merges it into the parent workflow when this sub-job completes.
job.addWorkflowData({ batch_id: 'batch-2026-07-12' });For more details, see Workflow Data.
Adds persistent user data for the server running the job. xyOps applies the shallow merge when the job completes.
job.addServerData({ last_backup: Date.now() });For more details, see Server Data.
Appends one output file path or glob pattern. xyOps uploads the matching files when the job completes and passes them to downstream jobs.
job.addFile('report.csv');For more details, see Output Files.
Appends multiple output file paths or glob patterns. Each item may also be an object with path and delete properties.
job.addFiles(['logs/*.log', { path: 'temp/*.json', delete: true }]);For more details, see Output Files.
Appends one Tag ID to the current job.
job.addTag('important');For more details, see Job Tags.
Appends multiple Tag IDs to the current job.
job.addTags(['nightly', 'backup']);For more details, see Job Tags.
Appends one job action object. See Action Types for all supported properties.
job.addAction({
condition: 'success',
type: 'run_event',
event_id: 'EVENT_ID',
params: {},
enabled: true
});For more details, see Job Actions.
Appends multiple job action objects. See Action Types for all supported properties.
job.addActions([
{ condition: 'complete', type: 'email', email: 'ops@example.com', users: [], enabled: true }
]);For more details, see Job Actions.
These helpers add a custom report to the Job Details page. caption is optional in every call.
Displays tabular data.
job.setTable(
'Import Results',
['File', 'Rows'],
[['customers.csv', 250], ['orders.csv', 840]],
'Rows imported by file'
);For more details, see Custom Content.
Displays sanitized HTML. xyOps removes elements and attributes that are not allowed by its sanitization configuration.
job.setHTML('Summary', '<b>Backup complete</b>', 'Generated by the backup job');For more details, see Custom Content.
Displays plain text while preserving whitespace.
job.setText('Command Output', 'Processed: 125\nFailed: 0');For more details, see Custom Content.
Displays GitHub Flavored Markdown rendered and sanitized by xyOps.
job.setMarkdown('Summary', '**Backup complete**\n\nAll files were uploaded.');Only one HTML, text, or Markdown content block is retained for a job.
For more details, see Custom Content.
Updates the job progress. Pass a fraction from 0.0 through 1.0, or a percentage greater than 1.
job.setProgress(0.25);
job.setProgress(50);
job.setProgress(100);Sets the temporary status line shown while the job is running.
job.setStatus('Processing file 34 of 68...');Sets the label displayed beside the Job ID in completed job history.
job.setLabel('Nightly Customer Import');After you call and await job.read(), job.logger contains a ready-to-use pixl-logger instance. Logging is completely optional. The SDK creates the logger for you, but it does not write anything unless you call one of its logging methods.
pixl-logger writes one text row per event using bracket-delimited columns. For example, a debug message may look like this:
[1784059200.123][2026-07-14 10:20:00][worker01][12345][EVENT_ID][JOB_ID][debug][1][Starting database backup][]
The SDK configures these columns by default:
[
'hires_epoch', 'date', 'hostname', 'pid', 'event',
'job', 'category', 'code', 'msg', 'data'
]The timestamps, hostname, process ID, Event ID, and Job ID are populated automatically. The shortcut methods also populate category, so you typically only need to provide a code, msg, and optional data. Objects passed as data are serialized as JSON.
await job.read();
job.logger.debug(1, 'Debug level 1 message');
job.logger.error('DB702', 'Database connection failed');
job.logger.transaction('backup_create', 'Created backup successfully', {
files: 14,
bytes: 5823411
});The default debug level is 1. Calls to debug() with a higher level are silently skipped. Set a more verbose level once, immediately after reading the job:
await job.read();
job.logger.set('debugLevel', 9);
job.logger.debug(9, 'Detailed diagnostic message');The logger initially writes to the unique path supplied by xyOps in job.log_file. If the logger writes to this path, xySat automatically uploads the file, attaches it to the job at completion, and deletes the local copy.
You can point the logger at a different file at any time:
job.logger.path = '/var/log/my-custom-log.log';A custom path is not uploaded or deleted automatically. You are responsible for rotating or archiving that file. If you want the custom log attached to the job, add it explicitly:
job.addFile(job.logger.path);You can replace the default columns with any set you need:
job.logger.columns = ['date', 'code', 'msg'];You can also replace the default bracket-delimited serializer. This example writes a simple comma-separated row:
job.logger.serializer = function(cols, args) {
return cols.join(',') + "\n";
};By default, the SDK enables synchronous mode, so each row is written with fs.appendFileSync(). This is a safe default for ordinary job logging. If your job produces an extremely high volume of log rows, enable buffering to write rows in batches. Approximate time mode can reduce clock overhead as well:
await job.read();
job.logger.enableBuffer();
job.logger.approximateTime = true;
// Perform high-volume work and write log rows here.
job.finalSuccess('High-volume work complete');See the pixl-logger documentation for the complete API, including print(), custom hooks, console echoing, buffering, rotation, and archiving.
After you call and await job.read(), job.perf contains a running pixl-perf tracker. You can use it to measure named operations and increment arbitrary counters throughout your job:
await job.read();
job.perf.begin('db_backup');
// Perform the database backup.
job.perf.end('db_backup');
job.perf.begin('db_vacuum');
// Vacuum the database.
job.perf.end('db_vacuum');
job.perf.count('db_bytes_saved', 5000);
job.perf.count('dangling_pages', 8);
job.finalSuccess('Database maintenance complete');Named timings are cumulative, so you can call begin() and end() with the same name multiple times. Counters also accumulate, and default to an increment of 1 when you omit the amount:
job.perf.count('records_processed');
job.perf.count('records_processed', 25);For overlapping asynchronous operations that use the same metric name, keep the tracker returned by begin() and end that specific measurement:
let tracker = job.perf.begin('api_request');
await makeRequest();
tracker.end();When you call job.finalSuccess() or job.finalError(), the SDK automatically summarizes the tracker and includes the metrics in the final job metadata for xyOps to display. If you do not add any named timings or counters, the SDK omits the tracker summary.
The SDK reports timings in seconds by default. To use a different time scale, call setScale() immediately after job.read() and before recording your own metrics. For example, use a scale of 1000 to report milliseconds:
await job.read();
job.perf.setScale(1000); // millisecondsThe scale represents how many units equal one second. Use 1 for seconds, 1000 for milliseconds, 1000000 for microseconds, or 1000000000 for nanoseconds. See the pixl-perf documentation for precision and advanced tracker options.
If you already have your own raw performance metrics and do not want to use pixl-perf, you can send them directly with job.write(). Values normally represent elapsed seconds:
job.write({ perf: { foo: 42, bar: 100 } });For more details about accepted raw formats, see Perf Metrics.
Completes the job successfully with code 0. The message is optional and defaults to Success. Any user-added performance metrics are included automatically.
job.finalSuccess('Imported 250 records');Completes the job with an error. The code defaults to 1, and the message defaults to Unknown Error. Any user-added performance metrics are included automatically.
job.finalError(999, 'Database connection failed');An error code may be a number or string, but it must be truthy.
Writes one raw XYWP update immediately. The SDK adds xy: 1, serializes the object onto one line, and appends a newline. Prefer the specific helpers above when one is available.
job.write({ progress: 0.5, status: 'Halfway there...' });Do not include a final code with job.write() and then continue sending updates. Prefer finalSuccess() or finalError() so the SDK also prevents accidental writes after completion.
const { api, job } = require('@pixlcore/xyops-sdk');
(async function() {
try {
await job.read();
let eventId = job.getParam('event_id');
job.setLabel('Event Inspector');
job.setStatus('Loading event...');
job.setProgress(10);
let { err, data } = await api.getEvent({ id: eventId });
if (err) return job.finalError(1, err.message || String(err));
job.addData({
event_id: data.event.id,
event_title: data.event.title
});
job.setMarkdown(
'Event Summary',
'Loaded **' + data.event.title + '** successfully.'
);
job.setProgress(100);
job.finalSuccess('Event loaded');
}
catch (err) {
job.finalError(1, err.message || String(err));
}
})();When this code runs as an xyOps job, the API client automatically uses JOB_BASE_URL. You still need to make an API key available as XYOPS_API_KEY, typically through the xyOps Secret Vault.
Set these environment variables before loading the SDK:
| Variable | Required | Description |
|---|---|---|
XYOPS_BASE_URL |
Yes, outside a job | Base URL of your xyOps conductor, such as https://xyops.example.com. |
XYOPS_API_KEY |
Yes | An xyOps API Key with the privileges required by the APIs you call. |
JOB_BASE_URL |
(Automatic) | Base URL supplied to running xyOps jobs. This is used when XYOPS_BASE_URL is not set. |
XYOPS_USER_AGENT |
No | Replaces the default SDK HTTP User-Agent string. |
XYOPS_TIMEOUT |
No | Time-to-first-byte timeout in milliseconds. Defaults to 30000. |
XYOPS_CONNECT_TIMEOUT |
No | DNS and socket connection timeout in milliseconds. Defaults to 10000. |
XYOPS_IDLE_TIMEOUT |
No | Socket idle timeout in milliseconds. Defaults to 30000. |
XYOPS_RETRIES |
No | Number of automatic request retries. Defaults to 0. |
XYOPS_RETRY_DELAY |
No | Initial delay between automatic retries in milliseconds. The delay doubles after each retry. Defaults to 50. |
XYOPS_RETRY_DELAY_MAX |
No | Maximum delay between automatic retries in milliseconds. Defaults to 8000. |
XYOPS_ALLOW_UNAUTHORIZED |
No | Set to any nonempty value to accept self-signed or otherwise unauthorized TLS certificates. This disables certificate verification for all SDK API requests. |
For example:
export XYOPS_BASE_URL="https://xyops.example.com"
export XYOPS_API_KEY="YOUR_API_KEY"XYOPS_ALLOW_UNAUTHORIZED is intended for local development and testing. Do not enable it in production unless you understand the risks.
The client automatically sends the API key in the X-API-Key header.
API methods use camel case. The SDK converts the method name to the snake case xyOps API name, so api.getEvent() calls get_event:
const { api } = require('@pixlcore/xyops-sdk');
(async function() {
let { err, data } = await api.getEvent({ id: 'emri0e0tnxibay5t' });
if (err) {
console.error(err);
return;
}
console.log(data.event);
})();The first argument is the API request object. Depending on the API, this may be automatically serialized as a query string, or passed as JSON POST data.
The API client does not throw by default. Every call resolves to the following object:
let { err, data, resp, perf } = await api.getEvent({ id: 'emri0e0tnxibay5t' });| Property | Description |
|---|---|
err |
An error object or message on failure. It will be false or undefined on success. |
data |
Response data. Standard API responses are parsed into JavaScript objects. Downloads and streams may not include this. |
resp |
The raw Node.js IncomingMessage response. |
perf |
A pixl-perf request tracker. Call perf.metrics() for timing and counter details. |
Check err before using data:
let { err, data } = await api.getEvents();
if (err) return console.error(err);
console.log(data.rows);If you prefer exceptions, enable throw mode once during startup:
api.throw = true;
try {
let { data } = await api.getEvent({ id: 'emri0e0tnxibay5t' });
console.log(data.event);
}
catch (err) {
console.error(err);
}Pass a optional options object as the second argument. You can specify properties such as headers, files, and download. The SDK always adds the X-API-Key header (unless you set your own).
let { err, data } = await api.runEvent(
{ id: 'emri0e0tnxibay5t' },
{ headers: { 'X-Request-ID': 'deploy-123' } }
);See the pixl-request documentation for all supported options.
Set download to a destination path or writable stream, for APIs that return binary responses. The promise resolves after the complete response has been written.
let { err } = await api.getJobLog(
{ id: 'JOB_ID' },
{ download: 'dest_file.log' }
);You can use the same pattern for other wrapped binary or streamed APIs. Endpoints with extra path components or nonstandard GET names may require a direct HTTP request, as noted in the catalog.
Pass file paths in opts.files like this:
let { err } = await api.uploadBucketFiles(
{ id: 'BUCKET_ID' },
{ files: ['file1.txt', 'file2.txt'] }
);You can pass the files array directly as a shorthand:
let { err } = await api.uploadBucketFiles(
{ id: 'BUCKET_ID' },
['file1.txt', 'file2.txt']
);The same pattern works with APIs such as uploadFiles, runEvent, createTicket, uploadUserTicketFiles, and sendEmail.
streamJob watches a live job, and calls your iterator function for every update (i.e. progress, state changes, completion, etc.):
let { err } = await api.streamJob({ id: 'JOB_ID' }, function(data) {
// called repeatedly for each streaming job update
console.log(data);
});The call remains pending until the event stream closes.
Every standard API method is available via the SDK. The examples below show the SDK method and an example request. Follow each link for parameters, privileges, and response fields.
All examples assume you've preloaded the API:
const { api } = require('@pixlcore/xyops-sdk');Fetch all alert definitions. This call does not require any parameters. See the get_alerts API reference for response details.
let { err, data } = await api.getAlerts();
if (err) return console.error(err);
console.log(data.rows);Fetch one alert definition by its ID. See the get_alert API reference for parameter and response details.
let { err, data } = await api.getAlert({ id: 'load_avg_high' });
if (err) return console.error(err);
console.log(data.alert);Create a new alert definition. See the create_alert API reference for all supported alert properties.
let { err, data } = await api.createAlert({
title: 'High CPU Load',
expression: 'monitors.load_avg >= (cpu.cores + 1)',
message: 'CPU load average is too high: {{float(monitors.load_avg)}}',
monitor_id: 'load_avg',
enabled: true,
samples: 1
});
if (err) return console.error(err);
console.log(data.alert);Update selected properties on an existing alert. The request is shallow-merged, so properties you omit are left unchanged. See the update_alert API reference for details.
let { err } = await api.updateAlert({
id: 'load_avg_high',
title: 'High CPU Load',
expression: 'monitors.load_avg >= (cpu.cores + 1)'
});
if (err) return console.error(err);Test an alert expression and message against the current data from a server. See the test_alert API reference for response details.
let { err, data } = await api.testAlert({
server: 'SERVER_ID',
expression: 'monitors.load_avg >= (cpu.cores + 1)',
message: 'CPU load average is too high: {{float(monitors.load_avg)}}'
});
if (err) return console.error(err);
console.log(data.result, data.message);Permanently delete an alert definition by its ID. See the delete_alert API reference for privilege requirements.
let { err } = await api.deleteAlert({ id: 'load_avg_high' });
if (err) return console.error(err);Fetch all storage bucket definitions. Bucket data and file lists are not included. See the get_buckets API reference for response details.
let { err, data } = await api.getBuckets();
if (err) return console.error(err);
console.log(data.rows);Fetch one bucket definition, including its user-defined data and file list. See the get_bucket API reference for response details.
let { err, data } = await api.getBucket({ id: 'BUCKET_ID' });
if (err) return console.error(err);
console.log(data.bucket, data.data, data.files);Create a new storage bucket, optionally with initial user-defined data. Files must be uploaded separately. See the create_bucket API reference for all supported bucket properties.
let { err, data } = await api.createBucket({
title: 'Build Artifacts',
enabled: true,
data: {
build: 42,
status: 'ready'
}
});
if (err) return console.error(err);
console.log(data.bucket);Update selected properties on an existing bucket. The request is shallow-merged, so properties you omit are left unchanged. See the update_bucket API reference for details.
let { err } = await api.updateBucket({
id: 'BUCKET_ID',
title: 'Release Artifacts',
notes: 'Files from production releases'
});
if (err) return console.error(err);Permanently delete a bucket and all of its data and files. See the delete_bucket API reference for privilege requirements.
let { err } = await api.deleteBucket({ id: 'BUCKET_ID' });
if (err) return console.error(err);Shallow-merge user-defined data into an existing bucket. Set fetch to true to return the complete merged data object. See the write_bucket_data API reference for details.
let { err, data } = await api.writeBucketData({
id: 'BUCKET_ID',
fetch: true,
data: {
build: 43,
status: 'complete'
}
});
if (err) return console.error(err);
console.log(data.data);Upload one or more files into a bucket using a multipart request. Existing files with the same normalized filenames are replaced. See the upload_bucket_files API reference for details.
let { err } = await api.uploadBucketFiles(
{ id: 'BUCKET_ID' },
['report.csv', 'summary.txt']
);
if (err) return console.error(err);Permanently delete one file from a bucket using its normalized filename. See the delete_bucket_file API reference for details.
let { err } = await api.deleteBucketFile({
id: 'BUCKET_ID',
filename: 'report.csv'
});
if (err) return console.error(err);Permanently remove all files, all user-defined data, or both, while keeping the bucket itself. See the empty_bucket API reference for details.
let { err } = await api.emptyBucket({
id: 'BUCKET_ID',
files: true,
data: true
});
if (err) return console.error(err);Fetch all category definitions. This call does not require any parameters. See the get_categories API reference for response details.
let { err, data } = await api.getCategories();
if (err) return console.error(err);
console.log(data.rows);Fetch one category definition by its ID. See the get_category API reference for parameter and response details.
let { err, data } = await api.getCategory({ id: 'general' });
if (err) return console.error(err);
console.log(data.category);Create a new category for organizing events. See the create_category API reference for all supported category properties.
let { err, data } = await api.createCategory({
title: 'Maintenance',
enabled: true,
color: 'blue',
notes: 'Scheduled maintenance events',
limits: [],
actions: []
});
if (err) return console.error(err);
console.log(data.category);Update selected properties on an existing category. The request is shallow-merged, so properties you omit are left unchanged. See the update_category API reference for details.
let { err } = await api.updateCategory({
id: 'general',
title: 'General Jobs',
color: 'blue'
});
if (err) return console.error(err);Permanently delete a category by its ID. xyOps refuses the deletion if any events are still assigned to the category. See the delete_category API reference for privilege requirements.
let { err } = await api.deleteCategory({ id: 'CATEGORY_ID' });
if (err) return console.error(err);Fetch all channel definitions. See the get_channels API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getChannels();
if (err) return console.error(err);
console.log(data.rows);Fetch one channel definition by its ID. See the get_channel API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getChannel({ id: 'sev1' });
if (err) return console.error(err);
console.log(data.channel);Create a new channel. See the create_channel API reference for complete parameters, privileges, and response details.
let { err, data } = await api.createChannel({ title: 'On Call', enabled: true, users: ['admin'] });
if (err) return console.error(err);
console.log(data.channel);Update an existing channel. See the update_channel API reference for complete parameters, privileges, and response details.
let { err } = await api.updateChannel({ id: 'sev1', max_per_day: 5 });
if (err) return console.error(err);Permanently delete an existing channel. See the delete_channel API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteChannel({ id: 'CHANNEL_ID' });
if (err) return console.error(err);Fetch event definitions, optionally filtered by properties such as plugin or enabled state. See the get_events API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getEvents({ enabled: true });
if (err) return console.error(err);
console.log(data.rows);Fetch one event definition by its ID. See the get_event API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getEvent({ id: 'EVENT_ID' });
if (err) return console.error(err);
console.log(data.event);Fetch the revision history for an event. See the get_event_history API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getEventHistory({ id: 'EVENT_ID', limit: 20 });
if (err) return console.error(err);
console.log(data.rows);Create a new event. See the create_event API reference for complete parameters, privileges, and response details.
let { err, data } = await api.createEvent({
title: 'Nightly Task',
enabled: true,
category: 'general',
targets: ['main'],
algo: 'random',
plugin: 'shellplug',
params: {
script: "#!/bin/bash\n\necho 'Hi'\n"
}
});
if (err) return console.error(err);
console.log(data.event);Update an existing event. See the update_event API reference for complete parameters, privileges, and response details.
let { err } = await api.updateEvent({ id: 'EVENT_ID', enabled: false });
if (err) return console.error(err);Permanently delete an existing event. See the delete_event API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteEvent({ id: 'EVENT_ID' });
if (err) return console.error(err);Run an event on demand with optional parameter overrides. See the run_event API reference for complete parameters, privileges, and response details.
let { err, data } = await api.runEvent({ id: 'EVENT_ID', params: { mode: 'full' } });
if (err) return console.error(err);
console.log(data);Upload one or more general-purpose files for the user (API key in this case). See the upload_files API reference for complete parameters, privileges, and response details.
let { err, data } = await api.uploadFiles({}, ['report.csv']);
if (err) return console.error(err);
console.log(data);Delete a file attached to a job. See the delete_job_file API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteJobFile({ id: 'JOB_ID', path: 'files/jobs/JOB_ID/.../report.csv' });
if (err) return console.error(err);Fetch all server group definitions. See the get_groups API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getGroups();
if (err) return console.error(err);
console.log(data.rows);Fetch one server group definition by its ID. See the get_group API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getGroup({ id: 'main' });
if (err) return console.error(err);
console.log(data.group);Create a new group. See the create_group API reference for complete parameters, privileges, and response details.
let { err, data } = await api.createGroup({ title: 'Linux Servers', hostname_match: '^linux-' });
if (err) return console.error(err);
console.log(data.group);Update an existing group. See the update_group API reference for complete parameters, privileges, and response details.
let { err } = await api.updateGroup({ id: 'main', title: 'Production' });
if (err) return console.error(err);Permanently delete an existing server group. See the delete_group API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteGroup({ id: 'GROUP_ID' });
if (err) return console.error(err);Start or stop automatic snapshots for a server group. See the watch_group API reference for complete parameters, privileges, and response details.
let { err } = await api.watchGroup({ id: 'main', duration: 3600 });
if (err) return console.error(err);Create a snapshot containing the latest data for a server group. See the create_group_snapshot API reference for complete parameters, privileges, and response details.
let { err, data } = await api.createGroupSnapshot({ group: 'main' });
if (err) return console.error(err);
console.log(data);Fetch active jobs. See the get_active_jobs API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getActiveJobs({ limit: 50 });
if (err) return console.error(err);
console.log(data.rows);Fetch active job summary. See the get_active_job_summary API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getActiveJobSummary();
if (err) return console.error(err);
console.log(data.events);Fetch workflow job summary. See the get_workflow_job_summary API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getWorkflowJobSummary({ 'workflow.job': 'JOB_ID' });
if (err) return console.error(err);
console.log(data.nodes);Fetch job data for a specific job, which may be running or completed. See the get_job API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getJob({ id: 'JOB_ID' });
if (err) return console.error(err);
console.log(data.job);Fetch multiple jobs by their IDs. See the get_jobs API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getJobs({ ids: ['JOB_ID_1', 'JOB_ID_2'] });
if (err) return console.error(err);
console.log(data.jobs);Download a job log to a local file. See the get_job_log API reference for complete parameters, privileges, and response details.
let { err } = await api.getJobLog({ id: 'JOB_ID' }, { download: 'job.log' });
if (err) return console.error(err);Receive live job updates over Server-Sent Events. See the stream_job API reference for complete parameters, privileges, and response details.
let { err } = await api.streamJob({ id: 'JOB_ID' }, data => console.log(data));
if (err) return console.error(err);Update a live job while it is owned by the conductor. Standard jobs can only be updated before dispatch to xySat, while top-level workflow jobs can be updated as their sub-jobs run. The changes are saved with the completed job, but do not modify the source event. See the update_active_job API reference for complete field restrictions, privileges, and workflow validation details.
let { err } = await api.updateActiveJob({
id: 'JOB_ID',
title: 'Updated Before Dispatch',
targets: ['production']
});
if (err) return console.error(err);Update an existing job (administrator only). See the update_job API reference for complete parameters, privileges, and response details.
let { err } = await api.updateJob({ id: 'JOB_ID', label: 'Corrected Label' });
if (err) return console.error(err);Resume a suspended active job with optional parameters. See the resume_job API reference for complete parameters, privileges, and response details.
let { err } = await api.resumeJob({ id: 'JOB_ID', params: { approved: true } });
if (err) return console.error(err);Skip the current delay period for an active job. See the job_skip_delay API reference for complete parameters, privileges, and response details.
let { err } = await api.jobSkipDelay({ id: 'JOB_ID' });
if (err) return console.error(err);Replace the tags on a completed job. See the manage_job_tags API reference for complete parameters, privileges, and response details.
let { err } = await api.manageJobTags({ id: 'JOB_ID', tags: ['important'] });
if (err) return console.error(err);Replace the ticket associations on a completed job. The tickets array is a complete replacement, so include every ticket that should remain attached. See the manage_job_tickets API reference for complete parameters, privileges, and response details.
let { err } = await api.manageJobTickets({ id: 'JOB_ID', tickets: ['TICKET_ID'] });
if (err) return console.error(err);Abort a running job. See the abort_job API reference for complete parameters, privileges, and response details.
let { err } = await api.abortJob({ id: 'JOB_ID' });
if (err) return console.error(err);Permanently delete an existing completed job, including its log and files. See the delete_job API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteJob({ id: 'JOB_ID' });
if (err) return console.error(err);Remove all queued jobs for an event. See the flush_event_queue API reference for complete parameters, privileges, and response details.
let { err } = await api.flushEventQueue({ id: 'EVENT_ID' });
if (err) return console.error(err);Fetch all monitor definitions. See the get_monitors API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getMonitors();
if (err) return console.error(err);
console.log(data.rows);Fetch one monitor definition by its ID. See the get_monitor API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getMonitor({ id: 'cpu_usage' });
if (err) return console.error(err);
console.log(data.monitor);Create a new monitor. See the create_monitor API reference for complete parameters, privileges, and response details.
let { err, data } = await api.createMonitor({
title: 'CPU Usage',
source: 'cpu.currentLoad',
data_type: 'float'
});
if (err) return console.error(err);
console.log(data.monitor);Update an existing monitor. See the update_monitor API reference for complete parameters, privileges, and response details.
let { err } = await api.updateMonitor({ id: 'cpu_usage', display: true });
if (err) return console.error(err);Test a monitor configuration against current data from a server. See the test_monitor API reference for complete parameters, privileges, and response details.
let { err, data } = await api.testMonitor({ server: 'SERVER_ID', source: 'cpu.currentLoad', data_type: 'float' });
if (err) return console.error(err);
console.log(data);Permanently delete an existing monitor. See the delete_monitor API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteMonitor({ id: 'MONITOR_ID' });
if (err) return console.error(err);Fetch the latest QuickMon samples for one or more servers (last 60 seconds of real-time data). See the get_quickmon_data API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getQuickmonData({ server: 'SERVER_ID' });
if (err) return console.error(err);
console.log(data.servers);Fetch the latest monitoring timeline entries for a server. See the get_latest_monitor_data API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getLatestMonitorData({ server: 'SERVER_ID', sys: 'hourly', limit: 24 });
if (err) return console.error(err);
console.log(data.rows);Fetch historical monitoring timeline entries for a server. See the get_historical_monitor_data API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getHistoricalMonitorData({
server: 'SERVER_ID',
sys: 'hourly',
date: 1783873778,
limit: 24
});
if (err) return console.error(err);
console.log(data.rows);Fetch all plugins. See the get_plugins API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getPlugins();
if (err) return console.error(err);
console.log(data.rows);Fetch a single plugin by its ID. See the get_plugin API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getPlugin({ id: 'shellplug' });
if (err) return console.error(err);
console.log(data.plugin);Create a new plugin. See the create_plugin API reference for complete parameters, privileges, and response details.
let { err, data } = await api.createPlugin({
title: 'Custom Runner',
type: 'event',
command: 'node plugin.js',
enabled: true
});
if (err) return console.error(err);
console.log(data.plugin);Update an existing plugin. See the update_plugin API reference for complete parameters, privileges, and response details.
let { err } = await api.updatePlugin({ id: 'PLUGIN_ID', enabled: false });
if (err) return console.error(err);Permanently delete an existing plugin. See the delete_plugin API reference for complete parameters, privileges, and response details.
let { err } = await api.deletePlugin({ id: 'PLUGIN_ID' });
if (err) return console.error(err);Fetch all user roles. See the get_roles API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getRoles();
if (err) return console.error(err);
console.log(data.rows);Fetch single user role by its ID. See the get_role API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getRole({ id: 'all' });
if (err) return console.error(err);
console.log(data.role);Create a new role. See the create_role API reference for complete parameters, privileges, and response details.
let { err, data } = await api.createRole({ title: 'Operators', enabled: true, privileges: { run_jobs: true } });
if (err) return console.error(err);
console.log(data.role);Update an existing role. See the update_role API reference for complete parameters, privileges, and response details.
let { err } = await api.updateRole({ id: 'ROLE_ID', enabled: false });
if (err) return console.error(err);Permanently delete an existing role. See the delete_role API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteRole({ id: 'ROLE_ID' });
if (err) return console.error(err);Search completed jobs with custom criteria. See the search_jobs API reference for complete parameters, privileges, and response details.
let { err, data } = await api.searchJobs({ query: 'tags:_error', limit: 50 });
if (err) return console.error(err);
console.log(data.rows);Search servers with custom criteria. See the search_servers API reference for complete parameters, privileges, and response details.
let { err, data } = await api.searchServers({ query: 'os_platform:linux', limit: 50 });
if (err) return console.error(err);
console.log(data.rows);Search alerts with custom criteria. See the search_alerts API reference for complete parameters, privileges, and response details.
let { err, data } = await api.searchAlerts({ query: 'active:true', limit: 50 });
if (err) return console.error(err);
console.log(data.rows);Search snapshots with custom criteria. See the search_snapshots API reference for complete parameters, privileges, and response details.
let { err, data } = await api.searchSnapshots({ query: 'source:alert', limit: 50 });
if (err) return console.error(err);
console.log(data.rows);Search tickets with custom criteria. See the search_tickets API reference for complete parameters, privileges, and response details.
let { err, data } = await api.searchTickets({ query: 'status:open', limit: 50 });
if (err) return console.error(err);
console.log(data.rows);Search activity with custom criteria. See the search_activity API reference for complete parameters, privileges, and response details.
let { err, data } = await api.searchActivity({ query: 'action:job_error', limit: 50 });
if (err) return console.error(err);
console.log(data.rows);Search revision history. See the search_revision_history API reference for complete parameters, privileges, and response details.
let { err, data } = await api.searchRevisionHistory({ type: 'events', limit: 20 });
if (err) return console.error(err);
console.log(data.rows);Fetch daily snapshots from the system statistics history. See the search_stat_history API reference for complete parameters, privileges, and response details.
let { err, data } = await api.searchStatHistory({ limit: 30, current_day: true });
if (err) return console.error(err);
console.log(data.items);Export search results to a local CSV, TSV, or NDJSON file. See the bulk_search_export API reference for complete parameters, privileges, and response details.
let { err } = await api.bulkSearchExport(
{
index: 'jobs',
query: 'tags:_error',
columns: ['id', 'event', 'category', 'plugin', 'completed', 'code'],
sort_by: 'completed',
sort_dir: -1,
format: 'csv',
compress: true
},
{ download: 'error-jobs.csv.gz' }
);
if (err) return console.error(err);Search the xyOps Marketplace or fetch supporting product information. See the marketplace API reference for complete parameters, privileges, and response details.
Search for products:
let { err, data } = await api.marketplace({ query: 'backup', limit: 20 });
if (err) return console.error(err);
console.log(data.rows);Fetch the unique values available for Marketplace filters:
let { err, data } = await api.marketplace({ fields: true });
if (err) return console.error(err);
console.log(data.fields);Fetch a product README in GitHub Flavored Markdown:
let { err, data } = await api.marketplace({
id: 'pixlcore/xyplug-weather',
readme: true
});
if (err) return console.error(err);
console.log(data.text);Fetch a product's xyOps Portable Data file:
let { err, data } = await api.marketplace({
id: 'pixlcore/xyplug-weather',
data: true
});
if (err) return console.error(err);
console.log(data.data);Fetch all secret metadata (does not include encrypted variables). See the get_secrets API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getSecrets();
if (err) return console.error(err);
console.log(data.rows);Fetch secret metadata for a single secret by its ID (does not include encrypted variables). See the get_secret API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getSecret({ id: 'SECRET_ID' });
if (err) return console.error(err);
console.log(data.secret);Decrypt and return the variables stored in a secret. See the decrypt_secret API reference for complete parameters, privileges, and response details. Administrator only.
let { err, data } = await api.decryptSecret({ id: 'SECRET_ID' });
if (err) return console.error(err);
// Display the field names without exposing their decrypted values.
console.log(data.fields.map(field => field.name));Create a new secret. See the create_secret API reference for complete parameters, privileges, and response details. Administrator only.
let { err, data } = await api.createSecret({
title: 'Database',
enabled: true,
fields: [
{ name: 'DB_HOST', value: 'db.example.com' }
]
});
if (err) return console.error(err);
console.log(data.secret);Update an existing secret. See the update_secret API reference for complete parameters, privileges, and response details. Administrator only.
let { err } = await api.updateSecret({ id: 'SECRET_ID', enabled: false });
if (err) return console.error(err);Permanently delete an existing secret and its encrypted data. See the delete_secret API reference for complete parameters, privileges, and response details. Administrator only.
let { err } = await api.deleteSecret({ id: 'SECRET_ID' });
if (err) return console.error(err);Treat decrypted secret data as sensitive. Avoid logging it or including it in job output.
Fetch server summaries. See the get_server_summaries API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getServerSummaries();
if (err) return console.error(err);
console.log(data);Fetch active servers. See the get_active_servers API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getActiveServers();
if (err) return console.error(err);
console.log(data);Fetch one active server by its ID. See the get_active_server API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getActiveServer({ id: 'SERVER_ID' });
if (err) return console.error(err);
console.log(data.server);Fetch one server by its ID, including its latest monitoring data. See the get_server API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getServer({ id: 'SERVER_ID' });
if (err) return console.error(err);
console.log(data.server);Update an existing server. See the update_server API reference for complete parameters, privileges, and response details.
let { err } = await api.updateServer({ id: 'SERVER_ID', title: 'Build Agent' });
if (err) return console.error(err);Shallow-merge user data into a server record. See the update_server_data API reference for complete parameters, privileges, and response details.
let { err } = await api.updateServerData({ id: 'SERVER_ID', data: { region: 'west' } });
if (err) return console.error(err);Permanently delete an existing server. See the delete_server API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteServer({ id: 'SERVER_ID', history: true });
if (err) return console.error(err);Start or stop automatic snapshots for a server. See the watch_server API reference for complete parameters, privileges, and response details.
let { err } = await api.watchServer({ id: 'SERVER_ID', duration: 3600 });
if (err) return console.error(err);Create a snapshot containing the latest data for a server. See the create_snapshot API reference for complete parameters, privileges, and response details.
let { err, data } = await api.createSnapshot({ server: 'SERVER_ID' });
if (err) return console.error(err);
console.log(data);Permanently delete an existing snapshot. See the delete_snapshot API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteSnapshot({ id: 'SNAPSHOT_ID' });
if (err) return console.error(err);Fetch all tag definitions. See the get_tags API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getTags();
if (err) return console.error(err);
console.log(data.rows);Fetch single tag definition by its ID. See the get_tag API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getTag({ id: 'important' });
if (err) return console.error(err);
console.log(data.tag);Create a new tag. See the create_tag API reference for complete parameters, privileges, and response details.
let { err, data } = await api.createTag({ title: 'Important', notes: 'Needs attention' });
if (err) return console.error(err);
console.log(data.tag);Update an existing tag. See the update_tag API reference for complete parameters, privileges, and response details.
let { err } = await api.updateTag({ id: 'important', title: 'High Priority' });
if (err) return console.error(err);Permanently delete an existing tag. See the delete_tag API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteTag({ id: 'TAG_ID' });
if (err) return console.error(err);Fetch a single ticket by its ID. See the get_ticket API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getTicket({ id: 'TICKET_ID' });
if (err) return console.error(err);
console.log(data.ticket);Fetch multiple tickets by their IDs. See the get_tickets API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getTickets({ ids: ['TICKET_ID_1', 'TICKET_ID_2'] });
if (err) return console.error(err);
console.log(data.tickets);Create a new ticket. See the create_ticket API reference for complete parameters, privileges, and response details.
let { err, data } = await api.createTicket({
subject: 'Backup failed',
type: 'issue',
status: 'open',
body: 'See job logs.'
});
if (err) return console.error(err);
console.log(data.ticket);Update an existing ticket. See the update_ticket API reference for complete parameters, privileges, and response details.
let { err } = await api.updateTicket({ id: 'TICKET_ID', status: 'closed' });
if (err) return console.error(err);Add a change, such as a comment, to a ticket. See the add_ticket_change API reference for complete parameters, privileges, and response details.
let { err, data } = await api.addTicketChange({ id: 'TICKET_ID', change: { type: 'comment', body: 'Investigating.' } });
if (err) return console.error(err);
console.log(data);Edit or delete an existing ticket change. See the update_ticket_change API reference for complete parameters, privileges, and response details.
let { err, data } = await api.updateTicketChange({
id: 'TICKET_ID',
change_id: 'CHANGE_ID',
change: { body: 'Updated.' }
});
if (err) return console.error(err);
console.log(data);Upload one or more files and attach them to a ticket. See the upload_user_ticket_files API reference for complete parameters, privileges, and response details.
let { err, data } = await api.uploadUserTicketFiles({ ticket: 'TICKET_ID', save: true }, ['job-log.txt']);
if (err) return console.error(err);
console.log(data);Permanently delete a file attached to a ticket. See the delete_ticket_file API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteTicketFile({ id: 'TICKET_ID', path: 'files/...' });
if (err) return console.error(err);Permanently delete an existing ticket. See the delete_ticket API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteTicket({ id: 'TICKET_ID' });
if (err) return console.error(err);Fetch all web hooks. See the get_web_hooks API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getWebHooks();
if (err) return console.error(err);
console.log(data.rows);Fetch single web hook by its ID. See the get_web_hook API reference for complete parameters, privileges, and response details.
let { err, data } = await api.getWebHook({ id: 'HOOK_ID' });
if (err) return console.error(err);
console.log(data.web_hook);Create a new web hook. See the create_web_hook API reference for complete parameters, privileges, and response details.
let { err, data } = await api.createWebHook({
title: 'Deploy Hook',
enabled: true,
url: 'https://example.com/hook',
method: 'POST'
});
if (err) return console.error(err);
console.log(data.web_hook);Update an existing web hook. See the update_web_hook API reference for complete parameters, privileges, and response details.
let { err } = await api.updateWebHook({ id: 'HOOK_ID', timeout: 60 });
if (err) return console.error(err);Permanently delete an existing web hook. See the delete_web_hook API reference for complete parameters, privileges, and response details.
let { err } = await api.deleteWebHook({ id: 'HOOK_ID' });
if (err) return console.error(err);Send a custom email with optional file attachments. See the send_email API reference for complete parameters, privileges, and response details.
let { err, data } = await api.sendEmail({ to: 'ops@example.com', subject: 'Job Report', body: 'The job completed.' });
if (err) return console.error(err);
console.log(data.details);To attach files to an email:
await api.sendEmail(
{
to: 'ops@example.com',
subject: 'Job Report',
body: 'The report is attached.'
},
['report.csv']
);MIT