The HyperSDK REST API provides programmatic access to manage VM migration jobs, schedules, webhooks, and more. All endpoints return JSON responses and use standard HTTP methods and status codes.
Base URL: http://localhost:8080 (configurable)
Authentication: Currently no authentication (add in production)
Health check endpoint.
Response:
{
"status": "ok"
}
Get current daemon status and statistics.
Response:
{
"total_jobs": 42,
"running_jobs": 3,
"completed_jobs": 35,
"failed_jobs": 4,
"worker_count": 10,
"active_workers": 3
}
Submit a new migration job.
Request Body:
{
"vm_path": "Datacenter/vm/production/web-server-1",
"source": {
"type": "vsphere",
"vcenter_url": "vcenter.example.com",
"username": "admin@vsphere.local",
"password": "password",
"datacenter": "Datacenter"
},
"destination": {
"type": "kvm",
"libvirt_uri": "qemu+ssh://user@host/system"
},
"options": {
"conversion_method": "vddk",
"network_mapping": {
"VM Network": "br0"
}
}
}
Response:
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"message": "job submitted successfully"
}
Status Codes:
201 Created - Job submitted successfully400 Bad Request - Invalid request body500 Internal Server Error - Failed to submit jobQuery jobs with filters.
Request Body:
{
"all": true,
"status": "running",
"limit": 10
}
Response:
{
"jobs": [
{
"definition": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"vm_path": "Datacenter/vm/production/web-server-1"
},
"status": "running",
"progress": {
"stage": "conversion",
"percent_complete": 45,
"current_bytes": 21474836480,
"total_bytes": 53687091200
},
"started_at": "2026-01-17T10:30:00Z",
"error": null
}
],
"total": 1
}
Status Codes:
200 OK - Query successful400 Bad Request - Invalid query parametersGet specific job details.
URL Parameters:
id - Job ID (UUID)Response:
{
"definition": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"vm_path": "Datacenter/vm/production/web-server-1"
},
"status": "running",
"progress": {
"stage": "conversion",
"percent_complete": 45
}
}
Status Codes:
200 OK - Job found404 Not Found - Job not foundCancel jobs by ID or status.
Request Body:
{
"job_ids": ["550e8400-e29b-41d4-a716-446655440000"],
"status": "running"
}
Response:
{
"message": "jobs cancelled successfully",
"count": 1
}
Status Codes:
200 OK - Jobs cancelled400 Bad Request - Invalid requestList all scheduled jobs.
Response:
{
"schedules": [
{
"id": "daily-backup",
"name": "Daily VM Backup",
"schedule": "0 2 * * *",
"enabled": true,
"job_template": {
"vm_path": "Datacenter/vm/production/*",
"source": {...},
"destination": {...}
},
"last_run": "2026-01-17T02:00:00Z",
"next_run": "2026-01-18T02:00:00Z",
"run_count": 30
}
],
"total": 1,
"timestamp": "2026-01-17T12:00:00Z"
}
Create a new scheduled job.
Request Body:
{
"id": "daily-backup",
"name": "Daily VM Backup",
"description": "Backup production VMs every night",
"schedule": "0 2 * * *",
"enabled": true,
"job_template": {
"vm_path": "Datacenter/vm/production/web-server-1",
"source": {...},
"destination": {...}
}
}
Schedule Format: Cron expression (minute hour day month weekday)
0 2 * * * - Every day at 2:00 AM*/15 * * * * - Every 15 minutes0 0 * * 0 - Every Sunday at midnightResponse:
{
"message": "schedule created successfully",
"schedule": {...}
}
Status Codes:
201 Created - Schedule created400 Bad Request - Invalid schedule503 Service Unavailable - Scheduler not enabledGet specific schedule.
Response:
{
"id": "daily-backup",
"name": "Daily VM Backup",
"schedule": "0 2 * * *",
"enabled": true,
"last_run": "2026-01-17T02:00:00Z",
"next_run": "2026-01-18T02:00:00Z"
}
Update schedule.
Request Body:
{
"name": "Updated Name",
"schedule": "0 3 * * *",
"enabled": true
}
Response:
{
"message": "schedule updated successfully"
}
Delete schedule.
Response:
{
"message": "schedule deleted successfully"
}
Enable schedule.
Response:
{
"message": "schedule enabled successfully"
}
Disable schedule.
Response:
{
"message": "schedule disabled successfully"
}
Manually trigger schedule execution.
Response:
{
"message": "schedule triggered successfully"
}
Get schedule statistics.
Response:
{
"total_schedules": 5,
"enabled_schedules": 3,
"disabled_schedules": 2,
"total_runs": 150,
"successful_runs": 145,
"failed_runs": 5
}
List all configured webhooks.
Response:
{
"webhooks": [
{
"url": "https://hooks.example.com/notify",
"events": ["job.completed", "job.failed"],
"enabled": true,
"timeout": 30,
"retry_count": 3
}
],
"total": 1,
"timestamp": "2026-01-17T12:00:00Z"
}
Add new webhook.
Request Body:
{
"url": "https://hooks.example.com/notify",
"events": ["job.completed", "job.failed"],
"enabled": true,
"timeout": 30,
"retry_count": 3,
"headers": {
"Authorization": "Bearer token123"
}
}
Available Events:
job.submitted - Job submittedjob.started - Job startedjob.completed - Job completed successfullyjob.failed - Job failedjob.progress - Job progress updateschedule.triggered - Schedule triggeredschedule.completed - Scheduled job completedResponse:
{
"message": "webhook added successfully",
"webhook": {...}
}
Delete webhook by index.
URL Parameters:
index - Webhook index (0-based)Response:
{
"message": "webhook deleted successfully"
}
Test webhook delivery.
Request Body:
{
"url": "https://hooks.example.com/notify",
"event": "test"
}
Response:
{
"message": "test webhook sent"
}
List VMs from vCenter.
Query Parameters:
vcenter_url - vCenter URLusername - vCenter usernamepassword - vCenter passworddatacenter - Datacenter name (optional)Response:
{
"vms": [
{
"name": "web-server-1",
"path": "Datacenter/vm/production/web-server-1",
"power_state": "poweredOn",
"num_cpu": 4,
"memory_mb": 8192,
"storage": 107374182400,
"guest_os": "Ubuntu Linux (64-bit)",
"ip_address": "192.168.1.10"
}
],
"total": 1
}
Get detailed VM information.
Query Parameters:
vcenter_url - vCenter URLusername - vCenter usernamepassword - vCenter passwordvm_path - VM inventory pathResponse:
{
"name": "web-server-1",
"path": "Datacenter/vm/production/web-server-1",
"uuid": "42329208-8c5a-3254-1234-567890abcdef",
"power_state": "poweredOn",
"hardware": {
"num_cpu": 4,
"memory_mb": 8192,
"num_virtual_disks": 2
},
"disks": [
{
"label": "Hard disk 1",
"capacity_kb": 104857600,
"file_path": "[datastore1] web-server-1/web-server-1.vmdk"
}
]
}
Gracefully shutdown VM.
Request Body:
{
"vcenter_url": "vcenter.example.com",
"username": "admin@vsphere.local",
"password": "password",
"vm_path": "Datacenter/vm/production/web-server-1"
}
Response:
{
"message": "VM shutdown initiated"
}
Force power off VM.
Request Body: Same as shutdown
Response:
{
"message": "VM powered off"
}
Remove CD-ROM devices from VM.
Request Body: Same as shutdown
Response:
{
"message": "CD-ROM devices removed"
}
WebSocket endpoint for real-time updates.
Connection:
const ws = new WebSocket('ws://localhost:8080/ws');
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
console.log(message);
};
Message Format:
{
"type": "status|jobs|job_update|schedule_event",
"timestamp": "2026-01-17T12:00:00Z",
"data": {...}
}
Message Types:
{
"type": "status",
"data": {
"total_jobs": 42,
"running_jobs": 3,
"completed_jobs": 35,
"failed_jobs": 4
}
}
{
"type": "jobs",
"data": {
"jobs": [...]
}
}
{
"type": "job_update",
"data": {
"definition": {...},
"status": "running",
"progress": {...}
}
}
{
"type": "schedule_event",
"data": {
"schedule_id": "daily-backup",
"event": "triggered|completed|failed"
}
}
Features:
Prometheus metrics endpoint.
Note: Must be enabled in configuration:
metrics:
enabled: true
port: 8080
Response: Prometheus text format
# HELP hypersdk_api_requests_total Total API requests
# TYPE hypersdk_api_requests_total counter
hypersdk_api_requests_total{method="GET",path="/status",status="OK"} 1234
# HELP hypersdk_api_request_duration_seconds API request duration
# TYPE hypersdk_api_request_duration_seconds histogram
hypersdk_api_request_duration_seconds_bucket{method="GET",path="/status",le="0.1"} 1200
# HELP hypersdk_jobs_total Total jobs by status
# TYPE hypersdk_jobs_total gauge
hypersdk_jobs_total{status="completed"} 35
hypersdk_jobs_total{status="running"} 3
hypersdk_jobs_total{status="failed"} 4
Available Metrics:
hypersdk_api_requests_total - Total API requests (counter)hypersdk_api_request_duration_seconds - Request duration (histogram)hypersdk_jobs_total - Total jobs by status (gauge)hypersdk_workers_active - Active workers (gauge)hypersdk_build_info - Build information (gauge)All endpoints use standard HTTP status codes and return errors in this format:
{
"error": "descriptive error message"
}
Common Status Codes:
200 OK - Success201 Created - Resource created400 Bad Request - Invalid request404 Not Found - Resource not found405 Method Not Allowed - Wrong HTTP method500 Internal Server Error - Server error503 Service Unavailable - Service not enabled# config.yaml
database:
path: "/var/lib/hypersdk/jobs.db"
metrics:
enabled: true
port: 8080
webhooks:
- url: "https://hooks.example.com/notify"
events:
- job.completed
- job.failed
enabled: true
timeout: 30
retry_count: 3
headers:
Authorization: "Bearer token123"
Submit Job:
curl -X POST http://localhost:8080/jobs/submit \
-H "Content-Type: application/json" \
-d '{
"vm_path": "Datacenter/vm/test-vm",
"source": {"type": "vsphere", ...},
"destination": {"type": "kvm", ...}
}'
Query Jobs:
curl -X POST http://localhost:8080/jobs/query \
-H "Content-Type: application/json" \
-d '{"all": true}'
Create Schedule:
curl -X POST http://localhost:8080/schedules \
-H "Content-Type: application/json" \
-d '{
"id": "nightly-backup",
"schedule": "0 2 * * *",
"job_template": {...}
}'
import requests
# Submit job
response = requests.post('http://localhost:8080/jobs/submit', json={
'vm_path': 'Datacenter/vm/test-vm',
'source': {'type': 'vsphere', ...},
'destination': {'type': 'kvm', ...}
})
job_id = response.json()['job_id']
print(f"Job submitted: {job_id}")
# Monitor job
while True:
job = requests.get(f'http://localhost:8080/jobs/{job_id}').json()
if job['status'] in ['completed', 'failed']:
break
print(f"Progress: {job['progress']['percent_complete']}%")
time.sleep(5)
// Using axios
const axios = require('axios');
// Submit job
const response = await axios.post('http://localhost:8080/jobs/submit', {
vm_path: 'Datacenter/vm/test-vm',
source: {type: 'vsphere', ...},
destination: {type: 'kvm', ...}
});
const jobId = response.data.job_id;
// Connect WebSocket for real-time updates
const ws = new WebSocket('ws://localhost:8080/ws');
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'job_update' &&
msg.data.definition.id === jobId) {
console.log('Progress:', msg.data.progress.percent_complete + '%');
}
};
Currently no rate limiting is implemented. Consider adding in production: