SparkCloud API Reference

The SparkCloud API lets you manage containers, spaces, databases, CDN files, and AI keys programmatically. All endpoints live under /api/v1/.

Authentication

Generate an API key in your Account settings under API Keys. Keys begin with sc_live_.

Pass your key on every request:

X-API-Key: sc_live_your_key_here
#: or: Authorization: Bearer sc_live_your_key_here
Admin endpoints (under /admin/) require the admin role on your account.

Errors

All responses are JSON. Errors return an error string. Successful mutations return a message string.

Error

{
  "error": "Container not found"
}

Success

{
  "message": "Container stopped"
}

Paginated endpoints accept ?page=1&limit=25 query parameters (max limit 100).

Account

Manage your own profile and credentials.

GET /api/v1/account

Returns your profile, credit balance, quotas, and current usage.

Response

{
  "id": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
  "username": "alice",
  "email": "alice@example.com",
  "role": "user",
  "credits": 42.5,
  "quotas": {
    "containers": { "used": 1, "limit": 3 },
    "spaces":     { "used": 0, "limit": 2 },
    "databases":  { "used": 1, "limit": 2 }
  },
  "createdAt": "2025-01-15T10:00:00.000Z"
}

PATCH /api/v1/account

Update your username and/or email address.

Request

{
  "username": "alice2",
  "email": "alice2@example.com"
}

Response

{
  "user": {
    "id": "3f2504e0...",
    "username": "alice2",
    "email": "alice2@example.com",
    "role": "user"
  }
}

POST /api/v1/account/change-password

Change your own account password.

Request

{
  "currentPassword": "oldSecret123",
  "newPassword": "newSecret456"
}

Response

{
  "message": "Password changed successfully"
}

GET /api/v1/account/transactions

Paginated credit transaction history. Query: ?page=1&limit=25

Response

{
  "transactions": [
    {
      "id": "uuid",
      "amount": -0.002,
      "type": "debit",
      "description": "Container hourly billing",
      "createdAt": "2025-03-07T12:00:00.000Z"
    }
  ],
  "page": 1,
  "limit": 25,
  "total": 84
}

GET /api/v1/account/storage

Full storage usage breakdown for your account, including quota, allocated instances, and CDN files. Running/stopped instances report their allocated disk. Hibernated instances report their actual compressed snapshot size.

Response

{
  "quota": {
    "quotaGb": 0,
    "allocatedGb": 15,
    "cdnGb": 0.12,
    "availableGb": 4.88
  },
  "totalBytes": 21474836480,
  "totalMb": 20480,
  "breakdown": {
    "containers": {
      "count": 2,
      "allocatedBytes": 10737418240,
      "snapshotBytes": 524288000,
      "totalBytes": 11261706240
    },
    "spaces": {
      "count": 1,
      "allocatedBytes": 5368709120,
      "snapshotBytes": 0,
      "totalBytes": 5368709120
    },
    "databases": {
      "count": 1,
      "allocatedBytes": 5368709120,
      "snapshotBytes": 0,
      "totalBytes": 5368709120
    },
    "backups": {
      "count": 3,
      "totalBytes": 314572800
    },
    "cdn": {
      "count": 12,
      "totalBytes": 130023424
    }
  }
}

Notifications

Platform notifications sent to your account.

GET /api/v1/notifications

List your notifications. Query: ?unread=true, ?page=1&limit=25.

Response

{
  "notifications": [
    {
      "id": "uuid",
      "title": "Container transferred",
      "message": "Your container has been moved to a new node.",
      "type": "info",
      "read": false,
      "link": "/containers/uuid",
      "createdAt": "2025-03-07T12:00:00.000Z"
    }
  ],
  "page": 1,
  "limit": 25,
  "total": 3,
  "unreadCount": 1
}

Mark Notifications Read

POST/api/v1/notifications/:id/read
POST/api/v1/notifications/read-all

Response

{ "message": "All notifications marked as read" }

Delete Notifications

DELETE/api/v1/notifications/:idDelete one
DELETE/api/v1/notificationsClear all

Response

{ "message": "All notifications cleared" }

Vouchers

Redeem voucher codes to add credits to your account.

POST /api/v1/vouchers/redeem

Redeem a voucher code. Each code can only be redeemed once per user.

Request

{ "code": "ABCD-EFGH-WXYZ" }

Response

{ "message": "Voucher redeemed successfully", "credits": 500 }

Containers

Linux containers with full SSH access, a dedicated IP, and an optional extra port.

Compute & Images

GET/api/v1/containers/plansDynamic plan info & price

SparkCloud runs a single Dynamic plan: CPU and RAM fluctuate to your workload, so there is nothing to choose at create time.

Response

{
  "plans": [
    { "id": "dynamic", "name": "Dynamic", "dynamic": true, "pricePerHour": 0.5,
      "note": "CPU and RAM fluctuate to your workload, no plan selection needed." }
  ]
}
GET/api/v1/containers/imagesList allowed images

Response

{ "images": [ { "value": "ubuntu:22.04", "label": "Spark Ubuntu 22.04 LTS" } ] }

POST /api/v1/containers

Create a new container. The container is queued immediately and typically starts within 30–60 seconds. No plan to choose. CPU and RAM scale to the node automatically.

Request

{
  "name": "my-ubuntu",
  "image": "ubuntu:22.04",
  "diskGb": 10
}

Response

{
  "container": {
    "id": "uuid",
    "name": "my-ubuntu",
    "status": "queued",
    "image": "ubuntu:22.04",
    "subdomain": "myapp",
    "host": "myapp.node1.yourdomain.com",
    "sshPort": 32100,
    "sshUser": "root",
    "sshPassword": "xK9mP2qL...",
    "hostname": "my-ubuntu",
    "extraPort": 32101,
    "ssh": {
      "host": "1.2.3.4",
      "port": 32100,
      "user": "root",
      "password": "xK9mP2qL...",
      "command": "ssh root@1.2.3.4 -p 32100"
    },
    "createdAt": "2025-01-15T10:00:00.000Z"
  },
  "message": "Container queued for deployment"
}
Only image: ubuntu:22.04 (Spark Ubuntu 22.04 LTS). Poll GET /containers/:id until status becomes running. Pass optional diskGb to allocate a specific amount of your storage quota to this container (default: 10GB).

GET /api/v1/containers

List your containers. Query: ?status=running. Statuses: running, stopped, hibernated, creating, error.

Response

{
  "containers": [
    {
      "id": "uuid",
      "name": "my-ubuntu",
      "status": "running",
      "image": "ubuntu:22.04",
      "subdomain": "myapp",
    "host": "myapp.node1.yourdomain.com",
      "sshPort": 32100,
      "sshUser": "root",
      "sshPassword": "xK9mP2qL...",
      "hostname": "my-ubuntu",
      "extraPort": 32101,
      "hibernated": false,
      "ssh": {
        "host": "1.2.3.4",
        "port": 32100,
        "user": "root",
        "password": "xK9mP2qL...",
        "command": "ssh root@1.2.3.4 -p 32100"
      },
      "plan": { "name": "Nano", "cpu": 1, "memoryMb": 512, "diskGb": 10 },
      "nodeRegion": "us-east-1",
      "createdAt": "2025-01-15T10:00:00.000Z"
    }
  ]
}

GET /api/v1/containers/:id

Full details for a single container including SSH connection command.

Response

{
  "id": "uuid",
  "name": "my-ubuntu",
  "status": "running",
  "ssh": {
    "host": "1.2.3.4",
    "port": 32100,
    "user": "root",
    "password": "xK9mP2qL...",
    "command": "ssh root@1.2.3.4 -p 32100"
  },
  "plan": { "id": "uuid", "name": "Nano", "cpu": 1, "memoryMb": 512, "diskGb": 10 },
  "nodeRegion": "us-east-1",
  "createdAt": "2025-01-15T10:00:00.000Z"
}

DELETE /api/v1/containers/:id

Permanently destroy a container and all its data.

This action is irreversible.

Response

{ "message": "Container destroyed" }

Start / Stop / Restart

POST/api/v1/containers/:id/start
POST/api/v1/containers/:id/stop
POST/api/v1/containers/:id/restart

No request body required.

Response

{ "message": "Container started" }
{ "message": "Container stopped" }
{ "message": "Container restarted" }

GET /api/v1/containers/:id/logs

Recent container logs. Query: ?tail=100 (max 500 lines).

Response

{
  "logs": "Welcome to Ubuntu 22.04
...
root@my-ubuntu:~#",
  "lines": 42
}

POST /api/v1/containers/:id/exec

Run a shell command inside a running container.

Request

{ "command": "df -h && uptime" }

Response

{
  "output": "Filesystem  Size  Used
...",
  "exitCode": 0
}

POST /api/v1/containers/:id/regenerate-password

Generate a new SSH password. Applied instantly and saved to your account.

Response

{
  "message": "Password regenerated",
  "password": "nX7kQ2mPvRtL9s3J",
  "ssh": {
    "host": "1.2.3.4",
    "port": 32100,
    "user": "root",
    "password": "nX7kQ2mPvRtL9s3J",
    "command": "ssh root@1.2.3.4 -p 32100"
  }
}

Hibernate & Wake

Hibernation snapshots the filesystem to storage and deallocates compute. Storage charges continue; CPU/RAM charges stop.

POST/api/v1/containers/:id/hibernate
POST/api/v1/containers/:id/unhibernate

Response

{ "message": "Container hibernated" }
{ "message": "Container is running" }

PATCH /api/v1/containers/:id/storage

Reallocate disk storage for a container. The new allocation is saved immediately and applied to the Docker storage quota on the next restart. Must not exceed your available storage quota.

Request

{ "diskGb": 20 }

Response

{
  "message": "Storage updated. Restart to apply.",
  "diskGb": 20
}
Check available quota first via GET /api/v1/account/storage. A restart is required for Docker to enforce the new limit.

Spaces

Browser-based VS Code environments. Auto-hibernates after 30 minutes of inactivity.

GET /api/v1/spaces/plans

Spaces run on the single Dynamic plan: CPU and RAM scale to the node automatically.

Response

{
  "plans": [
    { "id": "dynamic", "name": "Dynamic", "dynamic": true, "pricePerHour": 0.5 }
  ]
}

POST /api/v1/spaces

Create a new dev space (browser VS Code). No plan to choose. CPU and RAM scale to the node automatically.

Request

{
  "name": "my-workspace",
  "diskGb": 10
}

Response

{
  "space": {
    "id": "uuid",
    "name": "my-workspace",
    "status": "creating",
    "subdomain": "myapp",
    "host": "myapp.node1.yourdomain.com",
    "webPort": 43210,
    "createdAt": "2025-01-15T10:00:00.000Z"
  },
  "message": "Space is launching…"
}
Poll GET /spaces/:id until status is running, then open the space through the dashboard. Pass optional diskGb to allocate a specific amount of your storage quota (default: plan disk size).

GET /api/v1/spaces

List your spaces. Query: ?status=running

Response

{
  "spaces": [
    {
      "id": "uuid",
      "name": "my-workspace",
      "status": "running",
      "subdomain": "myapp",
    "host": "myapp.node1.yourdomain.com",
      "webPort": 56100,
      "hibernated": false,
      "lastActiveAt": "2025-03-07T11:45:00.000Z",
      "nodeRegion": "us-east-1",
      "createdAt": "2025-02-01T08:00:00.000Z"
    }
  ]
}

GET /api/v1/spaces/:id

Response

{
  "id": "uuid",
  "name": "my-workspace",
  "status": "running",
  "subdomain": "myapp",
    "host": "myapp.node1.yourdomain.com",
  "webPort": 56100,
  "hibernated": false,
  "lastActiveAt": "2025-03-07T11:45:00.000Z",
  "nodeRegion": "us-east-1",
  "createdAt": "2025-02-01T08:00:00.000Z"
}

DELETE /api/v1/spaces/:id

Response

{ "message": "Space deleted" }

Start / Stop

POST/api/v1/spaces/:id/start
POST/api/v1/spaces/:id/stop

Response

{ "message": "Space started" }
{ "message": "Space stopped" }

Logs & Activity

GET/api/v1/spaces/:id/logsQuery: ?tail=100

Response

{ "logs": "[16:42:05] INFO  Server listening on :8080
..." }
GET/api/v1/spaces/:id/activity

Response

{
  "lastActiveAt": "2025-03-07T11:45:00.000Z",
  "status": "running"
}

Hibernate & Wake

POST/api/v1/spaces/:id/hibernate
POST/api/v1/spaces/:id/unhibernate

Response

{ "message": "Space hibernated" }
{ "message": "Space is running" }

PATCH /api/v1/spaces/:id/storage

Reallocate disk storage for a space. Saved immediately; applied to the Docker storage quota on next restart.

Request

{ "diskGb": 15 }

Response

{
  "message": "Storage updated. Restart to apply.",
  "diskGb": 15
}

Databases

Managed PostgreSQL with automated backups, SQL Studio, and table browser.

GET /api/v1/databases/pricing

Returns the current hourly credit cost and default resource specs for a new database.

Response

{
  "pricePerHour": 1,
  "engine": "postgresql",
  "defaultDiskGb": 5,
  "defaultMemoryMb": 512,
  "defaultCpu": 1
}

POST /api/v1/databases

Provision a new PostgreSQL database. Only a name is required: resources are fixed at the defaults shown in GET /databases/pricing. Pass optional diskGb to allocate a specific amount of your storage quota (default: 5 GB).

Request

{
  "name": "my-db"
}

Response

{
  "database": {
    "id": "uuid",
    "name": "my-db",
    "status": "creating",
    "subdomain": "myapp",
    "host": "myapp.node1.yourdomain.com",
    "dbPort": 35000,
    "dbName": "sparkcloud",
    "dbUser": "sparkcloud",
    "dbPassword": "auto-generated",
    "connectionString": "postgresql://sparkcloud:pass@1.2.3.4:35000/sparkcloud",
    "createdAt": "2025-01-15T10:00:00.000Z"
  },
  "message": "Database is provisioning…"
}
Poll GET /databases/:id until status is running. The connectionString is ready to use at that point.

GET /api/v1/databases

List your databases. Query: ?status=running

Response

{
  "databases": [
    {
      "id": "uuid",
      "name": "my-postgres",
      "status": "running",
      "subdomain": "myapp",
    "host": "myapp.node1.yourdomain.com",
      "dbPort": 5432,
      "dbName": "sparkcloud",
      "dbUser": "sparkcloud",
      "dbPassword": "secret123",
      "connectionString": "postgresql://sparkcloud:secret123@1.2.3.4:5432/sparkcloud",
      "hibernated": false,
      "backupSchedule": "daily",
      "nodeRegion": "us-east-1",
      "createdAt": "2025-01-20T08:00:00.000Z"
    }
  ]
}

GET /api/v1/databases/:id

Response

{
  "id": "uuid",
  "name": "my-postgres",
  "status": "running",
  "connectionString": "postgresql://sparkcloud:secret123@1.2.3.4:5432/sparkcloud",
  "backupSchedule": "daily",
  "hibernated": false,
  "nodeRegion": "us-east-1",
  "createdAt": "2025-01-20T08:00:00.000Z"
}

DELETE /api/v1/databases/:id

All backups are also deleted. Irreversible.

Response

{ "message": "Database destroyed" }

Start / Stop / Restart

POST/api/v1/databases/:id/start
POST/api/v1/databases/:id/stop
POST/api/v1/databases/:id/restart

Response

{ "message": "Database started" }

POST /api/v1/databases/:id/reset-password

Generate a new PostgreSQL password. Applied instantly. Returns a fresh connection string.

Response

{
  "message": "Password reset",
  "newPassword": "Xk9mQ2pL...",
  "connectionString": "postgresql://sparkcloud:Xk9mQ2pL...@1.2.3.4:5432/sparkcloud"
}

PATCH /api/v1/databases/:id/backup-schedule

Request

{ "schedule": "daily" }

Values: "daily", "weekly", null

Response

{ "message": "Backup schedule set to daily" }

POST /api/v1/databases/:id/query

Execute any SQL statement. Database must be running.

Request

{ "sql": "SELECT id, name FROM users LIMIT 3" }

Response

{
  "columns": ["id", "name"],
  "rows": [["1","Alice"],["2","Bob"]],
  "rowCount": 2,
  "duration": 12
}

GET /api/v1/databases/:id/tables

All tables in the public schema with column definitions.

Response

{
  "tables": [
    {
      "name": "users",
      "columns": [
        { "name": "id",    "type": "uuid", "nullable": false },
        { "name": "email", "type": "text", "nullable": false }
      ]
    }
  ]
}

Backups

GET/api/v1/databases/:id/backupsList

Response

{
  "backups": [
    {
      "id": "uuid",
      "label": "Before migration",
      "type": "manual",
      "status": "ready",
      "sizeBytes": 2097152,
      "createdAt": "2025-03-07T10:00:00.000Z"
    }
  ]
}
POST/api/v1/databases/:id/backupsCreate manual backup

Request

{ "label": "Before migration" }

Response

{ "message": "Backup started", "backup": { "id": "uuid" } }
POST/api/v1/databases/:id/backups/:bid/restore
{ "message": "Backup restored successfully" }
DELETE/api/v1/databases/:id/backups/:bid
{ "message": "Backup deleted" }

Hibernate & Wake

POST/api/v1/databases/:id/hibernate
POST/api/v1/databases/:id/unhibernate

Response

{ "message": "Database hibernated" }
{ "message": "Database is running" }

PATCH /api/v1/databases/:id/storage

Reallocate disk storage for a database. Saved immediately; applied to the Docker storage quota on next restart.

Request

{ "diskGb": 10 }

Response

{
  "message": "Storage updated. Restart to apply.",
  "diskGb": 10
}

CDN Storage

Upload and serve files via SparkStore. Files get a permanent slug-based URL.

GET /api/v1/cdn/files

List your CDN files. Query: ?page=1&limit=25

Response

{
  "files": [
    {
      "slug": "xK9mP2qL",
      "filename": "photo.jpg",
      "size": 204800,
      "visibility": "private",
      "url": "https://cdn.example.com/api/files/xK9mP2qL",
      "createdAt": "2025-03-01T10:00:00.000Z"
    }
  ],
  "page": 1, "limit": 25, "total": 12
}

POST /api/v1/cdn/upload

All uploads are private.

Option A: multipart/form-data

curl -X POST /api/v1/cdn/upload   -H "X-API-Key: sc_live_..."   -F "file=@photo.jpg"

Option B: binary body

curl -X POST /api/v1/cdn/upload   -H "X-API-Key: sc_live_..."   -H "X-Filename: photo.jpg"   --data-binary @photo.jpg

Response

{
  "slug": "xK9mP2qL",
  "url": "https://cdn.example.com/api/files/xK9mP2qL",
  "filename": "photo.jpg",
  "size": 204800,
  "visibility": "private"
}

GET /api/v1/cdn/files/:slug

Response

{
  "slug": "xK9mP2qL",
  "filename": "photo.jpg",
  "size": 204800,
  "visibility": "private",
  "url": "https://cdn.example.com/api/files/xK9mP2qL",
  "createdAt": "2025-03-01T10:00:00.000Z"
}

DELETE /api/v1/cdn/files/:slug

Response

{ "message": "File deleted" }

AI Keys

Manage keys for SparkCloud's OpenAI-compatible proxy at /api/ai/v1/ (and its Anthropic-compatible twin at /api/ai/anthropic/v1/messages, which Claude Code uses).

GET /api/ai/v1/models

Pass one of these ids as model in POST /api/ai/v1/chat/completions. Omit it, or send an id your key can’t use, and the request runs on the default model. Usage is billed at the serving model’s price, in credits per 1,000 tokens. GET /api/ai/v1/models returns the same list for your key, including any early-access models enabled for your account.

Loading models…

Response

{
  "object": "list",
  "data": [
    {
      "id": "auto",
      "object": "model",
      "name": "…",
      "supports_tools": true,
      "context_window": 128000,
      "pricing": { "unit": "credits_per_1k_tokens", "input": 0.15, "output": 0.15 }
    }
  ]
}

GET /api/v1/ai/keys

Response

{
  "keys": [
    {
      "id": "uuid",
      "name": "My App",
      "prefix": "sc-ai-3f2504e0…",
      "createdAt": "2025-02-15T10:00:00.000Z"
    }
  ]
}

POST /api/v1/ai/keys

The full key is only returned once. Store it immediately.

Request

{ "name": "Production App" }

Response

{
  "id": "uuid",
  "name": "Production App",
  "key": "sc-ai-3f2504e04f89..."
}

DELETE /api/v1/ai/keys/:id

Response

{ "message": "AI key deleted" }