Node.js SDK
Official Node.js/TypeScript SDK for LOX Backup API. Full TypeScript support with ESM and CommonJS builds.
v0.1.0Updated 2026-01-01
Installation
npm install @lox-backup/sdk
Requirements
- Node.js 18 or higher
- TypeScript 4.7+ (optional, for type definitions)
Quick Start
ESM (Recommended)
import { LoxClient } from '@lox-backup/sdk';
const client = new LoxClient({ apiKey: 'your-api-key' });
// Upload a backup
const backup = await client.backups.upload({
filePath: 'backup.tar.gz',
name: 'my-backup',
tags: ['production', 'database'],
retentionDays: 30
});
console.log(`Backup created: ${backup.uuid}`);
console.log(`Status: ${backup.status}`);CommonJS
const { LoxClient } = require('@lox-backup/sdk');
const client = new LoxClient({ apiKey: 'your-api-key' });
async function main() {
const backup = await client.backups.upload({
filePath: 'backup.tar.gz',
name: 'my-backup'
});
console.log(`Backup created: ${backup.uuid}`);
}
main();Configuration
Client Options
import { LoxClient } from '@lox-backup/sdk';
const client = new LoxClient({
apiKey: 'your-api-key', // Required: Your LOX API key
baseUrl: 'https://backlox.com/api', // Optional: API base URL
timeout: 300000, // Optional: Request timeout in ms (default: 5min)
maxRetries: 3, // Optional: Max retry attempts (default: 3)
});Environment Variables
# .env LOX_API_KEY=your-api-key LOX_API_URL=https://backlox.com/api
import { LoxClient } from '@lox-backup/sdk';
// Reads from process.env.LOX_API_KEY
const client = new LoxClient();Backups API
Upload Backup
// Simple upload
const backup = await client.backups.upload({
filePath: 'backup.tar.gz'
});
// Upload with all options
const backup = await client.backups.upload({
filePath: 'backup.tar.gz',
name: 'production-db-2024-01-15',
description: 'Daily production database backup',
tags: ['production', 'database', 'mysql'],
retentionDays: 90,
waitForCompletion: true, // Wait for processing
timeout: 3600000 // Max wait time in ms
});
console.log(`UUID: ${backup.uuid}`);
console.log(`Status: ${backup.status}`);
console.log(`Size: ${backup.sizeBytes} bytes`);List Backups
// List all backups
const backups = await client.backups.list();
for (const backup of backups) {
console.log(`${backup.name}: ${backup.status}`);
}
// Filter by status
const completed = await client.backups.list({
status: 'completed'
});
// Filter by tags
const production = await client.backups.list({
tags: 'production'
});
// Search by name
const results = await client.backups.list({
search: 'database'
});
// Pagination
const page1 = await client.backups.list({ limit: 10, offset: 0 });
const page2 = await client.backups.list({ limit: 10, offset: 10 });Get Backup
const backup = await client.backups.get('550e8400-e29b-41d4-a716-446655440000');
console.log(`Name: ${backup.name}`);
console.log(`Status: ${backup.status}`);
console.log(`Size: ${backup.sizeBytes}`);
console.log(`Created: ${backup.createdAt}`);
console.log(`Tags: ${backup.tags.join(', ')}`);Restore/Download Backup
// Request restore (generates download URL)
const restore = await client.backups.restore(
'550e8400-e29b-41d4-a716-446655440000'
);
console.log(`Download URL: ${restore.downloadUrl}`);
console.log(`Expires: ${restore.expiresAt}`);
// Download using the URL
import { createWriteStream } from 'fs';
import { pipeline } from 'stream/promises';
const response = await fetch(restore.downloadUrl);
await pipeline(
response.body,
createWriteStream('restored-backup.tar.gz')
);Delete Backup
await client.backups.delete('550e8400-e29b-41d4-a716-446655440000');
console.log('Backup deleted');Wait for Completion
// Upload without waiting
const backup = await client.backups.upload({
filePath: 'backup.tar.gz',
waitForCompletion: false
});
console.log(`Upload started: ${backup.uuid}`);
// Wait for completion later
const completed = await client.backups.waitForCompletion(backup.uuid, {
timeout: 3600000, // Max wait time in ms
pollInterval: 5000 // Check every 5 seconds
});
console.log(`Backup completed: ${completed.status}`);Tenant API
Get Current Tenant
const tenant = await client.tenant.getCurrent();
console.log(`Name: ${tenant.name}`);
console.log(`Email: ${tenant.email}`);
console.log(`Created: ${tenant.createdAt}`);Get Storage Quota
const quota = await client.tenant.getQuota();
console.log(`Used: ${quota.usedBytes} bytes`);
console.log(`Quota: ${quota.quotaBytes} bytes`);
console.log(`Usage: ${quota.usagePercentage}%`);
console.log(`Unlimited: ${quota.unlimited}`);
// Check if storage is available
const hasSpace = await client.tenant.hasAvailableStorage(100 * 1024 * 1024);
if (hasSpace) {
console.log('100MB available');
} else {
console.log('Not enough storage');
}Storage API
// List storage targets
const targets = await client.storage.list();
for (const target of targets) {
console.log(`${target.name}: ${target.provider} - ${target.status}`);
}
// Get health summary
const health = await client.storage.getHealthSummary();
console.log(`Healthy: ${health.healthyCount}`);
console.log(`Degraded: ${health.degradedCount}`);
console.log(`Offline: ${health.offlineCount}`);Notification Channels API
Manage notification channels for backup alerts via webhook, Slack, Discord, and more.
Create Channel
import { LoxClient, ChannelType, NotificationEvent } from '@lox-backup/sdk';
const client = new LoxClient();
// Create a webhook channel
const webhook = await client.notificationChannels.create({
name: 'Production Alerts',
channelType: ChannelType.WEBHOOK,
config: { url: 'https://example.com/webhook' },
events: [NotificationEvent.BACKUP_COMPLETED, NotificationEvent.BACKUP_FAILED],
});
console.log(`Webhook secret: ${webhook.config.secret}`);
// Create a Slack channel
const slack = await client.notificationChannels.create({
name: 'Slack Alerts',
channelType: ChannelType.SLACK,
config: {
webhookUrl: 'https://hooks.slack.com/services/...',
channel: '#backup-alerts',
},
});
// Create a Discord channel
const discord = await client.notificationChannels.create({
name: 'Discord Alerts',
channelType: ChannelType.DISCORD,
config: {
webhookUrl: 'https://discord.com/api/webhooks/...',
username: 'LOX Backup Bot',
},
});List and Manage Channels
// List all channels
const channels = await client.notificationChannels.list();
for (const channel of channels) {
console.log(`${channel.name} (${channel.channelType}): ${channel.isHealthy ? 'healthy' : 'unhealthy'}`);
}
// Get channel summary
const summary = await client.notificationChannels.getSummary();
console.log(`Total: ${summary.totalChannels}, Unhealthy: ${summary.unhealthyChannels}`);
// Test a channel
const result = await client.notificationChannels.test(channel.uuid);
if (result.status === 'success') {
console.log('Channel is working!');
}
// Enable/disable channel
await client.notificationChannels.disable(channel.uuid);
await client.notificationChannels.enable(channel.uuid);
// Update channel
const updated = await client.notificationChannels.update(channel.uuid, {
name: 'New Name',
regenerateSecret: true, // For webhook channels
});
// Delete channel
await client.notificationChannels.delete(channel.uuid);Backup Agents API
Manage backup agents for Veeam-style machine backup with agent registration and monitoring.
Register Agent
import { LoxClient, OSType } from '@lox-backup/sdk';
const client = new LoxClient();
// Register a new agent
const registration = await client.agents.register({
hostname: 'server-01',
osType: OSType.LINUX,
displayName: 'Production Server 01',
capabilities: ['file', 'block'],
hardwareInfo: {
cpuCores: 8,
memoryGb: 32,
disks: [{ path: '/', sizeGb: 500 }],
},
});
console.log(`Agent UUID: ${registration.uuid}`);
console.log(`Registration Token: ${registration.registrationToken}`);
// Get install command
const cmd = await client.agents.getInstallCommand(registration.uuid);
console.log(cmd.recommendedCommand);List and Manage Agents
// List all agents
const agents = await client.agents.list();
for (const agent of agents) {
console.log(`${agent.hostname} (${agent.osType}): ${agent.status}`);
}
// Get agent summary
const summary = await client.agents.getSummary();
console.log(`Online: ${summary.onlineAgents}, Offline: ${summary.offlineAgents}`);
console.log(`Total data protected: ${summary.totalDataProtectedBytes} bytes`);
// Get specific agent
const agent = await client.agents.get('agent-uuid');
console.log(`Success rate: ${agent.successRate}%`);
console.log(`Total backups: ${agent.totalBackups}`);
// Update agent
const updated = await client.agents.update('agent-uuid', {
displayName: 'New Display Name',
});
// Enable/disable agent
await client.agents.disable('agent-uuid');
await client.agents.enable('agent-uuid');
// Regenerate token
const newReg = await client.agents.regenerateToken('agent-uuid');
console.log(`New token: ${newReg.registrationToken}`);
// Delete agent
await client.agents.delete('agent-uuid');Backup Jobs API
Create and manage scheduled backup jobs for automated machine backups.
Create Job
import { LoxClient, JobType, BackupMode } from '@lox-backup/sdk';
const client = new LoxClient();
// Create a file backup job
const job = await client.jobs.create({
agentUuid: 'agent-uuid',
name: 'Daily Full Backup',
jobType: JobType.FILE,
sources: [
{ type: 'path', value: '/home' },
{ type: 'path', value: '/var/www' },
],
exclusions: ['*.log', '*.tmp', 'node_modules'],
backupMode: BackupMode.FULL,
scheduleCron: '0 2 * * *', // Daily at 2 AM
scheduleEnabled: true,
retentionPolicy: {
daily: 7,
weekly: 4,
monthly: 12,
},
compression: 'zstd',
compressionLevel: 6,
encryptionEnabled: true,
verifyAfterBackup: true,
});
console.log(`Job created: ${job.uuid}`);Run and Manage Jobs
// List all jobs
const jobs = await client.jobs.list();
// Filter by agent
const agentJobs = await client.jobs.list('agent-uuid');
// Run job immediately
const result = await client.jobs.run(job.uuid, 'full');
console.log(`Backup started: ${result.backupUuid}`);
// List job's backups
const backups = await client.jobs.listBackups(job.uuid);
for (const backup of backups) {
console.log(`${backup.uuid}: ${backup.status} - ${backup.sizeBytes} bytes`);
}
// Update job
const updated = await client.jobs.update(job.uuid, {
name: 'New Job Name',
scheduleCron: '0 3 * * *', // Change to 3 AM
});
// Enable/disable job
await client.jobs.disable(job.uuid);
await client.jobs.enable(job.uuid);
// Delete job and all its backups
await client.jobs.delete(job.uuid);Machine Backups API
Manage machine backup restore points created by backup jobs.
// List all machine backups
const backups = await client.machineBackups.list();
// Filter by status
const completed = await client.machineBackups.list({ status: 'completed' });
// Get specific backup
const backup = await client.machineBackups.get('backup-uuid');
console.log(`Type: ${backup.backupType}`);
console.log(`Size: ${backup.sizeBytes} bytes`);
console.log(`Files: ${backup.filesCount}`);
// Create restore job
const restore = await client.machineBackups.restore('backup-uuid', {
restoreType: 'full', // 'full' or 'selective'
targetType: 'original', // 'original' or 'alternate'
overwriteExisting: false,
preservePermissions: true,
// For alternate restore:
// targetAgentUuid: 'other-agent-uuid',
// targetPath: '/restore/path',
// For selective restore:
// selectedItems: ['/home/user/documents', '/var/www'],
});
console.log(`Restore job: ${restore.uuid}`);
console.log(`Status: ${restore.status}`);
// Delete backup
await client.machineBackups.delete('backup-uuid');Error Handling
import { LoxClient } from '@lox-backup/sdk';
import {
LoxError,
AuthenticationError,
NotFoundError,
QuotaExceededError,
ValidationError,
RateLimitError,
TimeoutError,
} from '@lox-backup/sdk/errors';
const client = new LoxClient();
try {
const backup = await client.backups.upload({
filePath: 'backup.tar.gz'
});
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Invalid API key');
} else if (error instanceof QuotaExceededError) {
console.error('Storage quota exceeded');
} else if (error instanceof NotFoundError) {
console.error('Resource not found');
} else if (error instanceof ValidationError) {
console.error(`Validation error: ${error.message}`);
} else if (error instanceof RateLimitError) {
console.error('Rate limited, try again later');
} else if (error instanceof TimeoutError) {
console.error('Request timed out');
} else if (error instanceof LoxError) {
console.error(`API error: ${error.message}`);
} else {
throw error;
}
}TypeScript Types
The SDK exports all TypeScript types for full type safety:
import type {
Backup,
BackupStatus,
BackupListParams,
UploadOptions,
Tenant,
TenantQuota,
StorageTarget,
StorageHealth,
RestoreResult,
} from '@lox-backup/sdk';
// Type-safe backup handling
function processBackup(backup: Backup): void {
if (backup.status === 'completed') {
console.log(`Ready: ${backup.name}`);
}
}
// Type-safe options
const options: UploadOptions = {
filePath: 'backup.tar.gz',
name: 'typed-backup',
tags: ['typescript'],
retentionDays: 30,
};Backup Type
| Field | Type | Description |
|---|---|---|
| uuid | string | Unique identifier |
| name | string | Backup name |
| status | BackupStatus | 'pending' | 'validating' | 'scanning' | 'distributing' | 'completed' | 'failed' | 'quarantine' |
| sizeBytes | number | File size in bytes |
| checksumSha256 | string | SHA-256 hash |
| tags | string[] | Tags for organization |
| retentionDays | number | Days until expiration |
| createdAt | Date | Creation timestamp |
| expiresAt | Date | Expiration timestamp |
Complete Example
#!/usr/bin/env node
/**
* LOX Backup - Database Backup Script (TypeScript)
*/
import { LoxClient } from '@lox-backup/sdk';
import { QuotaExceededError } from '@lox-backup/sdk/errors';
import { execSync } from 'child_process';
import { mkdtempSync, rmSync } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
async function backupDatabase(): Promise<boolean> {
const client = new LoxClient();
// Check storage quota
const quota = await client.tenant.getQuota();
console.log(`Storage used: ${quota.usagePercentage}%`);
// Create temp directory
const tmpDir = mkdtempSync(join(tmpdir(), 'backup-'));
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const dumpFile = join(tmpDir, `db_${timestamp}.sql.gz`);
try {
// Dump PostgreSQL database
execSync(`pg_dump mydb | gzip > ${dumpFile}`, { stdio: 'inherit' });
// Upload to LOX
const backup = await client.backups.upload({
filePath: dumpFile,
name: `postgres-mydb-${timestamp}`,
tags: ['postgres', 'production', 'automated'],
retentionDays: 30,
waitForCompletion: true
});
console.log('Backup complete!');
console.log(` UUID: ${backup.uuid}`);
console.log(` Size: ${backup.sizeBytes.toLocaleString()} bytes`);
console.log(` Expires: ${backup.expiresAt}`);
return true;
} catch (error) {
if (error instanceof QuotaExceededError) {
console.error('ERROR: Storage quota exceeded!');
console.error('Please delete old backups or upgrade your plan.');
return false;
}
throw error;
} finally {
// Cleanup
rmSync(tmpDir, { recursive: true });
}
}
backupDatabase().catch(console.error);