Skip to main content
Last updated: May 29, 2026Latest Frontend Version:

tiCrypt REST API

Base URL

Your base URL is the backend domain of your tiCrypt deployment (e.g., https://api.yourinstitution.edu). Replace api-demo.ticrypt.com in the examples below with your own backend domain.

Authentication

The tiCrypt API uses token-based authentication. Each token is scoped to a specific resource type, which determines which routes are accessible. Tokens are generated through the tiCrypt administrative interface.

Token Types

Each token type is scoped to its own set of routes:

Token TypeAvailable Routes
DriveDrive Routes
VMVM Routes
TeamTeam Routes
ProjectProject Routes
UserUser Routes

Passing Tokens

Tokens can be passed in one of two ways:

MethodExample
URL parameter/api/drives?token=YOUR_TOKEN
Cookie headerCookie: TC_TOKEN=YOUR_TOKEN
Token Precedence

If both a URL parameter and a cookie are provided, the URL parameter takes precedence and the cookie is ignored.

Read-Only Tokens (as of ver. 3.13.8)

Tokens can be created as read-only by passing "readOnly": true in the token creation request body. A read-only token is restricted to read and list operations only. Any request that mutates state will be rejected with an error.

If readOnly is omitted or set to false at creation time, the token behaves as a full-access token for its type.

When fetching or creating a token, the readOnly field is included in the response:

  • APITokenInfo (returned when listing/fetching tokens) includes readOnly: boolean
  • APITokenCreateResponse (returned on creation) reflects the resolved readOnly value (false if not specified)

Routes accessible with a read-only token:

RouteMethodDescription
/api/drivesGETGet Drives
/api/vms/imagesGETGet VM Images
/api/vms/<realmID>/activeGETGet Active VMs for Realm
/api/vms/<realmID>/configsGETGet VM Configs
/api/teamsGETGet Teams
/api/teams/quotasGETGet Team Quotas
/api/projectsGETGet Projects
/api/projects/<projectID>GETGet Project
/api/usersGETList Users

Routes blocked for read-only tokens:

RouteMethodDescription
/api/vms/imagesPOSTCreate VM Image
/api/vms/bricksPATCHEdit Brick
/api/teamsPOSTCreate Team
/api/teams/quotasPATCHEdit Team Quotas
/api/users/disablePOSTDeactivate Users

Error Handling

When a request fails, the API returns an appropriate HTTP status code with an error message in the response body.

Common Status Codes

StatusMeaning
200 OKRequest succeeded
400 Bad RequestMalformed request body or missing required fields
401 UnauthorizedMissing or invalid token
403 ForbiddenToken does not have permission for this operation (e.g., read-only token on a mutating route, or wrong token type)
404 Not FoundThe requested resource does not exist
422 Unprocessable EntityRequest body is valid JSON but contains invalid values
500 Internal Server ErrorUnexpected server error
Pagination

List endpoints return all results in a single response. There is no pagination. For large datasets, filter on the client side.


Drive Routes

Route Summary

RouteMethodDescription
/api/drivesGETGet Drives

Get Drives

GET /api/drives

Token type: Drive

Lists all drives on the system.

Request body: None

Response:

StatusDescription
200 OKReturns an array of DriveInfo objects
401 UnauthorizedInvalid or missing token
interface DriveInfo {
id: string;
name: string;
owner: string;
capacity: number; // Total capacity in bytes
format: string; // ext4, ntfs, etc.
noBackup?: boolean; // Whether the drive has backup disabled (Deprecated)
settings?: object; // Frontend-specific JSON settings
writer?: string; // ID of any VM attached as read-write
readers: string[]; // IDs of VMs attached as read-only
created: number; // Epoch time in millis
changed?: number; // Epoch time in millis, last modified
attached?: number; // Epoch time in millis, last attached
writable?: boolean;
poolID?: string; // Libvirt pool ID, if not in default pool
team?: string;
project?: string;
realmID: string;
diskType?: string; // qcow2, raw, etc.
cache?: string;
io?: string;
state: string; // Ready | ReadOnly | ReadWrite | Transferring | Initializing
stateChange?: number; // Epoch time in millis
hasSnapshot: boolean;
}
Deprecated Field

The noBackup field is deprecated and defaults to true. It will be removed in a future version.

Example response:

[
{
"id": "8cd6c832-d5db-45cf-9de2-b2c2f1a9b107",
"name": "Research Data Vol 1",
"owner": "60eeec74-37db-4f69-bb46-bf4ca4f69e03",
"capacity": 107374182400,
"format": "ext4",
"readers": [],
"created": 1747838038956,
"writable": true,
"realmID": "libvirt",
"diskType": "qcow2",
"state": "Ready",
"hasSnapshot": false
}
]

cURL example:

curl --request GET \
--url 'https://api-demo.ticrypt.com/api/drives?token=YOUR_TOKEN' \
--cookie 'TC_TOKEN=YOUR_TOKEN'

VM Routes

Route Summary

RouteMethodDescription
/api/vms/imagesGETGet VM Images
/api/vms/imagesPOSTCreate VM Image
/api/vms/bricksPATCHEdit Brick (Hardware Setup)
/api/vms/<realmID>/activeGETGet Active VMs for Realm
/api/vms/<realmID>/configsGETGet VM Configs

Get VM Images

GET /api/vms/images

Token type: VM

Lists all images for the specified realm.

Request body:

FieldTypeRequiredDescription
realmstringYesRealm ID to list images for

Response:

StatusDescription
200 OKReturns an array of ImageInfo objects
400 Bad RequestMissing realm field
401 UnauthorizedInvalid or missing token
interface ImageInfo {
id: string;
name?: string;
description?: string;
size?: number; // Size in bytes
imageType?: string; // "windows" | "linux"
info: LibvirtExtraInfo;
created?: number; // Epoch time in millis
modified?: number; // Epoch time in millis
version?: number; // Empty if base image (ver. 0)
parent?: string; // Empty if base image
limit?: number; // Max concurrent VMs (undefined = no limit)
settings?: object; // Frontend-only settings
}

LibvirtExtraInfo

interface LibvirtExtraInfo {
pool: string; // Pool ID
volume: string; // Volume name in pool (e.g., "my-image.img")
deviceBusType: "scsi" | "virtio";
}

Example response:

[
{
"id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"name": "Rocky 8 Production",
"description": "Rocky Linux 8 base image with tiCrypt VM controller",
"size": 5368709120,
"imageType": "linux",
"info": {
"pool": "ticrypt-vm-drives",
"volume": "rocky8-prod.qcow2",
"deviceBusType": "virtio"
},
"created": 1740000000000,
"modified": 1747000000000,
"version": 0
}
]

cURL example:

curl --request GET \
--url 'https://api-demo.ticrypt.com/api/vms/images?token=YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--data '{"realm": "libvirt"}'

Get VM Configs

GET /api/vms/<realmID>/configs

Token type: VM

Returns all VM configurations in the system for the specified realm.

Request body: None

Response:

StatusDescription
200 OKReturns an array of VMConfigInfo objects
401 UnauthorizedInvalid or missing token
interface VMConfigInfo {
id: string;
vmID?: string; // UUID of spawned VM
state: "Stopped" | "Starting" | "Running" | "Suspended" | "Stopping";
owners: string[];
name: string;
description: string;
brick: string; // Hardware Setup ID
team?: string;
project?: string;
rwDrives: string[]; // Read-write drive IDs
roDrives: string[]; // Read-only drive IDs
mac?: string;
host?: string; // Pinned host
controllerID?: string;
driveSlots: { [key: string]: number };
macOptions: string[];
settings?: object;
}

Example response:

[
{
"id": "7f1b326d-0eef-4875-9deb-d820ace7a372",
"brick": "dd86080c-062a-4aba-889a-dbf64624e917",
"description": "",
"driveSlots": {},
"mac": "9c:75:16:ee:b5:3e",
"macOptions": [],
"name": "July08-rocky",
"owners": ["8e5789ae-da9f-48c1-8e63-ea989a4249a0"],
"project": "proj|38fa1dae-748e-45ae-8a1f-c799a4840a18",
"roDrives": [],
"rwDrives": ["8cd6c832-d5db-45cf-9de2-b2c2f1a9b107"],
"state": "Stopped",
"team": "team|2d48a972-4dd0-44e6-803f-956dbc56503c",
"vmID": "3a4be5cf-2e3c-43ff-879e-2b62e8665dd6"
}
]

cURL example:

curl --request GET \
--url 'https://api-demo.ticrypt.com/api/vms/libvirt/configs?token=YOUR_TOKEN'

Get Active VMs for Realm

GET /api/vms/<realmID>/active

Token type: VM

Returns all active (running) VMs for the specified realm.

Request body: None

Response:

StatusDescription
200 OKReturns an array of VirtualMachine objects
401 UnauthorizedInvalid or missing token
interface VirtualMachine {
id: string;
name: string;
owner: string;
brick: string; // Hardware Setup ID
active: boolean;
pubkey?: PublicKey; // PEM-encoded RSA public key
drives: { [key: string]: string }; // Device name → drive ID (e.g., "vda" → "driveID")
ip: string; // Host address
team?: string;
project?: string;
protocolVer: number;
authedUsers: string[]; // All authorized users (excluding owner)
managers: string[]; // Users who can authorize others (subset of authedUsers)
realmID: string;
resources?: HostUsage;
ownerType?: "User" | "VM";
vpn: HostAndPort;
ssh: HostAndPort;
lastPing?: number; // Epoch time in millis
start?: number; // Epoch time in millis
shutDown?: number; // Epoch time in millis
config?: string; // VM Config ID
vmcInfo: VMCInfo[];
systemInfo?: object;
}

interface HostUsage {
vms: number;
vcpus: number;
memory: number;
devices: { [deviceType: string]: number };
}

interface HostAndPort {
host: string;
port: number;
}

interface VMCInfo {
timestamp: number;
info: object;
}

Example response:

[
{
"id": "13154348-ed6c-48fc-bf6c-9591bc974738",
"name": "Test VM",
"owner": "60eeec74-37db-4f69-bb46-bf4ca4f69e03",
"brick": "dd86080c-062a-4aba-889a-dbf64624e917",
"active": true,
"drives": {
"vdb": "94d13381-4720-4318-a594-d99eeacd151a",
"vdc": "ef71c696-360d-46a0-8e15-93ca6a635e28"
},
"ip": "192.168.122.80",
"authedUsers": [
"5babdba1-1354-4f08-93e2-018cfe113e70",
"f78c005b-690f-4cab-a515-0064bc0d24e2"
],
"managers": ["5babdba1-1354-4f08-93e2-018cfe113e70"],
"realmID": "libvirt",
"ownerType": "User",
"protocolVer": 1,
"resources": {
"vms": 1,
"vcpus": 16,
"memory": 17179869184,
"devices": {"gpu-nvidia": 0}
},
"vpn": {"host": "127.0.0.1", "port": 30336},
"ssh": {"host": "127.0.0.1", "port": 30080},
"lastPing": 1747955324629,
"start": 1747838038956,
"config": "d022a3ca-dd93-4aad-a783-40b6b47bf6d9",
"vmcInfo": []
}
]

cURL example:

curl --request GET \
--url 'https://api-demo.ticrypt.com/api/vms/libvirt/active?token=YOUR_TOKEN'

Create VM Image

POST /api/vms/images

Token type: VM   Read-only: Blocked

Creates a new VM image in the specified realm.

Request body:

FieldTypeRequiredDescription
realmstringYesRealm ID
namestringNoName for the image
descriptionstringNoShort description
sizenumberNoImage size in bytes
imageTypestringNo"windows" or "linux"
infoLibvirtExtraInfoYesRealm-specific image info
limitnumberNoMax concurrent VMs from this image
settingsobjectNoFrontend-specific settings (see below)

Settings options:

FieldOptionsDescription
driveFormatsext4, ntfs, btrfs, xfs, zfsAllowed drive formats for VMs running this image

Response:

StatusDescription
200 OKReturns the created ImageInfo object
400 Bad RequestMissing required fields
401 UnauthorizedInvalid or missing token
403 ForbiddenRead-only token

Returns an ImageInfo object on success.

Example request:

{
"realm": "libvirt",
"name": "Rocky 8 Custom",
"description": "Custom Rocky Linux 8 image",
"size": 5368709120,
"imageType": "linux",
"info": {
"pool": "ticrypt-vm-drives",
"volume": "rocky8-prod.qcow2",
"deviceBusType": "virtio"
},
"limit": 5,
"settings": {
"driveFormats": ["ext4", "xfs"]
}
}

cURL example:

curl --request POST \
--url 'https://api-demo.ticrypt.com/api/vms/images?token=YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--data @payload.json

Edit Brick

PATCH /api/vms/bricks

Token type: VM   Read-only: Blocked

Updates a Hardware Setup (Brick) used for creating VMs. Only the fields included in params will be changed.

Request body:

FieldTypeRequiredDescription
idstringYesID of the brick to edit
paramsBrickParametersYesFields to update

Brick Update Parameters

All fields are optional. Only defined fields are changed.

FieldTypeDescription
namestringShort name for the brick
descriptionstringLonger description, supports markdown
vcoresnumberVirtual CPU cores
maxMemBytesnumberRAM in bytes
setupstringSetup instructions for VM creation
realmIDstringRealm ID
libvirtLibvirtBrickConfigLibvirt-specific config (required if realm driver is libvirt)
whitelistBrickWhitelistTeams and users allowed to access the brick
externalServersstring[]External servers the brick can access
formatstringOS format: "linux" or "windows"

Response:

StatusDescription
200 OKReturns the updated BrickInfo object
400 Bad RequestMissing id or malformed params
401 UnauthorizedInvalid or missing token
403 ForbiddenRead-only token
404 Not FoundBrick ID does not exist
interface BrickInfo {
id: string;
name: string;
description: string;
setup?: string; // Markdown setup instructions
vcores: number;
maxMemBytes: number;
realmID: string;
libvirt?: LibvirtBrickConfig;
whitelist?: BrickWhitelist;
creatorID: string;
externalServers: string[];
format?: string; // "linux" | "windows"
imageID?: string;
created: number; // Epoch time in millis
modified?: number; // Epoch time in millis
noQuota: boolean; // Default: false
params?: string; // Optional VM parameters
settings?: string; // Frontend-only settings
vmType: "Secure" | "Service" | "Data" | "Worker";
}

interface LibvirtBrickConfig {
image: { pool: string; volume: string };
video?: "vnc" | "spice"; // Default: none
pty?: boolean; // Default: false
clockOffset?: "utc" | "localtime"; // Default: "localtime" (Windows), "utc" (others)
nic?: string; // Default: "virtio". Also: "rtl8139"
devices?: { [type: string]: number };
extraXML?: string;
headfullGPU?: string;
deviceBusType?: string;
}

interface BrickWhitelist {
teamIDs: string[];
userIDs: string[];
}

Example request:

{
"id": "dd86080c-062a-4aba-889a-dbf64624e917",
"params": {
"name": "Updated Brick",
"vcores": 8,
"maxMemBytes": 17179869184,
"libvirt": {
"image": {
"pool": "ticrypt-vm-drives",
"volume": "rocky8-prod.qcow2"
},
"video": "vnc",
"pty": true,
"clockOffset": "utc",
"nic": "virtio",
"devices": {"gpu-nvidia": 1}
},
"whitelist": {
"teamIDs": ["team|2d48a972-4dd0-44e6-803f-956dbc56503c"],
"userIDs": []
},
"format": "linux"
}
}

cURL example:

curl --request PATCH \
--url 'https://api-demo.ticrypt.com/api/vms/bricks?token=YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--data @payload.json

Team Routes

Shared Structures

TeamInfo

interface TeamInfo {
id: string;
name: string;
desc: string;
created: number; // Epoch time in millis
modified: number; // Epoch time in millis
quotas: { [key: string]: number }; // Legacy quota representation
teamQuotas: QuotasTyped;
perUserQuotas: QuotasTyped;
settings: object;
startDate?: number; // Epoch millis, resource access start
endDate?: number; // Epoch millis, resource access end
members: TeamMemberInfo[];
}

interface TeamMemberInfo {
id: string;
firstName: string; // Empty string if user no longer exists
lastName: string;
email?: string;
lastLogin?: number; // Epoch time in millis
}

QuotasTyped

interface QuotasTyped {
cores?: number; // undefined = no limit
memory?: number; // In bytes. undefined = no limit
storage?: { [storageType: string]: number }; // In bytes. Empty map = no limits
devices?: { [deviceType: string]: number }; // Empty map = no limits
}

Route Summary

RouteMethodDescription
/api/teamsGETGet Teams
/api/teamsPOSTCreate Team
/api/teams/quotasGETGet Team Quotas
/api/teams/quotasPATCHEdit Team Quotas

Get Teams

GET /api/teams

Token type: Team

Returns all teams on the system.

Request body: None

Response:

StatusDescription
200 OKReturns an array of TeamInfo objects
401 UnauthorizedInvalid or missing token

Example response:

[
{
"id": "team|2d48a972-4dd0-44e6-803f-956dbc56503c",
"name": "Genomics Research Lab",
"desc": "Dr. Chen's genomics team",
"created": 1740000000000,
"modified": 1747000000000,
"quotas": {},
"teamQuotas": {
"cores": 64,
"memory": 137438953472,
"storage": {"vault": 1099511627776}
},
"perUserQuotas": {
"cores": 16,
"memory": 34359738368
},
"settings": {},
"members": [
{"id": "60eeec74-37db-4f69-bb46-bf4ca4f69e03", "firstName": "Jane", "lastName": "Chen", "email": "jchen@example.edu", "lastLogin": 1747955324629}
]
}
]

cURL example:

curl --request GET \
--url 'https://api-demo.ticrypt.com/api/teams?token=YOUR_TOKEN'

Create Team

POST /api/teams

Token type: Team   Read-only: Blocked

Creates a new team.

Request body:

FieldTypeRequiredDescription
namestringYesName of the team
descstringYesDescription of the team

Response:

StatusDescription
200 OKReturns the created TeamInfo object
400 Bad RequestMissing required fields
401 UnauthorizedInvalid or missing token
403 ForbiddenRead-only token

Example request:

{
"name": "New Research Team",
"desc": "Biostatistics collaboration group"
}

cURL example:

curl --request POST \
--url 'https://api-demo.ticrypt.com/api/teams?token=YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--data '{"name": "New Research Team", "desc": "Biostatistics collaboration group"}'

Get Team Quotas

GET /api/teams/quotas

Token type: Team

Returns the quotas for a specific team.

Request body:

FieldTypeRequiredDescription
teamstringYesTeam ID

Response:

StatusDescription
200 OKReturns a QuotasTyped object
400 Bad RequestMissing team field
401 UnauthorizedInvalid or missing token
404 Not FoundTeam does not exist

cURL example:

curl --request GET \
--url 'https://api-demo.ticrypt.com/api/teams/quotas?token=YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--data '{"team": "team|2d48a972-4dd0-44e6-803f-956dbc56503c"}'

Edit Team Quotas

PATCH /api/teams/quotas

Token type: Team   Read-only: Blocked

Updates the quotas for a specific team.

Request body:

FieldTypeRequiredDescription
teamstringYesTeam ID
quotasQuotasTypedYesNew quota values

Response:

StatusDescription
200 OKReturns the updated TeamInfo object
400 Bad RequestMissing required fields
401 UnauthorizedInvalid or missing token
403 ForbiddenRead-only token
404 Not FoundTeam does not exist

Example request:

{
"team": "team|2d48a972-4dd0-44e6-803f-956dbc56503c",
"quotas": {
"cores": 128,
"memory": 274877906944,
"storage": {
"vault": 1099511627776,
"drives": 2199023255552
},
"devices": {
"gpu-nvidia": 4
}
}
}

cURL example:

curl --request PATCH \
--url 'https://api-demo.ticrypt.com/api/teams/quotas?token=YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--data @payload.json

Project Routes

Shared Structures

ProjectInfo

interface ProjectInfo {
id: string;
name: string;
desc: string; // Supports markdown
securityLevel: string; // ID of required security level
parent?: string; // Parent project ID (for sub-projects)
settings: object; // Frontend-specific JSON settings
created: number; // Epoch time in millis
modified: number; // Epoch time in millis
}

Route Summary

RouteMethodDescription
/api/projectsGETGet Projects
/api/projects/<projectID>GETGet Project

Get Projects

GET /api/projects

Token type: Project

Returns all projects on the system.

Request body: None

Response:

StatusDescription
200 OKReturns an array of ProjectInfo objects
401 UnauthorizedInvalid or missing token

Example response:

[
{
"id": "proj|38fa1dae-748e-45ae-8a1f-c799a4840a18",
"name": "CMMC Enclave Study",
"desc": "DoD-funded research project under CMMC Level 2",
"securityLevel": "cui",
"settings": {},
"created": 1740000000000,
"modified": 1747000000000
}
]

cURL example:

curl --request GET \
--url 'https://api-demo.ticrypt.com/api/projects?token=YOUR_TOKEN'

Get Project

GET /api/projects/<projectID>

Token type: Project

Returns information about a specific project.

Request body: None

Response:

StatusDescription
200 OKReturns a ProjectInfo object
401 UnauthorizedInvalid or missing token
404 Not FoundProject does not exist

cURL example:

curl --request GET \
--url 'https://api-demo.ticrypt.com/api/projects/proj%7C38fa1dae-748e-45ae-8a1f-c799a4840a18?token=YOUR_TOKEN'
URL Encoding

Project IDs contain the | character, which must be URL-encoded as %7C when used in the path.


User Routes

Shared Structures

UserInfo

interface UserInfo {
id: string;
firstName: string;
lastName: string;
email: string; // Login email / username
contactEmail?: string; // Contact email if different from login
joined: number; // Epoch time in millis
lastLogin?: number; // Epoch time in millis
role: string;
permissions: string[];
state: string; // Account state
stateReason?: string;
deactivationType?: DeactivationType;
department?: string;
position?: string;
comment?: string; // Admin-visible notes
neverEscrow?: boolean;
passChanged?: number; // Epoch millis, last SSA credential change
expiration?: number; // Epoch millis, account expiration
tosAccepted?: number; // Epoch millis, last ToS acceptance
deactivatedUntil?: number; // Epoch millis, temporary deactivation end
lastEscrow?: number; // Epoch millis, last escrow date
}

DeactivationType

ValueDescription
AdminDisabled by an administrator
FailedPasswordDisabled due to consecutive failed password attempts
TimeoutDisabled due to account inactivity
XSSDisabled due to detected XSS attack attempt
RegistrationDisabled pending account activation

Route Summary

RouteMethodDescription
/api/usersGETList Users
/api/users/disablePOSTDeactivate Users

List Users

GET /api/users

Token type: User

Lists all users in the system.

Request body: None

Response:

StatusDescription
200 OKReturns an array of UserInfo objects
401 UnauthorizedInvalid or missing token

Example response:

[
{
"id": "60eeec74-37db-4f69-bb46-bf4ca4f69e03",
"firstName": "Jane",
"lastName": "Chen",
"email": "jchen@example.edu",
"joined": 1720000000000,
"lastLogin": 1747955324629,
"role": "User",
"permissions": ["drive.create", "vm.launch"],
"state": "Active"
}
]

cURL example:

curl --request GET \
--url 'https://api-demo.ticrypt.com/api/users?token=YOUR_TOKEN'

Deactivate Users

POST /api/users/disable

Token type: User   Read-only: Blocked

Disables one or more users by ID. Super-admins cannot be disabled.

Request body:

FieldTypeRequiredDescription
usersstring[]YesArray of user IDs to deactivate

Response:

StatusDescription
200 OKUsers deactivated successfully
400 Bad RequestMissing or empty users array
401 UnauthorizedInvalid or missing token
403 ForbiddenRead-only token, or attempted to deactivate a super-admin

Example request:

{
"users": ["a3770b72-7d09-4493-910b-c7dec7417d78"]
}

cURL example:

curl --request POST \
--url 'https://api-demo.ticrypt.com/api/users/disable?token=YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--data '{"users": ["a3770b72-7d09-4493-910b-c7dec7417d78"]}'