diff --git a/src/client/cmdTemplate/templateDel.go b/src/client/cmdTemplate/templateDel.go
index feb619ddfb71ac021a6587932b01b67b50e0e423..b6522fe0a630353d0ebc985edf5b8fba065492a0 100644
--- a/src/client/cmdTemplate/templateDel.go
+++ b/src/client/cmdTemplate/templateDel.go
@@ -37,7 +37,6 @@ func (cmd *Del) Run(args []string) int {
 	}
 
 	tplID := args[0]
-
 	err := libclient.TemplateDel(tplID)
 	if err != nil {
 		u.PrintlnErr(err)
diff --git a/src/client/cmdVM/helper.go b/src/client/cmdVM/helper.go
index 5ffd553a4b422fead99b806554a03af7320edda4..a20df134f367b89efb5e60984fafe8d05e58f55a 100644
--- a/src/client/cmdVM/helper.go
+++ b/src/client/cmdVM/helper.go
@@ -1,20 +1,19 @@
 package cmdVM
 
 import (
-	"encoding/json"
 	"errors"
 	"nexus-client/cmd"
 	u "nexus-client/utils"
 	"nexus-common/vm"
-	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 	"regexp"
 	"strings"
 
-	"github.com/go-playground/validator/v10"
-	"github.com/go-resty/resty/v2"
 	"github.com/google/uuid"
 )
 
+type GetVMs func() ([]vm.VMNetworkSerialized, error)
+
 func printRegexUsage(c cmd.Command) {
 	for _, desc := range c.GetDesc() {
 		u.PrintlnErr(desc)
@@ -34,7 +33,7 @@ Regex examples:
 	u.PrintlnErr(usage)
 }
 
-// Returns a list of filtered VMs for a given route.
+// Returns a list of filtered VMs based on a regex.
 // Filters are based on patterns describing IDs or regexes.
 // Patterns can either be:
 // - any number of "VM IDs" (UUID)
@@ -46,14 +45,11 @@ Regex examples:
 //
 //	"."   -> matches everything
 //	"bla" -> matches any VM name containing "bla"
-func getFilteredVMs(route string, patterns []string) ([]vm.VMNetworkSerialized, error) {
+func getFilteredVMs(filteredVMsFunc GetVMs, patterns []string) ([]vm.VMNetworkSerialized, error) {
 	if len(patterns) < 1 {
 		return nil, errors.New("At least one ID or regex must be specified")
 	}
 
-	client := g.GetInstance().Client
-	host := g.GetInstance().Host
-
 	var ids []string
 	var regexes []string
 
@@ -66,47 +62,38 @@ func getFilteredVMs(route string, patterns []string) ([]vm.VMNetworkSerialized,
 		}
 	}
 
-	resp, err := client.R().Get(host + route)
+	vms, err := filteredVMsFunc()
 	if err != nil {
 		return nil, err
 	}
 
-	vmsList := []vm.VMNetworkSerialized{}
+	filteredVMs := []vm.VMNetworkSerialized{}
 
-	if resp.IsSuccess() {
-		vms, err := deserializeVMs(resp)
-		if err != nil {
-			return nil, err
+	for _, vm := range vms {
+		found := false
+		for _, id := range ids {
+			if id == vm.ID.String() {
+				filteredVMs = append(filteredVMs, vm)
+				found = true
+				break
+			}
 		}
-
-		for _, vm := range vms {
-			found := false
-			for _, id := range ids {
-				if id == vm.ID.String() {
-					vmsList = append(vmsList, vm)
-					found = true
+		if found {
+			continue
+		}
+		for _, regex := range regexes {
+			match, err := regexp.MatchString(strings.ToLower(regex), strings.ToLower(vm.Name))
+			if err != nil {
+				return nil, errors.New("Error matching \"" + regex + "\": " + err.Error())
+			} else {
+				if match {
+					filteredVMs = append(filteredVMs, vm)
 					break
 				}
 			}
-			if found {
-				continue
-			}
-			for _, regex := range regexes {
-				match, err := regexp.MatchString(strings.ToLower(regex), strings.ToLower(vm.Name))
-				if err != nil {
-					return nil, errors.New("Error matching \"" + regex + "\": " + err.Error())
-				} else {
-					if match {
-						vmsList = append(vmsList, vm)
-						break
-					}
-				}
-			}
 		}
-		return vmsList, nil
-	} else {
-		return nil, errors.New(resp.Status() + ": " + resp.String())
 	}
+	return filteredVMs, nil
 }
 
 // Returns a list of filtered VM credentials for a given route.
@@ -126,9 +113,6 @@ func getFilteredVMCredentials(route string, patterns []string) ([]vm.VMAttachCre
 		return nil, errors.New("At least one ID or regex must be specified")
 	}
 
-	client := g.GetInstance().Client
-	host := g.GetInstance().Host
-
 	var ids []string
 	var regexes []string
 
@@ -141,87 +125,36 @@ func getFilteredVMCredentials(route string, patterns []string) ([]vm.VMAttachCre
 		}
 	}
 
-	resp, err := client.R().Get(host + route)
+	vmAttachCreds, err := libclient.GetVMAttachCredentials()
 	if err != nil {
 		return nil, err
 	}
 
-	vmsList := []vm.VMAttachCredentialsSerialized{}
+	filteredVMAttachCreds := []vm.VMAttachCredentialsSerialized{}
 
-	if resp.IsSuccess() {
-		vms, err := deserializeVMsCredentials(resp)
-		if err != nil {
-			return nil, err
+	for _, vm := range vmAttachCreds {
+		found := false
+		for _, id := range ids {
+			if id == vm.ID.String() {
+				filteredVMAttachCreds = append(filteredVMAttachCreds, vm)
+				found = true
+				break
+			}
 		}
-
-		for _, vm := range vms {
-			found := false
-			for _, id := range ids {
-				if id == vm.ID.String() {
-					vmsList = append(vmsList, vm)
-					found = true
+		if found {
+			continue
+		}
+		for _, regex := range regexes {
+			match, err := regexp.MatchString(strings.ToLower(regex), strings.ToLower(vm.Name))
+			if err != nil {
+				return nil, errors.New("Error matching \"" + regex + "\": " + err.Error())
+			} else {
+				if match {
+					filteredVMAttachCreds = append(filteredVMAttachCreds, vm)
 					break
 				}
 			}
-			if found {
-				continue
-			}
-			for _, regex := range regexes {
-				match, err := regexp.MatchString(strings.ToLower(regex), strings.ToLower(vm.Name))
-				if err != nil {
-					return nil, errors.New("Error matching \"" + regex + "\": " + err.Error())
-				} else {
-					if match {
-						vmsList = append(vmsList, vm)
-						break
-					}
-				}
-			}
 		}
-		return vmsList, nil
-	} else {
-		return nil, errors.New(resp.Status() + ": " + resp.String())
-	}
-}
-
-// Deserialize a list of VMs from an http response.
-func deserializeVMs(resp *resty.Response) ([]vm.VMNetworkSerialized, error) {
-	vms := []vm.VMNetworkSerialized{}
-	if err := json.Unmarshal(resp.Body(), &vms); err != nil {
-		return nil, err
-	}
-	return vms, nil
-}
-
-// Deserialize a single VM from an http response.
-func deserializeVM(resp *resty.Response) (*vm.VMNetworkSerialized, error) {
-	var vm *vm.VMNetworkSerialized = &vm.VMNetworkSerialized{}
-	if err := json.Unmarshal(resp.Body(), vm); err != nil {
-		return vm, err
-	}
-	if err := validator.New(validator.WithRequiredStructEnabled()).Struct(vm); err != nil {
-		return nil, err
-	}
-	return vm, nil
-}
-
-// Deserialize a list of VM credentials from an http response.
-func deserializeVMsCredentials(resp *resty.Response) ([]vm.VMAttachCredentialsSerialized, error) {
-	vmsCreds := []vm.VMAttachCredentialsSerialized{}
-	if err := json.Unmarshal(resp.Body(), &vmsCreds); err != nil {
-		return nil, err
-	}
-	return vmsCreds, nil
-}
-
-// Deserialize a VM credentials from an http response.
-func deserializeVMCredentials(resp *resty.Response) (*vm.VMAttachCredentialsSerialized, error) {
-	var vmCreds vm.VMAttachCredentialsSerialized
-	if err := json.Unmarshal(resp.Body(), &vmCreds); err != nil {
-		return nil, err
-	}
-	if err := validator.New(validator.WithRequiredStructEnabled()).Struct(vmCreds); err != nil {
-		return nil, err
 	}
-	return &vmCreds, nil
+	return filteredVMAttachCreds, nil
 }
diff --git a/src/client/cmdVM/vmAddAccess.go b/src/client/cmdVM/vmAddAccess.go
index d53c59dc1397f8a4525bb7d9f13fd608824f672a..f5a9f13b5c1187093bba3dc11616fbd2f065c2ef 100644
--- a/src/client/cmdVM/vmAddAccess.go
+++ b/src/client/cmdVM/vmAddAccess.go
@@ -9,6 +9,7 @@ import (
 	"nexus-common/caps"
 	"nexus-common/params"
 	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 	"os"
 	"strings"
 )
@@ -138,7 +139,7 @@ func (cmd *AddAccess) Run(args []string) int {
 			return 1
 		}
 
-		vms, err := getFilteredVMs("/vms/editaccess", patterns)
+		vms, err := getFilteredVMs(libclient.GetEditAccessVMs, patterns)
 		if err != nil {
 			u.PrintlnErr(err.Error())
 			return 1
diff --git a/src/client/cmdVM/vmAttachAsyncSingle.go b/src/client/cmdVM/vmAttachAsyncSingle.go
index f088d1ed721c3c2f8228ac13c585ae3dc630c839..0f2a5f242ff962b637a455dbfa80bb808efe9a38 100644
--- a/src/client/cmdVM/vmAttachAsyncSingle.go
+++ b/src/client/cmdVM/vmAttachAsyncSingle.go
@@ -4,7 +4,7 @@ import (
 	"nexus-client/exec"
 	u "nexus-client/utils"
 	"nexus-common/vm"
-	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 )
 
 type AttachAsyncSingle struct {
@@ -42,31 +42,18 @@ func (cmd *AttachAsyncSingle) Run(args []string) int {
 		return 1
 	}
 
-	client := g.GetInstance().Client
-	host := g.GetInstance().Host
-
 	vmID := args[0]
-	resp, err := client.R().Get(host + "/vms/" + vmID + "/attach")
+
+	creds, err := libclient.VMAttach(vmID)
 	if err != nil {
 		u.PrintlnErr("Failed retrieving VM credentials for VM \"" + vmID + "\": " + err.Error())
 		return 1
-	} else {
-		if resp.IsSuccess() {
-			creds, err := deserializeVMCredentials(resp)
-			if err != nil {
-				u.PrintlnErr("Failed retrieving server's response: " + err.Error())
-				return 1
-			}
-			statusCode, err := AttachToVMs([]vm.VMAttachCredentialsSerialized{*creds}, false)
-			if err != nil {
-				u.PrintlnErr(err)
-			}
-			return statusCode
-		} else {
-			u.PrintlnErr("Failed retrieving VM credentials for VM \"" + vmID + "\": " + resp.Status() + ": " + resp.String())
-			return 1
-		}
 	}
 
-	return 0
+	statusCode, err := AttachToVMs([]vm.VMAttachCredentialsSerialized{*creds}, false)
+	if err != nil {
+		u.PrintlnErr(err)
+		return 1
+	}
+	return statusCode
 }
diff --git a/src/client/cmdVM/vmCreate.go b/src/client/cmdVM/vmCreate.go
index 38198dcd67fe1575fea4eb26c50a1ac74914e740..073a453f45b92e3f5892fe19f313276555459320 100644
--- a/src/client/cmdVM/vmCreate.go
+++ b/src/client/cmdVM/vmCreate.go
@@ -5,7 +5,7 @@ import (
 	u "nexus-client/utils"
 	"nexus-common/params"
 	"nexus-common/vm"
-	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 	"strconv"
 
 	"github.com/google/uuid"
@@ -49,9 +49,6 @@ file.csv    1-column CSV file defining the students names.
 }
 
 func (cmd *Create) Run(args []string) int {
-	client := g.GetInstance().Client
-	host := g.GetInstance().Host
-
 	argc := len(args)
 	if argc < 6 || argc > 7 {
 		cmd.PrintUsage()
@@ -103,7 +100,7 @@ func (cmd *Create) Run(args []string) int {
 	// if csvFile == "" -> we must create count VMs
 	// otherwise -> we parse the CSV to know how many VMs to create
 
-	vmArgs := &params.VMCreate{
+	vmArgs := params.VMCreate{
 		Name:       name,
 		Cpus:       ncpus,
 		Ram:        ram,
@@ -125,22 +122,12 @@ func (cmd *Create) Run(args []string) int {
 			vmArgs.Name = name + " " + csvEntries[i-1]
 		}
 
-		resp, err := client.R().SetBody(vmArgs).Post(host + "/vms")
+		vm, err := libclient.VMCreate(vmArgs)
 		if err != nil {
-			u.PrintlnErr("Failed creating VM \"" + vmArgs.Name + "\": " + err.Error())
+			u.PrintlnErr(err)
 			statusCode = 1
 		} else {
-			if resp.IsSuccess() {
-				vm, err := deserializeVM(resp)
-				if err != nil {
-					u.PrintlnErr("Failed retrieving server's response: " + err.Error())
-					statusCode = 1
-				}
-				u.Println("Created VM \"" + vm.Name + "\" | " + vm.ID.String())
-			} else {
-				u.PrintlnErr("Failed creating VM \"" + vmArgs.Name + "\": " + resp.Status() + ": " + resp.String())
-				statusCode = 1
-			}
+			u.Println("Created VM \"" + vm.Name + "\" | " + vm.ID.String())
 		}
 	}
 
diff --git a/src/client/cmdVM/vmDel.go b/src/client/cmdVM/vmDel.go
index 5251c0f8f50a69c5050c6026910f6c22d1d41039..68caed12f4ffd4684484392e492eeadf5c7c54fb 100644
--- a/src/client/cmdVM/vmDel.go
+++ b/src/client/cmdVM/vmDel.go
@@ -2,7 +2,7 @@ package cmdVM
 
 import (
 	u "nexus-client/utils"
-	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 )
 
 type Del struct {
@@ -25,16 +25,13 @@ func (cmd *Del) PrintUsage() {
 }
 
 func (cmd *Del) Run(args []string) int {
-	client := g.GetInstance().Client
-	host := g.GetInstance().Host
-
 	argc := len(args)
 	if argc < 1 {
 		cmd.PrintUsage()
 		return 1
 	}
 
-	vms, err := getFilteredVMs("/vms/del", args)
+	vms, err := getFilteredVMs(libclient.GetDelVMs, args)
 	if err != nil {
 		u.PrintlnErr(err.Error())
 		return 1
@@ -45,24 +42,15 @@ func (cmd *Del) Run(args []string) int {
 		return 1
 	}
 
-	statusCode := 0
-
 	for _, vm := range vms {
-		uuid := vm.ID.String()
-		resp, err := client.R().Delete(host + "/vms/" + uuid)
+
+		err := libclient.VMDel(vm.ID.String())
 		if err != nil {
-			u.PrintlnErr("Failed deleting VM \"" + vm.Name + "\": " + err.Error())
-			statusCode = 1
-		} else {
-			if resp.IsSuccess() {
-				u.Println("Deleted VM \"" + vm.Name + "\"")
-			} else {
-				u.PrintlnErr("Failed deleting VM \"" + vm.Name + "\": " + resp.Status() + ": " + resp.String())
-				statusCode = 1
-			}
+			u.PrintlnErr(err)
+			return 1
 		}
-
+		u.Println("Deleted VM \"" + vm.Name + "\"")
 	}
 
-	return statusCode
+	return 0
 }
diff --git a/src/client/cmdVM/vmDelAccess.go b/src/client/cmdVM/vmDelAccess.go
index c830076c842276134409766c75f72a18a7449cd5..ee61f45a0e25f836742a7714aeaa991563fe13be 100644
--- a/src/client/cmdVM/vmDelAccess.go
+++ b/src/client/cmdVM/vmDelAccess.go
@@ -7,6 +7,7 @@ import (
 	"net/mail"
 	u "nexus-client/utils"
 	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 	"os"
 )
 
@@ -106,7 +107,7 @@ func (cmd *DelAccess) Run(args []string) int {
 			return 1
 		}
 
-		vms, err := getFilteredVMs("/vms/editaccess", patterns)
+		vms, err := getFilteredVMs(libclient.GetEditAccessVMs, patterns)
 		if err != nil {
 			u.PrintlnErr(err.Error())
 			return 1
diff --git a/src/client/cmdVM/vmEdit.go b/src/client/cmdVM/vmEdit.go
index 0a1cf1ae8322c7222e7fbf05bfc619727e6b5b6a..13055fbcbcc7dfb014d5b69ab61f17e4bc8a9d20 100644
--- a/src/client/cmdVM/vmEdit.go
+++ b/src/client/cmdVM/vmEdit.go
@@ -6,6 +6,7 @@ import (
 	"nexus-common/params"
 	"nexus-common/vm"
 	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 	"strconv"
 	"strings"
 )
@@ -65,7 +66,7 @@ func (cmd *Edit) Run(args []string) int {
 		return 1
 	}
 
-	vms, err := getFilteredVMs("/vms/edit", patterns)
+	vms, err := getFilteredVMs(libclient.GetEditVMs, patterns)
 	if err != nil {
 		u.PrintlnErr(err.Error())
 		return 1
diff --git a/src/client/cmdVM/vmExportDir.go b/src/client/cmdVM/vmExportDir.go
index 61b5521c8643cfdbcf43dc05028a9f29b1330fe7..cb3f4562be37b8261138ea29bd3d0d3e37b4005c 100644
--- a/src/client/cmdVM/vmExportDir.go
+++ b/src/client/cmdVM/vmExportDir.go
@@ -4,6 +4,7 @@ import (
 	u "nexus-client/utils"
 	"nexus-common/params"
 	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 )
 
 type ExportDir struct {
@@ -46,9 +47,9 @@ func (cmd *ExportDir) Run(args []string) int {
 
 	dir := args[argc-1]
 
-	vms, err := getFilteredVMs("/vms/exportdir", args[:argc-1])
+	vms, err := getFilteredVMs(libclient.GetExportDirVMs, args[:argc-1])
 	if err != nil {
-		u.PrintlnErr("Error: " + err.Error())
+		u.PrintlnErr(err.Error())
 		return 1
 	}
 
diff --git a/src/client/cmdVM/vmImportDir.go b/src/client/cmdVM/vmImportDir.go
index 3e04a94454ae855488cd3739c9423c2d341f24eb..659fa4f09c10109de9691d51d702dd6ea8a335b0 100644
--- a/src/client/cmdVM/vmImportDir.go
+++ b/src/client/cmdVM/vmImportDir.go
@@ -3,6 +3,8 @@ package cmdVM
 import (
 	u "nexus-client/utils"
 	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
+
 	"os"
 )
 
@@ -48,9 +50,9 @@ func (cmd *ImportDir) Run(args []string) int {
 	vmDir := args[argc-1]
 	localDir := args[argc-2]
 
-	vms, err := getFilteredVMs("/vms/importfiles", args[:argc-2])
+	vms, err := getFilteredVMs(libclient.GetImportFileVMs, args[:argc-2])
 	if err != nil {
-		u.PrintlnErr("Error: " + err.Error())
+		u.PrintlnErr(err.Error())
 		return 1
 	}
 
diff --git a/src/client/cmdVM/vmList.go b/src/client/cmdVM/vmList.go
index ec0a7c3c36d3efd19e26dd1c31f564a483dd5b09..a2fa9de3dbe4442568354b87d9f64407f28dc866 100644
--- a/src/client/cmdVM/vmList.go
+++ b/src/client/cmdVM/vmList.go
@@ -3,6 +3,7 @@ package cmdVM
 import (
 	"fmt"
 	u "nexus-client/utils"
+	libclient "nexus-libclient/vm"
 )
 
 type List struct {
@@ -54,7 +55,7 @@ func (cmd *List) printFilteredVMs(args []string, route string) int {
 		args = u.RemoveArgAtIndex(args, foundLongOutputFlag)
 	}
 
-	vms, err := getFilteredVMs(route, args)
+	vms, err := getFilteredVMs(libclient.GetListVMs, args)
 	if err != nil {
 		u.PrintlnErr("Error: " + err.Error())
 		return 1
diff --git a/src/client/cmdVM/vmListSingle.go b/src/client/cmdVM/vmListSingle.go
index f8f35d5db841442ef2cd688064ec9b846f451b33..be8ef4b579d06466a55f3d4b5db6689a178bd234 100644
--- a/src/client/cmdVM/vmListSingle.go
+++ b/src/client/cmdVM/vmListSingle.go
@@ -2,7 +2,7 @@ package cmdVM
 
 import (
 	u "nexus-client/utils"
-	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 )
 
 type ListSingle struct {
@@ -29,9 +29,6 @@ func (cmd *ListSingle) PrintUsage() {
 }
 
 func (cmd *ListSingle) Run(args []string) int {
-	client := g.GetInstance().Client
-	host := g.GetInstance().Host
-
 	argc := len(args)
 	if argc < 1 {
 		cmd.PrintUsage()
@@ -39,28 +36,17 @@ func (cmd *ListSingle) Run(args []string) int {
 	}
 
 	vmID := args[0]
-	resp, err := client.R().Get(host + "/vms/" + vmID)
+	vm, err := libclient.GetListableVM(vmID)
 	if err != nil {
-		u.PrintlnErr("Failed retrieving VM \"" + vmID + "\": " + err.Error())
+		u.PrintlnErr(err)
 		return 1
-	} else {
-		if resp.IsSuccess() {
-			vm, err := deserializeVM(resp)
-			if err != nil {
-				u.PrintlnErr("Failed retrieving server's response: " + err.Error())
-				return 1
-			}
-			str, err := vm.String()
-			if err != nil {
-				u.PrintlnErr("Failed decoding VM " + vm.ID.String() + " to string. Skipped.")
-			} else {
-				u.Println(str)
-			}
-		} else {
-			u.PrintlnErr("Failed retrieving VM \"" + vmID + "\": " + resp.Status() + ": " + resp.String())
-			return 1
-		}
 	}
 
+	vmStr, err := vm.String()
+	if err != nil {
+		u.PrintlnErr(err)
+		return 1
+	}
+	u.Println(vmStr)
 	return 0
 }
diff --git a/src/client/cmdVM/vmReboot.go b/src/client/cmdVM/vmReboot.go
index 6faee7114f35d225683e395c15943ad99733eaa2..e62c57d1626db11b402bda7b0f0a31ceab52d413 100644
--- a/src/client/cmdVM/vmReboot.go
+++ b/src/client/cmdVM/vmReboot.go
@@ -1,8 +1,9 @@
 package cmdVM
 
 import (
+	libclient "nexus-libclient/vm"
+
 	u "nexus-client/utils"
-	g "nexus-libclient/globals"
 )
 
 type Reboot struct {
@@ -25,16 +26,13 @@ func (cmd *Reboot) PrintUsage() {
 }
 
 func (cmd *Reboot) Run(args []string) int {
-	client := g.GetInstance().Client
-	host := g.GetInstance().Host
-
 	argc := len(args)
 	if argc < 1 {
 		cmd.PrintUsage()
 		return 1
 	}
 
-	vms, err := getFilteredVMs("/vms/reboot", args)
+	vms, err := getFilteredVMs(libclient.GetRebootVMs, args)
 	if err != nil {
 		u.PrintlnErr(err.Error())
 		return 1
@@ -45,24 +43,15 @@ func (cmd *Reboot) Run(args []string) int {
 		return 1
 	}
 
-	statusCode := 0
-
 	for _, vm := range vms {
-		uuid := vm.ID.String()
-		resp, err := client.R().Put(host + "/vms/" + uuid + "/reboot")
+		err := libclient.VMReboot(vm.ID.String())
 		if err != nil {
-			u.PrintlnErr("Reboot failed for VM \"" + vm.Name + "\": " + err.Error())
-			statusCode = 1
-		} else {
-			if resp.IsSuccess() {
-				u.Println("Sent reboot message to VM \"" + vm.Name + "\"")
-			} else {
-				u.PrintlnErr("Reboot failed for VM \"" + vm.Name + "\": " + resp.Status() + ": " + resp.String())
-				statusCode = 1
-			}
+			u.PrintlnErr(err)
+			return 1
 		}
+		u.Println("Sent reboot message to VM \"" + vm.Name + "\"")
 
 	}
 
-	return statusCode
+	return 0
 }
diff --git a/src/client/cmdVM/vmShutdown.go b/src/client/cmdVM/vmShutdown.go
index e7108cb54a549c4a7e5f780bf3b5650cc2f4e232..da07af9f1b57084d3ad853482c4837c46be9b6c2 100644
--- a/src/client/cmdVM/vmShutdown.go
+++ b/src/client/cmdVM/vmShutdown.go
@@ -3,6 +3,7 @@ package cmdVM
 import (
 	u "nexus-client/utils"
 	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 )
 
 type Shutdown struct {
@@ -34,7 +35,7 @@ func (cmd *Shutdown) Run(args []string) int {
 		return 1
 	}
 
-	vms, err := getFilteredVMs("/vms/stop", args)
+	vms, err := getFilteredVMs(libclient.GetStopVMs, args)
 	if err != nil {
 		u.PrintlnErr(err.Error())
 		return 1
diff --git a/src/client/cmdVM/vmStart.go b/src/client/cmdVM/vmStart.go
index f556b3a3107e5a02e1ff7bac98b76f091e41e5c2..bf11948bef514a364404e4c94da705e6a2dcba48 100644
--- a/src/client/cmdVM/vmStart.go
+++ b/src/client/cmdVM/vmStart.go
@@ -3,6 +3,7 @@ package cmdVM
 import (
 	u "nexus-client/utils"
 	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 )
 
 type Start struct {
@@ -34,7 +35,7 @@ func (cmd *Start) Run(args []string) int {
 		return 1
 	}
 
-	vms, err := getFilteredVMs("/vms/start", args)
+	vms, err := getFilteredVMs(libclient.GetStartVMs, args)
 	if err != nil {
 		u.PrintlnErr(err.Error())
 		return 1
diff --git a/src/client/cmdVM/vmStartAttach.go b/src/client/cmdVM/vmStartAttach.go
index b684f0671439e2b0c97a2204680f696c8dba4ffa..49b9a8790bc3c3719696f8af234de7363b6af366 100644
--- a/src/client/cmdVM/vmStartAttach.go
+++ b/src/client/cmdVM/vmStartAttach.go
@@ -4,6 +4,7 @@ import (
 	"nexus-client/exec"
 	u "nexus-client/utils"
 	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 )
 
 type StartAttach struct {
@@ -41,7 +42,7 @@ func (cmd *StartAttach) Run(args []string) int {
 		return 1
 	}
 
-	vms, err := getFilteredVMs("/vms/start", args)
+	vms, err := getFilteredVMs(libclient.GetStartVMs, args)
 	if err != nil {
 		u.PrintlnErr(err.Error())
 		return 1
diff --git a/src/client/cmdVM/vmStop.go b/src/client/cmdVM/vmStop.go
index 01d441ce9e6759dc75dd669d2f4486c9cb83c014..22f86d7b5b2f88e14240e250c99c9ce42a951273 100644
--- a/src/client/cmdVM/vmStop.go
+++ b/src/client/cmdVM/vmStop.go
@@ -2,7 +2,7 @@ package cmdVM
 
 import (
 	u "nexus-client/utils"
-	g "nexus-libclient/globals"
+	libclient "nexus-libclient/vm"
 )
 
 type Stop struct {
@@ -25,16 +25,13 @@ func (cmd *Stop) PrintUsage() {
 }
 
 func (cmd *Stop) Run(args []string) int {
-	client := g.GetInstance().Client
-	host := g.GetInstance().Host
-
 	argc := len(args)
 	if argc < 1 {
 		cmd.PrintUsage()
 		return 1
 	}
 
-	vms, err := getFilteredVMs("/vms/stop", args)
+	vms, err := getFilteredVMs(libclient.GetStopVMs, args)
 	if err != nil {
 		u.PrintlnErr(err.Error())
 		return 1
@@ -45,24 +42,14 @@ func (cmd *Stop) Run(args []string) int {
 		return 1
 	}
 
-	statusCode := 0
-
 	for _, vm := range vms {
-		uuid := vm.ID.String()
-		resp, err := client.R().Put(host + "/vms/" + uuid + "/stop")
+		err := libclient.VMStop(vm.ID.String())
 		if err != nil {
-			u.PrintlnErr("Failed stopping VM \"" + vm.Name + "\": " + err.Error())
-			statusCode = 1
-		} else {
-			if resp.IsSuccess() {
-				u.Println("Stopped VM \"" + vm.Name + "\"")
-			} else {
-				u.PrintlnErr("Failed stopping VM \"" + vm.Name + "\": " + resp.Status() + ": " + resp.String())
-				statusCode = 1
-			}
+			u.PrintlnErr(err)
+			return 1
 		}
-
+		u.Println("Stopped VM \"" + vm.Name + "\"")
 	}
 
-	return statusCode
+	return 0
 }
diff --git a/src/libclient/go.mod b/src/libclient/go.mod
index b1824aedfc566dae19c23ae79995cdbc8ca6e982..14915045c7c5d748b5efc1087ea1361c28d6c10a 100644
--- a/src/libclient/go.mod
+++ b/src/libclient/go.mod
@@ -3,3 +3,7 @@ module nexus-libclient
 go 1.22.0
 
 replace nexus-common => ../common
+
+require nexus-common v0.0.0-00010101000000-000000000000
+
+require github.com/google/uuid v1.6.0 // indirect
diff --git a/src/libclient/template/helper.go b/src/libclient/template/deserializer.go
similarity index 100%
rename from src/libclient/template/helper.go
rename to src/libclient/template/deserializer.go
diff --git a/src/libclient/user/helper.go b/src/libclient/user/deserializer.go
similarity index 100%
rename from src/libclient/user/helper.go
rename to src/libclient/user/deserializer.go
diff --git a/src/libclient/vm/deserializer.go b/src/libclient/vm/deserializer.go
new file mode 100644
index 0000000000000000000000000000000000000000..36ac137733861178efbbfa12aafddf3832e85156
--- /dev/null
+++ b/src/libclient/vm/deserializer.go
@@ -0,0 +1,51 @@
+package vm
+
+import (
+	"encoding/json"
+	"nexus-common/vm"
+
+	"github.com/go-playground/validator/v10"
+	"github.com/go-resty/resty/v2"
+)
+
+// Deserialize a list of VMs from an http response.
+func deserializeVMs(resp *resty.Response) ([]vm.VMNetworkSerialized, error) {
+	vms := []vm.VMNetworkSerialized{}
+	if err := json.Unmarshal(resp.Body(), &vms); err != nil {
+		return nil, err
+	}
+	return vms, nil
+}
+
+// Deserialize a single VM from an http response.
+func deserializeVM(resp *resty.Response) (*vm.VMNetworkSerialized, error) {
+	vm := vm.VMNetworkSerialized{}
+	if err := json.Unmarshal(resp.Body(), &vm); err != nil {
+		return nil, err
+	}
+	if err := validator.New(validator.WithRequiredStructEnabled()).Struct(vm); err != nil {
+		return nil, err
+	}
+	return &vm, nil
+}
+
+// Deserialize a list of VM credentials from an http response.
+func deserializeVMsCredentials(resp *resty.Response) ([]vm.VMAttachCredentialsSerialized, error) {
+	vmsCreds := []vm.VMAttachCredentialsSerialized{}
+	if err := json.Unmarshal(resp.Body(), &vmsCreds); err != nil {
+		return nil, err
+	}
+	return vmsCreds, nil
+}
+
+// Deserialize a VM credentials from an http response.
+func deserializeVMCredentials(resp *resty.Response) (*vm.VMAttachCredentialsSerialized, error) {
+	var vmCreds vm.VMAttachCredentialsSerialized
+	if err := json.Unmarshal(resp.Body(), &vmCreds); err != nil {
+		return nil, err
+	}
+	if err := validator.New(validator.WithRequiredStructEnabled()).Struct(vmCreds); err != nil {
+		return nil, err
+	}
+	return &vmCreds, nil
+}
diff --git a/src/libclient/vm/vmAttach.go b/src/libclient/vm/vmAttach.go
new file mode 100644
index 0000000000000000000000000000000000000000..113fb68276e3f4f511267661679db37b8d9e40c8
--- /dev/null
+++ b/src/libclient/vm/vmAttach.go
@@ -0,0 +1,27 @@
+package vm
+
+import (
+	"nexus-common/vm"
+	g "nexus-libclient/globals"
+	"nexus-libclient/response"
+)
+
+func VMAttach(vmID string) (*vm.VMAttachCredentialsSerialized, error) {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	resp, err := client.R().Get(host + "/vms/" + vmID + "/attach")
+	if err != nil {
+		return nil, err
+	}
+
+	if resp.IsSuccess() {
+		vmCreds, err := deserializeVMCredentials(resp)
+		if err != nil {
+			return nil, err
+		}
+		return vmCreds, nil
+	} else {
+		return nil, response.ErrorToMsg(resp)
+	}
+}
diff --git a/src/libclient/vm/vmAttachCredentials.go b/src/libclient/vm/vmAttachCredentials.go
new file mode 100644
index 0000000000000000000000000000000000000000..445865672d1a5ef69e6c64b253f87f91ab4e8bfd
--- /dev/null
+++ b/src/libclient/vm/vmAttachCredentials.go
@@ -0,0 +1,27 @@
+package vm
+
+import (
+	"nexus-common/vm"
+	g "nexus-libclient/globals"
+	"nexus-libclient/response"
+)
+
+func GetVMAttachCredentials() ([]vm.VMAttachCredentialsSerialized, error) {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	resp, err := client.R().Get(host + "/vms/attach")
+	if err != nil {
+		return nil, err
+	}
+
+	if resp.IsSuccess() {
+		vmCreds, err := deserializeVMsCredentials(resp)
+		if err != nil {
+			return nil, err
+		}
+		return vmCreds, nil
+	} else {
+		return nil, response.ErrorToMsg(resp)
+	}
+}
diff --git a/src/libclient/vm/vmCreate.go b/src/libclient/vm/vmCreate.go
new file mode 100644
index 0000000000000000000000000000000000000000..d9ebf4f533ac3b630e238cbac796e9df1753f10e
--- /dev/null
+++ b/src/libclient/vm/vmCreate.go
@@ -0,0 +1,28 @@
+package vm
+
+import (
+	"encoding/json"
+	"nexus-common/params"
+	"nexus-common/vm"
+	g "nexus-libclient/globals"
+	"nexus-libclient/response"
+)
+
+func VMCreate(p params.VMCreate) (*vm.VMNetworkSerialized, error) {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	resp, err := client.R().SetBody(p).Post(host + "/vms")
+	if err != nil {
+		return nil, err
+	}
+	if resp.IsSuccess() {
+		var vm vm.VMNetworkSerialized
+		if err := json.Unmarshal(resp.Body(), &vm); err != nil {
+			return nil, err
+		}
+		return &vm, nil
+	} else {
+		return nil, response.ErrorToMsg(resp)
+	}
+}
diff --git a/src/libclient/vm/vmDel.go b/src/libclient/vm/vmDel.go
new file mode 100644
index 0000000000000000000000000000000000000000..086b4f74f38e5f7d08192852a248e3a30a5faaef
--- /dev/null
+++ b/src/libclient/vm/vmDel.go
@@ -0,0 +1,21 @@
+package vm
+
+import (
+	g "nexus-libclient/globals"
+	"nexus-libclient/response"
+)
+
+func VMDel(vmID string) error {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	resp, err := client.R().Delete(host + "/vms/" + vmID)
+	if err != nil {
+		return err
+	}
+	if resp.IsSuccess() {
+		return nil
+	} else {
+		return response.ErrorToMsg(resp)
+	}
+}
diff --git a/src/libclient/vm/vmGet.go b/src/libclient/vm/vmGet.go
new file mode 100644
index 0000000000000000000000000000000000000000..2b2eaf3de2ed665cd83736ff8dda71ba0b529c08
--- /dev/null
+++ b/src/libclient/vm/vmGet.go
@@ -0,0 +1,100 @@
+package vm
+
+import (
+	"nexus-common/vm"
+	g "nexus-libclient/globals"
+	"nexus-libclient/response"
+)
+
+const (
+	attachVMs     = "/vms/attach"
+	delVMs        = "/vms/del"
+	editVMs       = "/vms/edit"
+	editaccessVMs = "/vms/editaccess"
+	exportdirVMs  = "/vms/exportdir"
+	importfileVMs = "/vms/importfiles"
+	listVMs       = "/vms"
+	rebootVMs     = "/vms/reboot"
+	startVMs      = "/vms/start"
+	stopVMs       = "/vms/stop"
+)
+
+func GetAttachVMs() ([]vm.VMNetworkSerialized, error) {
+	return getFilteredVMs(attachVMs)
+}
+
+func GetDelVMs() ([]vm.VMNetworkSerialized, error) {
+	return getFilteredVMs(delVMs)
+}
+
+func GetEditAccessVMs() ([]vm.VMNetworkSerialized, error) {
+	return getFilteredVMs(editaccessVMs)
+}
+
+func GetEditVMs() ([]vm.VMNetworkSerialized, error) {
+	return getFilteredVMs(editVMs)
+}
+
+func GetExportDirVMs() ([]vm.VMNetworkSerialized, error) {
+	return getFilteredVMs(exportdirVMs)
+}
+
+func GetImportFileVMs() ([]vm.VMNetworkSerialized, error) {
+	return getFilteredVMs(importfileVMs)
+}
+
+func GetListVMs() ([]vm.VMNetworkSerialized, error) {
+	return getFilteredVMs(listVMs)
+}
+
+func GetRebootVMs() ([]vm.VMNetworkSerialized, error) {
+	return getFilteredVMs(rebootVMs)
+}
+
+func GetStartVMs() ([]vm.VMNetworkSerialized, error) {
+	return getFilteredVMs(startVMs)
+}
+
+func GetStopVMs() ([]vm.VMNetworkSerialized, error) {
+	return getFilteredVMs(stopVMs)
+}
+
+func getFilteredVMs(route string) ([]vm.VMNetworkSerialized, error) {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	resp, err := client.R().Get(host + route)
+	if err != nil {
+		return nil, err
+	}
+
+	if resp.IsSuccess() {
+		templates, err := deserializeVMs(resp)
+		if err != nil {
+			return nil, err
+		}
+		return templates, nil
+	} else {
+		return nil, response.ErrorToMsg(resp)
+	}
+}
+
+func GetListableVM(uuid string) (*vm.VMNetworkSerialized, error) {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	resp, err := client.R().Get(host + "/vms/" + uuid)
+	if err != nil {
+		return nil, err
+	}
+
+	if resp.IsSuccess() {
+		template, err := deserializeVM(resp)
+		if err != nil {
+			return nil, err
+		}
+		return template, nil
+	} else {
+		return nil, response.ErrorToMsg(resp)
+	}
+}
diff --git a/src/libclient/vm/vmReboot.go b/src/libclient/vm/vmReboot.go
new file mode 100644
index 0000000000000000000000000000000000000000..adb1d7e32df3ef5675efe767beb3e1fe8a201934
--- /dev/null
+++ b/src/libclient/vm/vmReboot.go
@@ -0,0 +1,21 @@
+package vm
+
+import (
+	g "nexus-libclient/globals"
+	"nexus-libclient/response"
+)
+
+func VMReboot(vmID string) error {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	resp, err := client.R().Put(host + "/vms/" + vmID + "/reboot")
+	if err != nil {
+		return err
+	}
+	if resp.IsSuccess() {
+		return nil
+	} else {
+		return response.ErrorToMsg(resp)
+	}
+}
diff --git a/src/libclient/vm/vmStop.go b/src/libclient/vm/vmStop.go
new file mode 100644
index 0000000000000000000000000000000000000000..9c735c597de867a0d25b5fb32df411b728269447
--- /dev/null
+++ b/src/libclient/vm/vmStop.go
@@ -0,0 +1,21 @@
+package vm
+
+import (
+	g "nexus-libclient/globals"
+	"nexus-libclient/response"
+)
+
+func VMStop(vmID string) error {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	resp, err := client.R().Put(host + "/vms/" + vmID + "/stop")
+	if err != nil {
+		return err
+	}
+	if resp.IsSuccess() {
+		return nil
+	} else {
+		return response.ErrorToMsg(resp)
+	}
+}