diff --git a/app/app.go b/app/app.go
index ddae517..562fcfd 100644
--- a/app/app.go
+++ b/app/app.go
@@ -5,12 +5,14 @@ import (
 	"flag"
 	"fmt"
 	"log"
-	"time"
+	"net/http"
+	"strconv"
 
+	"github.com/gin-gonic/gin"
 	"github.com/luthermonson/go-proxmox"
 )
 
-const APIVersion string = "0.0.1"
+const APIVersion string = "0.0.2"
 
 var client ProxmoxClient
 
@@ -26,36 +28,55 @@ func Run() {
 	token := fmt.Sprintf(`%s@%s!%s`, config.PVE.Token.USER, config.PVE.Token.REALM, config.PVE.Token.ID)
 	client = NewClient(token, config.PVE.Token.Secret)
 
-	//router := gin.Default()
+	router := gin.Default()
 
-	start := time.Now()
 	cluster := Cluster{}
 	cluster.Init(client)
 	cluster.Rebuild()
-	elapsed := time.Since(start)
 
-	fmt.Println(cluster)
-	fmt.Println(elapsed)
+	router.GET("/version", func(c *gin.Context) {
+		PVEVersion, err := client.Version()
+		if err != nil {
+			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+		} else {
+			c.JSON(http.StatusOK, gin.H{"api-version": APIVersion, "pve-version": PVEVersion})
+		}
+	})
 
-	/*
-		router.GET("/version", func(c *gin.Context) {
-			PVEVersion, err := client.Version()
-			if err != nil {
-				c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
+	router.GET("/nodes/:node", func(c *gin.Context) {
+		node := c.Param("node")
+		Host, ok := cluster.Hosts[node]
+		if !ok {
+			c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("%s not found in cluster", node)})
+			return
+		} else {
+			c.JSON(http.StatusOK, gin.H{"node": Host})
+			return
+		}
+	})
+
+	router.GET("/nodes/:node/instances/:instance", func(c *gin.Context) {
+		host := c.Param("node")
+		vmid, err := strconv.ParseUint(c.Param("instance"), 10, 64)
+		if err != nil {
+			c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("%s could not be converted to vmid (uint)", c.Param("instance"))})
+			return
+		}
+		Node, ok := cluster.Hosts[host]
+		if !ok {
+			c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("vmid %s not found in cluster", host)})
+			return
+		} else {
+			Instance, ok := Node.Instances[uint(vmid)]
+			if !ok {
+				c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("%d not found in %s", vmid, host)})
+				return
 			} else {
-				c.JSON(http.StatusOK, gin.H{"api-version": APIVersion, "pve-version": PVEVersion})
+				c.JSON(http.StatusOK, gin.H{"instance": Instance})
+				return
 			}
-		})
+		}
+	})
 
-		router.GET("/nodes/:node", func(c *gin.Context) {
-			Node, err := client.Node(c.Param("node"))
-			if err != nil {
-				c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
-			} else {
-				c.JSON(http.StatusOK, gin.H{"node": Node})
-			}
-		})
-
-		router.Run("0.0.0.0:" + strconv.Itoa(config.ListenPort))
-	*/
+	router.Run("0.0.0.0:" + strconv.Itoa(config.ListenPort))
 }
diff --git a/app/model.go b/app/model.go
index ae73d1a..67c27d9 100644
--- a/app/model.go
+++ b/app/model.go
@@ -9,7 +9,6 @@ import (
 type Cluster struct {
 	pve   ProxmoxClient
 	Hosts map[string]*Host
-	//Instance map[uint]*Instance
 }
 
 func (cluster *Cluster) Init(pve ProxmoxClient) {
@@ -77,7 +76,7 @@ func (host *Host) RebuildVM(vmid uint) error {
 		return err
 	}
 
-	host.Instance[vmid] = &instance
+	host.Instances[vmid] = &instance
 
 	for volid := range instance.configDisks {
 		instance.RebuildVolume(host, volid)
@@ -100,7 +99,7 @@ func (host *Host) RebuildCT(vmid uint) error {
 		return err
 	}
 
-	host.Instance[vmid] = &instance
+	host.Instances[vmid] = &instance
 
 	for volid := range instance.configDisks {
 		instance.RebuildVolume(host, volid)
@@ -121,7 +120,7 @@ func (instance *Instance) RebuildVolume(host *Host, volid string) error {
 		return err
 	}
 
-	instance.Volume[volid] = &volume
+	instance.Volumes[volid] = &volume
 
 	return nil
 }
@@ -138,7 +137,7 @@ func (instance *Instance) RebuildNet(netid string) error {
 		return nil
 	}
 
-	instance.Net[uint(idnum)] = &netinfo
+	instance.Nets[uint(idnum)] = &netinfo
 
 	return nil
 }
@@ -157,113 +156,20 @@ func (instance *Instance) RebuildDevice(host Host, deviceid string) error {
 	}
 
 	if DeviceBusIDIsSuperDevice(hostDeviceBusID) {
-		hostSuperDevice := host.Hardware[hostDeviceBusID]
-		subDevices := []*HostDevice{}
-		for _, v := range hostSuperDevice.Devices {
-			v.Reserved = true
-			subDevices = append(subDevices, v)
-		}
-		instance.Device[uint(instanceDeviceBusID)] = &InstanceDevice{
-			Device: subDevices,
-			PCIE:   strings.Contains(instanceDevice, "pcie=1"),
+		devices := []*Device{}
+		for k, v := range host.Devices {
+			if DeviceBusIDIsSubDevice(k, hostDeviceBusID) {
+				v.Reserved = true
+				devices = append(devices, v)
+			}
 		}
+		instance.Devices[uint(instanceDeviceBusID)] = devices
 	} else {
-		_, hostSubdeviceBusID, err := SplitDeviceBusID(hostDeviceBusID)
-		if err != nil {
-			return err
-		}
-		v := host.Hardware[hostDeviceBusID].Devices[hostSubdeviceBusID]
+		devices := []*Device{}
+		v := host.Devices[hostDeviceBusID]
 		v.Reserved = true
-		instance.Device[uint(instanceDeviceBusID)] = &InstanceDevice{
-			Device: []*HostDevice{v},
-			PCIE:   strings.Contains(instanceDevice, "pcie=1"),
-		}
+		instance.Devices[uint(instanceDeviceBusID)] = devices
 	}
 
 	return nil
 }
-
-func (cluster Cluster) String() string {
-	r := ""
-	for _, host := range cluster.Hosts {
-		r += host.String()
-	}
-	return r
-}
-
-func (host Host) String() string {
-	r := fmt.Sprintf("%s\n\tCores:\t%s\n\tMemory:\t%s\n\tSwap:\t%s\n", host.Name, host.Cores, host.Memory, host.Swap)
-
-	r += "\tHardware:\n"
-
-	for _, superdevice := range host.Hardware {
-		r += fmt.Sprintf("%s\n", superdevice)
-	}
-
-	r += "\tInstances:\n"
-
-	for vmid, vm := range host.Instance {
-		r += fmt.Sprintf("\t\t%d: %s\n", vmid, vm)
-	}
-
-	return r
-}
-
-func (r Resource) String() string {
-	return fmt.Sprintf("Totl: %d, Rsrv: %d, Free: %d", r.Total, r.Reserved, r.Free)
-}
-
-func (superdevice HostSuperDevice) String() string {
-	s := fmt.Sprintf("\t\t%s: %s %s -> ", superdevice.BusID, superdevice.VendorName, superdevice.DeviceName)
-	numunused := 0
-	for _, device := range superdevice.Devices {
-		if device.Reserved {
-			s += fmt.Sprintf("%s:(Rsrv %t, %s %s: %s %s)", device.SubID, device.Reserved, superdevice.VendorName, device.SubVendorName, superdevice.DeviceName, device.SubDeviceName)
-		} else {
-			numunused++
-		}
-	}
-	s += fmt.Sprintf("+%d unreserved subdevices", numunused)
-	return s
-}
-
-func (i Instance) String() string {
-	if i.Type == VM {
-		r := fmt.Sprintf("VM, Name: %s, Proctype: %s, Cores: %d, Memory: %d\n", i.Name, i.Proctype, i.Cores, i.Memory)
-		for k, v := range i.Volume {
-			r += fmt.Sprintf("\t\t\t%s: %s\n", k, v)
-		}
-		for k, v := range i.Net {
-			r += fmt.Sprintf("\t\t\tnet%d: %s\n", k, v)
-		}
-		for k, v := range i.Device {
-			r += fmt.Sprintf("\t\t\thostpci%d: %s\n", k, v)
-		}
-		return r
-	} else {
-		r := fmt.Sprintf("CT, Name: %s, Cores: %d, Memory: %d, Swap: %d\n", i.Name, i.Cores, i.Memory, i.Swap)
-		for k, v := range i.Volume {
-			r += fmt.Sprintf("\t\t\t%s: %s\n", k, v)
-		}
-		for k, v := range i.Net {
-			r += fmt.Sprintf("\t\t\tnet%d: %s\n", k, v)
-		}
-		return r
-	}
-}
-
-func (v Volume) String() string {
-	return fmt.Sprintf("id: %s, format: %s, size: %d", v.Volid, v.Format, v.Size)
-}
-
-func (n Net) String() string {
-	return fmt.Sprintf("rate: %d, vlan: %d", n.Rate, n.VLAN)
-}
-
-func (d InstanceDevice) String() string {
-	r := ""
-	for _, v := range d.Device {
-		r += fmt.Sprintf("%s:%s ", v.SubVendorName, v.SubDeviceName)
-	}
-	return r
-}
diff --git a/app/proxmox.go b/app/proxmox.go
index 603c06d..687ea7a 100644
--- a/app/proxmox.go
+++ b/app/proxmox.go
@@ -15,14 +15,6 @@ type ProxmoxClient struct {
 	client *proxmox.Client
 }
 
-type PVEDevice struct {
-	BusID               string `json:"id"`
-	DeviceName          string `json:"device_name"`
-	VendorName          string `json:"vendor_name"`
-	SubsystemDeviceName string `json:"subsystem_device_name"`
-	SubsystemVendorName string `json:"subsystem_vendor_name"`
-}
-
 func NewClient(token string, secret string) ProxmoxClient {
 	HTTPClient := http.Client{
 		Transport: &http.Transport{
@@ -67,44 +59,22 @@ func (pve ProxmoxClient) Nodes() ([]string, error) {
 // Gets a Node's resources but does not recursively expand instances
 func (pve ProxmoxClient) Node(nodeName string) (Host, error) {
 	host := Host{}
-	host.Hardware = make(map[string]*HostSuperDevice)
-	host.Instance = make(map[uint]*Instance)
+	host.Devices = make(map[string]*Device)
+	host.Instances = make(map[uint]*Instance)
 
 	node, err := pve.client.Node(context.Background(), nodeName)
 	if err != nil {
 		return host, err
 	}
 
-	devices := []PVEDevice{}
+	devices := []Device{}
 	err = pve.client.Get(context.Background(), fmt.Sprintf("/nodes/%s/hardware/pci", nodeName), &devices)
 	if err != nil {
 		return host, err
 	}
 
-	// map supersystem devices to each contained subsystem
-	// eg 0000:00:05 -> [0000:00:05.0, 0000:00:05.1, 0000:00:05.2, 0000:00:05.3, ...]
 	for _, device := range devices {
-		SupersystemID, SubsystemID, err := SplitDeviceBusID(device.BusID)
-		if err != nil {
-			return host, err
-		}
-
-		if host.Hardware[SupersystemID] == nil {
-			host.Hardware[SupersystemID] = &HostSuperDevice{
-				BusID:      SupersystemID,
-				DeviceName: device.DeviceName,
-				VendorName: device.VendorName,
-				Devices:    make(map[string]*HostDevice),
-			}
-		}
-
-		if !DeviceBusIDIsSuperDevice(device.BusID) {
-			host.Hardware[SupersystemID].Devices[SubsystemID] = &HostDevice{
-				SubID:         SubsystemID,
-				SubDeviceName: device.SubsystemDeviceName,
-				SubVendorName: device.SubsystemVendorName,
-			}
-		}
+		host.Devices[device.BusID] = &device
 	}
 
 	host.Name = node.Name
@@ -149,9 +119,9 @@ func (host Host) VirtualMachine(VMID uint) (Instance, error) {
 	instance.Proctype = vm.VirtualMachineConfig.CPU
 	instance.Cores = uint64(vm.VirtualMachineConfig.Cores)
 	instance.Memory = uint64(vm.VirtualMachineConfig.Memory) * MiB
-	instance.Volume = make(map[string]*Volume)
-	instance.Net = make(map[uint]*Net)
-	instance.Device = make(map[uint]*InstanceDevice)
+	instance.Volumes = make(map[string]*Volume)
+	instance.Nets = make(map[uint]*Net)
+	instance.Devices = make(map[uint][]*Device)
 
 	return instance, nil
 }
@@ -197,8 +167,8 @@ func (host Host) Container(VMID uint) (Instance, error) {
 	instance.Cores = uint64(ct.ContainerConfig.Cores)
 	instance.Memory = uint64(ct.ContainerConfig.Memory) * MiB
 	instance.Swap = uint64(ct.ContainerConfig.Swap) * MiB
-	instance.Volume = make(map[string]*Volume)
-	instance.Net = make(map[uint]*Net)
+	instance.Volumes = make(map[string]*Volume)
+	instance.Nets = make(map[uint]*Net)
 
 	return instance, nil
 }
diff --git a/app/types.go b/app/types.go
index 00dbc18..fc6984b 100644
--- a/app/types.go
+++ b/app/types.go
@@ -9,20 +9,20 @@ type Resource struct {
 }
 
 type Host struct {
-	Name     string
-	Cores    Resource
-	Memory   Resource
-	Swap     Resource
-	Hardware map[string]*HostSuperDevice
-	Instance map[uint]*Instance
-	node     *proxmox.Node
+	Name      string
+	Cores     Resource
+	Memory    Resource
+	Swap      Resource
+	Devices   map[string]*Device
+	Instances map[uint]*Instance
+	node      *proxmox.Node
 }
 
-type InstanceType bool
+type InstanceType string
 
 const (
-	VM InstanceType = true
-	CT InstanceType = false
+	VM InstanceType = "VM"
+	CT InstanceType = "CT"
 )
 
 type Instance struct {
@@ -32,9 +32,9 @@ type Instance struct {
 	Cores          uint64
 	Memory         uint64
 	Swap           uint64
-	Volume         map[string]*Volume
-	Net            map[uint]*Net
-	Device         map[uint]*InstanceDevice
+	Volumes        map[string]*Volume
+	Nets           map[uint]*Net
+	Devices        map[uint][]*Device
 	config         interface{}
 	configDisks    map[string]string
 	configNets     map[string]string
@@ -54,21 +54,11 @@ type Net struct {
 	VLAN uint64
 }
 
-type InstanceDevice struct {
-	Device []*HostDevice
-	PCIE   bool
-}
-
-type HostSuperDevice struct {
-	BusID      string
-	DeviceName string
-	VendorName string
-	Devices    map[string]*HostDevice
-}
-
-type HostDevice struct {
-	SubID         string
-	SubDeviceName string
-	SubVendorName string
-	Reserved      bool
+type Device struct {
+	BusID               string `json:"id"`
+	DeviceName          string `json:"device_name"`
+	VendorName          string `json:"vendor_name"`
+	SubsystemDeviceName string `json:"subsystem_device_name"`
+	SubsystemVendorName string `json:"subsystem_vendor_name"`
+	Reserved            bool
 }
diff --git a/app/utils.go b/app/utils.go
index e03cae6..b98775a 100644
--- a/app/utils.go
+++ b/app/utils.go
@@ -2,7 +2,6 @@ package app
 
 import (
 	"encoding/json"
-	"fmt"
 	"log"
 	"os"
 	"strings"
@@ -38,20 +37,17 @@ func GetConfig(configPath string) Config {
 // returns if a device pcie bus id is a super device or subsystem device
 //
 // subsystem devices always has the format xxxx:yy.z, whereas super devices have the format xxxx:yy
+//
+// returns true if BusID has format xxxx:yy
 func DeviceBusIDIsSuperDevice(BusID string) bool {
 	return !strings.ContainsRune(BusID, '.')
 }
 
-// splits a device pcie bus id into super device and subsystem device IDs if possible
-func SplitDeviceBusID(BusID string) (string, string, error) {
-	if DeviceBusIDIsSuperDevice(BusID) {
-		return BusID, "", nil
-	} else {
-		x := strings.Split(BusID, ".")
-		if len(x) != 2 {
-			return "", "", fmt.Errorf("BusID: %s contained more than one '.'", BusID)
-		} else {
-			return x[0], x[1], nil
-		}
-	}
+// returns if a device pcie bus id is a subdevice of specified super device
+//
+// subsystem devices always has the format xxxx:yy.z, whereas super devices have the format xxxx:yy
+//
+// returns true if BusID has prefix SuperDeviceBusID and SuperDeviceBusID is a Super Device
+func DeviceBusIDIsSubDevice(BusID string, SuperDeviceBusID string) bool {
+	return DeviceBusIDIsSuperDevice(SuperDeviceBusID) && strings.HasPrefix(BusID, SuperDeviceBusID)
 }
diff --git a/go.mod b/go.mod
index 73a99dd..eb36f5e 100644
--- a/go.mod
+++ b/go.mod
@@ -8,11 +8,37 @@ require github.com/luthermonson/go-proxmox v0.2.0
 
 require (
 	github.com/buger/goterm v1.0.4 // indirect
+	github.com/bytedance/sonic v1.11.6 // indirect
+	github.com/bytedance/sonic/loader v0.1.1 // indirect
+	github.com/cloudwego/base64x v0.1.4 // indirect
+	github.com/cloudwego/iasm v0.2.0 // indirect
 	github.com/diskfs/go-diskfs v1.4.2 // indirect
 	github.com/djherbis/times v1.6.0 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+	github.com/gin-contrib/sse v0.1.0 // indirect
+	github.com/gin-gonic/gin v1.10.0 // indirect
+	github.com/go-playground/locales v0.14.1 // indirect
+	github.com/go-playground/universal-translator v0.18.1 // indirect
+	github.com/go-playground/validator/v10 v10.20.0 // indirect
+	github.com/goccy/go-json v0.10.2 // indirect
 	github.com/gorilla/websocket v1.5.3 // indirect
 	github.com/jinzhu/copier v0.4.0 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.7 // indirect
+	github.com/leodido/go-urn v1.4.0 // indirect
 	github.com/magefile/mage v1.15.0 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
 	github.com/stretchr/testify v1.9.0 // indirect
+	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
+	github.com/ugorji/go/codec v1.2.12 // indirect
+	golang.org/x/arch v0.8.0 // indirect
+	golang.org/x/crypto v0.23.0 // indirect
+	golang.org/x/net v0.25.0 // indirect
 	golang.org/x/sys v0.26.0 // indirect
+	golang.org/x/text v0.15.0 // indirect
+	google.golang.org/protobuf v1.34.1 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
 )