Using the VALDI API
A public API is accessible to VALDI customers that enables programmatic provisioning, management, and termination of Virtual Machines.
Authentication
VALDI's API is authenticated with JSON Web Tokens (JWT). The team is in the process of implementing support for API keys, which when complete, will replace the authentication method described here.
Log in
First, log in and obtain a refresh token and access token. This is the programmatic equivalent to logging in to the VALDI dashboard at valdi.ai.
POST https://api.valdi.ai/account/login
You must include the following payload:
{
"email": "your.account.email@youremailprovider.com",
"password": "your_password"
}
An example 200 OK response is:
{
"access_token": "eyJhbGciOiJiUZI1NiIsInr5cCI6IkpXVCJ9.eyJkYXRhIjP7InVzZXJfaWQiOjgsImNyZWF0aW9uX3RpbWUiOiIymdIzLTEyLTA0IDIzOjU0OjU5LjczMzUwOCJ9LCJwdXJwb3NlIjoiYWNjZXNzX3Rva2VuIiwiZXhwIjoyMDIzMTIwNDIzNTk1Ox0.gTBdAOE1_SdAB7BHeUkOUiZfiiyJJBSJ89_ojRS7oFw",
"token_type": "Bearer",
"refresh_token": "eyjhbGciOiJIUzI1NiIsInR5cCI6IkpXVCj9.eyJkyxRhIjp7InVzZXJfawqiOjgsImNyZWF0aW9uX3RpbWUiOiIyMDIzLTEyLTA0IDIzOjU0OjU5LjczMzUwOCJ9LCJwdXJwb3NlIjoicmVmcmVzaC10b2tlbiIsimv4ccI6MjAyNDAxMDMyMzU0NTl9.g8uQyhC7yypj0jQPSK3LmS5MOYs90fD_k7NyfnYhi1m"
}
The access_token
is what you will use to authenticate when calling other APIs. The access token expires every 5
minutes. (This is why we are implementing API keys.)
Refresh access token
To obtain a new access token, use the refresh_token
from the /account/login
call as follows.
POST https://api.valdi.ai/account/refresh_token
You must include the following payload:
{
"token": "your_refresh_token"
}
An example 200 OK response is:
{
"access_token": "your_new_access_token",
"token_type": "Bearer"
}
Virtual Machines (VM)
Fetch available devices
To see the list of available VALDI devices and configurations across all of our different providers, use the following API call.
GET https://api.valdi.ai/v1/devices/available
This endpoint requires authentication. To authenticate, include the following header in the call:
'Authorization: Bearer {your_access_token}'
An example 200 OK response is:
{
"devices_by_provider": [
{
"provider_id": "a45088e0-1681-446e-9a3e-3ed9dfc3d57e",
"provider_devices": [
{
"flavor_id": "94d76997-44ec-4f1e-8291-231de42b6030",
"gpu_type": "RTX A6000 48GB",
"cpu_core_count": 6,
"main_ram": 55,
"storage": 500,
"gpu_count": 1,
"running_cost": "0.660000000000",
"stopped_cost": "0.100000000000"
},
{
"flavor_id": "b5917017-7ca4-403e-b08b-ba5cc31c7d2a",
"gpu_type": "RTX A6000 48GB",
"cpu_core_count": 12,
"main_ram": 110,
"storage": 1000,
"gpu_count": 2,
"running_cost": "1.320000000000",
"stopped_cost": "0.200000000000"
}
]
},
{
"provider_id": "66730e5d-98d2-45f6-8aaa-6ad8cdcbc285",
"provider_devices": [
{
"cpu_type": "AMD EPYC 7713P",
"cpu_core_count": 128,
"main_ram": 185,
"gpu_enabled": true,
"gpu_ram": 80,
"gpu_type": "A100 80GB",
"gpu_code": "a100-pcie-80gb",
"gpu_count": 2,
"location": "Exmouth, Devon, United Kingdom",
"storage": 300,
"hostnode": "b2ce5479-fa59-483f-86ba-0aa128051821",
"available_port": [
21299,
21298,
21297,
21296,
21295,
21294
],
"cpu_cost": 0.0035,
"ram_cost": 0.0025,
"storage_cost": 0.0002,
"gpu_cost": "2.044000000000000",
"upload_bw": 1000.0,
"download_bw": 1000.0
}
]
}
]
}
Generate an SSH key
Some VALDI servers require SSH key authentication, while others require password authentication. This is a consequence of the requirements and configurations implemented by the actual host of the server.
For security purposes, and in line with best practices of major hyperscalers, VALDI does not allow externally generated SSH keys to be used for provisioning a VM.
NOTE: It is generally easier and faster to generate your SSH keys through the dashboard at valdi.ai.
To generate an SSH key, use the following endpoint.
POST https://api.valdi.ai/sshkeys/sshkey
This endpoint requires authentication. To authenticate, include the following header in the call:
'Authorization: Bearer {your_access_token}'
The format of the payload is very simple:
{
"name": "whatever-you-want-to-name-the-key"
}
An example 201 Created response is:
{
"private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKAIBAAKCAgEAvVslMAKcIKk4blv182E2Fh7oJOzvOfzgoenual92VvOG6WPB\n30SHs4+MXBf17Nei+PRUsZ4aYGodt1GIjz3sX/nUdLEdN1oIEYIEqZuMSD899LAh\nme9wBRqydbhhYJOTksbufAkBJNjJT9QkZDArVpvMQ1hqOwCRqpBMY4QsYwxdK3wN\nYr/moffJEXiHvY3XnpaIAPfX+KzO/vp7N01K3L5mugQDisgxXlk7TQn3Py3fJkiD...",
"ssh_key_id": "your-new-ssh-key-uuid"
}
Please save both the private key and the SSH key ID. This is the only time you will be able to retrieve the private key, and the SSH key ID is needed to provision VMs that require SSH key authentication.
Remove new lines from private key
After copying and pasting the private key into a plain text file, you will need to manually remove new line characters
and replace them with actual new lines. One way to do this is by opening the file in vim (sorry emacs fans), entering
command mode by pressing :
, and then running the following command:
:%s/\\n/\r/g
If you generate the SSH key in the dashboard, you don't have to deal with this. :)
Modify permissions of private key
The private key file should have the following permissions, or ssh may refuse to connect you.
-rw-------
To assign such permissions, use the following command:
chmod 600 {private_key_filename}
Get SSH Keys
To get a list of the SSH keys under your account, use the following authenticated API.
GET https://api.valdi.ai/sshkeys
An example 200 OK response is as follows.
{
"ssh_keys": [
{
"name": "api-docs-key",
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC9WyUwApwgqThuW/XzYTYWHugk7O85/OCh6e5qX3ZW84bpY8HfRIezj4xcF/Xs16L49FSxnhpgah23UYiPPexf+dR0sR03WggRggSpm4xIPz30sCGZ73AFGrJ1uGFgk5OSxu58CQEk2MlP1CRkMCtWm8xDWGo7AJGqkExjhCxjDF0rfA1iv+ah98kReIe9jdeelogA99f4rM7++ns3TUrcvma6BAOKyDFeWTtNCfc/Ld8mSIPWCyxC+D3bmrIOm7re87oW01lanp7SSk1xU3P3hXNBsZRf1SkCjNXJIWEq3xp5WJDQYL4yy+J0FnahZC6o6LxeCkc/fEWfTV7yC4Cp7lBstCn9fiZyh2YAnFJd5FjD1JNThiWTw7KUB8qePbhZdxPfNJhMt3qRknMj2wRM6aDAQ68OSKMjUvJjDoJnr3jmlo4ZVvpcU2qRO73vJdrJDtwTCRUheDTXrSd0091JrQGN7qEsjj8BtC4NsPMuQpNJpUAVvCftBgjTD3OH892Ey8geDctLgI8HXoGhkIZNuRsmdL4SmWeH2nyWKRtnKpjiMTUi32Y6KV+Fs7ttvJZ5nG8x+SZ+4G2XfkeFXp/tRypiU7bYnYm5AQINXhSloaHsG/sztCaWyettQje5khNmnrHT/29XQB8vfcSHI3nnY/xkA9I5SN+fB2Vxcav69w==",
"ssh_key_id": "02a18443-93d1-4c86-92f9-65f90d129a74",
"created_at": "2023-12-12T23:13:54.285477"
},
{
"name": "valdi-test-key",
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCXPGUW6PkZjDtOjNf4o9mqtkTTl2w2UCLelcsVDXS2Hh/pS28D6Jyq9JFeLxgusvJrcMA+xUfW7Jc5PiWlvsSzkiaHHDd+Qp38TluxXPiCLz/grLURC6jwQt39z3DMh4Yqrc3ybUdVr8ScD54h6dEw/OtDchdgqmjkdAWTCdlGxmpdw4lPPFuR0MoTVR9ebbwtKxlB2eXk6+voNIYykLdlVxia71xpuVdaBBSI2c59fDK7KsGqkQw7xv31gE3RKc3Z663ieOB3sSClU9FFaixBplrqa2kU8Cb3c5zcmM7VXQiR2rVKSvIdFgIbHdIaEnSn0D9vauNxhJMsONxbVSY2+a6zx+tJ4FR25qsBWkCUwxe2vlMVeoR4kppk11XPiVQBVWPI+Pkygzh0PhrpCqrPz30m9Ue7Oug5SueCefJtrb3GBId2sCuAhiVxQETvUG0873D/TpMI+4mL4tmsNb/RgrxE7kAOAji+bJUaYORmLbJuY98VRJlECJsKHUn52VX9HpA2Vnpfo1RNcnUnMBUzDmh1kqBzzi8mx3c0xL/JQozqtNVuwDg9dAy79CNdU6+nwQdAqvYLU11v68x1i8XssA8b+rRJWzZ2W7QBXssIyPPvsvP1F8Na+8yBam9+XO1nyjL4i4XzmMCcddJJ/edb1xk0Lbrehh5J1LWTPHXVWQ==",
"ssh_key_id": "708bffd3-bce7-4806-aa55-cbaa9a3740b9",
"created_at": "2023-11-30T22:57:53.425409"
}
]
}
Notice that the private keys are not returned. VALDI does not store your private key, so you need to make sure to save it when you first create it.
Provision a VM
POST https://api.valdi.ai/v1/vm/provision
This endpoint requires authentication. To authenticate, include the following header in the call:
'Authorization: Bearer {your_access_token}'
The format of the payload is as follows:
{
"provider_id": "provider_id_from_available_devices_api",
"name": "whatever-name-you-want",
"details": PROVIDER-SPECIFIC OBJECT (SEE BELOW)
}
As noted in the above, the format of the details
object varies depending on the provider.
Provider ID a45088e0
An example details
object for this provider is shown below.
{
"flavor_id": "94d76997-44ec-4f1e-8291-231de42b6030",
"ssh_key_id": "02a18443-93d1-4c86-92f9-65f90d129a74"
}
The definitions of the two fields are:
flavor_id
: The UUID of the desired server configuration as returned byGET /v1/devices/available
ssh_key_id
: The UUID of the SSH key you would like to use to access this machine
A full example payload for provider ID a45088e0-1681-446e-9a3e-3ed9dfc3d57e is as follows.
{
"provider_id": "a45088e0-1681-446e-9a3e-3ed9dfc3d57e",
"name": "whatever-name-you-want",
"details": {
"flavor_id": "94d76997-44ec-4f1e-8291-231de42b6030",
"ssh_key_id": "02a18443-93d1-4c86-92f9-65f90d129a74"
}
}
These VMs have ports 80, 443, and 22 open by default. Other ports can be configured using ufw
once logged in.
Provider ID 66730e5d
An example details
object for this provider is shown below.
{
"gpu_model": "a100-pcie-80gb",
"operating_system": "Ubuntu 20.04 LTS",
"external_ports": "{21299}",
"internal_ports": "{22}",
"gpu_count": 1,
"password": "your-desired-password-to-access-the-vm",
"hostnode": "b2ce5479-fa59-483f-86ba-0aa128051821",
"storage": 256,
"vcpus": 64,
"ram": 128
}
The definitions of the various fields are:
gpu_model
: The desired GPU model as returned byGET /v1/devices/available
undergpu_code
operating_system
: One of the following:Ubuntu 20.04 LTS
: Vanilla image of Ubuntu 20.04 LTS (min. 20 GB storage req'd)Ubuntu 22.04 LTS
: Vanilla image of Ubuntu 22.04 LTS (min. 20 GB storage req'd)TensorML 20 TensorFlow
: Ubuntu 20.04 with TensorFlow and Jupyter (min. 40 GB storage req'd)TensorML 20 PyTorch
: Ubuntu 20.04 with PyTorch and Jupyter (min. 40 GB storage req'd)TensorML 20 Everything
: Ubuntu 20.04 with TensorFlow, PyTorch, MxNet, and Jupyter (min. 60 GB storage req'd)
external_ports
: A list of external ports you want to be exposed (e.g.,{21297, 21298, 21299}
)internal_ports
: A list of corresponding internal ports to which the external ports will map (.e.g,{22, 80, 443}
)- This would map 21297 to 22, 21298 to 80, and 21299 to 443
gpu_count
: The number of GPUs you want to attach to the VMpassword
: Your desired passwordhostnode
: The UUID of the hostnode as returned byGET /v1/devices/available
storage
: The desired amount of storage in GBvcpus
: The desired number of vCPUsram
: The desired amount of RAM in GB
A full example payload for provider ID 66730e5d-98d2-45f6-8aaa-6ad8cdcbc285 is as follows.
{
"provider_id": "66730e5d-98d2-45f6-8aaa-6ad8cdcbc285",
"name": "whatever-name-you-want",
"details": {
"gpu_model": "a100-pcie-80gb",
"operating_system": "Ubuntu 20.04 LTS",
"external_ports": "{21297, 21298, 21299}",
"internal_ports": "{22, 80, 443}",
"gpu_count": 1,
"password": "your-desired-password-to-access-the-vm",
"hostnode": "b2ce5479-fa59-483f-86ba-0aa128051821",
"storage": 256,
"vcpus": 64,
"ram": 128
}
}
This request is comparatively complex because this provider's VM specifications and networking are configurable.
NOTE: Virtual machines can take up to 15 minutes to provision, especially for large RAM deployments. If you are getting a "Connection refused" error from ssh, it is best to wait a bit longer and try again.
Get VM status
You can retrieve the full list of your virtual machines with the following authenticated call.
GET https://api.valdi.ai/v1/vm
An example 200 OK response is:
{
"virtual_machines": [
{
"server": "5bebf874-05d9-49d7-a45f-801a702ac27c",
"ip": "2a0b:d40:0:4c::1",
"provider_id": "a45088e0-1681-446e-9a3e-3ed9dfc3d57e",
"ssh_key_id": "02a18443-93d1-4c86-92f9-65f90d129a74",
"name": "valdi-customer-Vlj!%k",
"user_provided_name": "api-docs-test",
"gpu_count": 1,
"gpu_model": "RTXA6000.1GPU",
"pretty_gpu_name": "RTX A6000 48GB",
"vcpus": 6,
"ram": 55,
"storage": 500,
"operating_system": "Ubuntu 20.04 LTS",
"port_forwards": "{\"22\": \"22\", \"443\": \"443\", \"80\": \"80\"}",
"all_inclusive": true,
"cpu_cost": null,
"ram_cost": null,
"storage_cost": null,
"gpu_cost": null,
"all_inclusive_running_cost": "0.830000000000",
"all_inclusive_stopped_cost": "0.130000000000",
"last_stopped_time": null,
"last_restarted_time": null,
"created_at": "2023-12-12T23:41:05.232767",
"status": "running"
},
{
"server": "52703e5e-347a-47af-bdf4-1ac8fbb9942e",
"ip": "217.79.242.232",
"provider_id": "66730e5d-98d2-45f6-8aaa-6ad8cdcbc285",
"ssh_key_id": null,
"name": "valdi-customer-li03lg",
"user_provided_name": "api-docs-test",
"gpu_count": 1,
"gpu_model": "v100-pcie-16gb",
"pretty_gpu_name": "V100 16GB",
"vcpus": 2,
"ram": 4,
"storage": 20,
"operating_system": "Ubuntu 20.04 LTS",
"port_forwards": "{\"60000\": \"22\"}",
"all_inclusive": false,
"cpu_cost": "0.003500000000",
"ram_cost": "0.002500000000",
"storage_cost": "0.000100000000",
"gpu_cost": "0.292000000000",
"all_inclusive_running_cost": null,
"all_inclusive_stopped_cost": null,
"last_stopped_time": null,
"last_restarted_time": null,
"created_at": "2023-12-12T23:40:28.217619",
"status": "running"
}
]
}
Note that different fields are null
depending on the provider.
You can get the status of specific VMs by appending the VM ID to the path of the GET
call. For example,
GET /v1/vm/52703e5e-347a-47af-bdf4-1ac8fbb9942e
would return only the second entry in the list above.
Stop a VM
To stop (i.e., temporarily turn off) your VM but retain your locally stored data, use the following authenticated endpoint.
POST https://api.valdi.ai/v1/vm/stop/{server_id}
Upon success, you will get the following 200 OK response:
{
"message": "success"
}
For VMs from Provider ID a45088e0, the cost of the VM while stopped will be 13-16% of the cost while running. Your data will be retained, and you can restart the VM at any time.
For VMs from Provider ID 66730e5d, you will only pay for the amount of storage you assigned to the VM. Your data will be retained, but you are not guaranteed to be able to restart the VM at any time. (If all GPUs attached to your physical server are rented out while your VM is stopped, you will have to wait until at least one GPU becomes available again.)
Start a VM
To start a VM that had been stopped, use the following authenticated endpoint.
POST https://api.valdi.ai/v1/vm/start/{server_id}
Upon success, you will get the following 200 OK response:
{
"message": "success"
}
It may take a few minutes for your VM to come online and be accessible again.
Terminate a VM
To permanently delete a VM, use the following command. The VM can be either in a running or stopped state.
POST https://api.valdi.ai/v1/vm/destroy/{server_id}
Upon success, you will get the following 200 OK response:
{
"message": "success"
}