@pixlcore/xyops-sdk
v1.0.4
Published
An API client and job runtime helper library for xyOps.
Readme
- xyOps SDK for Node.js
- Installation
- Job Runtime SDK
- Complete Job Example
- API Client
- API Catalog
- License
xyOps SDK for Node.js
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.
Installation
npm install @pixlcore/xyops-sdkJob Runtime SDK
The 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.
Basic Job
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.
Reading Input
job.read
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.
job.getParams
Returns all Event Plugin parameters.
let params = job.getParams();
console.log(params);job.getParam
Returns one Event Plugin parameter by its name.
let mode = job.getParam('mode');job.getFiles
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.
job.getData
Returns all input.data, or one top-level value when you provide a key.
let data = job.getData();
let customerId = job.getData('customer_id');job.getWorkflowData
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.
job.getServerData
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.
job.getSecrets
Returns all assigned Secret Vault variables.
let secrets = job.getSecrets();For more details, see Secrets.
job.getSecret
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.
Encrypting and Decrypting Values
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.
job.encryptValue
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.
job.decryptValue
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.
Sending Output Data
job.addData
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.
job.addWorkflowData
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.
job.addServerData
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.
Attaching Files
job.addFile
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.
job.addFiles
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.
Tags and Actions
job.addTag
Appends one Tag ID to the current job.
job.addTag('important');For more details, see Job Tags.
job.addTags
Appends multiple Tag IDs to the current job.
job.addTags(['nightly', 'backup']);For more details, see Job Tags.
job.addAction
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.
job.addActions
Appends multiple job action objects. See Action Types for all supported properties.
job.addActions([
{ condition: 'complete', type: 'email', email: '[email protected]', users: [], enabled: true }
]);For more details, see Job Actions.
Custom Job Content
These helpers add a custom report to the Job Details page. caption is optional in every call.
job.setTable
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.
job.setHTML
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.
job.setText
Displays plain text while preserving whitespace.
job.setText('Command Output', 'Processed: 125\nFailed: 0');For more details, see Custom Content.
job.setMarkdown
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.
Live Updates
job.setProgress
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);job.setStatus
Sets the temporary status line shown while the job is running.
job.setStatus('Processing file 34 of 68...');job.setLabel
Sets the label displayed beside the Job ID in completed job history.
job.setLabel('Nightly Customer Import');Job Logging
job.logger
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.
Performance Metrics
job.perf
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.
Completing the Job
job.finalSuccess
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');job.finalError
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.
Low-Level Output
job.write
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.
Complete Job Example
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.
API Client
Configuration
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.
Making a Request
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.
Responses and Errors
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);
}Request Options
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.
Downloading Files
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.
Uploading Files
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.
Streaming a Live Job
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.
API Catalog
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');Alerts
getAlerts
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);getAlert
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);createAlert
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);updateAlert
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);testAlert
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);deleteAlert
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);Buckets
getBuckets
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);getBucket
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);createBucket
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);updateBucket
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);deleteBucket
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);writeBucketData
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);uploadBucketFiles
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);deleteBucketFile
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);emptyBucket
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);Categories
getCategories
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);getCategory
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);createCategory
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);updateCategory
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);deleteCategory
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);Channels
getChannels
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);getChannel
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);createChannel
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);updateChannel
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);deleteChannel
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);Events
getEvents
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);getEvent
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);getEventHistory
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);createEvent
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);updateEvent
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);deleteEvent
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);runEvent
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);Files
uploadFiles
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);deleteJobFile
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);Groups
getGroups
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);getGroup
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);createGroup
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);updateGroup
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);deleteGroup
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);watchGroup
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);createGroupSnapshot
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);Jobs
getActiveJobs
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);getActiveJobSummary
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);getWorkflowJobSummary
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);getJob
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);getJobs
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);getJobLog
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);streamJob
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);updateActiveJob
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);updateJob
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);resumeJob
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);jobSkipDelay
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);manageJobTags
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);manageJobTickets
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);abortJob
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);deleteJob
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);flushEventQueue
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);Monitors
getMonitors
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);getMonitor
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);createMonitor
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);updateMonitor
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);testMonitor
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);deleteMonitor
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);getQuickmonData
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);getLatestMonitorData
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);getHistoricalMonitorData
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);Plugins
getPlugins
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);getPlugin
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);createPlugin
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);updatePlugin
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);deletePlugin
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);Roles
getRoles
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);getRole
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);createRole
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);updateRole
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);deleteRole
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
searchJobs
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);searchServers
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);searchAlerts
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);searchSnapshots
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);searchTickets
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);searchActivity
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);searchRevisionHistory
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);searchStatHistory
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);bulkSearchExport
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);Marketplace
marketplace
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);Secrets
getSecrets
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);getSecret
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);decryptSecret
Decrypt and return the variables stored in a secret. See the [decrypt_secret](https://docs.xyops.io/
