diff --git a/api/domains.go b/api/domains.go
new file mode 100644
index 0000000..29afebb
--- /dev/null
+++ b/api/domains.go
@@ -0,0 +1,33 @@
+package api
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"net/http"
+)
+
+func (c *Client) CreateDomain(ctx context.Context, d KraudDomainCreate) (*KraudDomain, error) {
+	b := &bytes.Buffer{}
+	err := json.NewEncoder(b).Encode(d)
+	if err != nil {
+		return nil, err
+	}
+
+	req, err := http.NewRequestWithContext(
+		ctx,
+		"POST",
+		"/apis/kraudcloud.com/v1/domains",
+		b,
+	)
+	if err != nil {
+		return nil, err
+	}
+
+	out := &KraudDomain{}
+	err = c.Do(req, out)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
diff --git a/api/openapi.go b/api/openapi.go
index 5c4ea4f..3f47c3c 100644
--- a/api/openapi.go
+++ b/api/openapi.go
@@ -1,6 +1,6 @@
 // Package api provides primitives to interact with the openapi HTTP API.
 //
-// Code generated by github.com/discord-gophers/goapi-gen version v0.2.2 DO NOT EDIT.
+// Code generated by github.com/discord-gophers/goapi-gen version v0.3.0 DO NOT EDIT.
 package api
 
 import (
@@ -1541,6 +1541,26 @@ type KraudDeploymentList struct {
 	Items []KraudDeployment `json:"items"`
 }
 
+// KraudDomain defines model for Kraud.Domain.
+type KraudDomain struct {
+	CreatedAt time.Time `json:"CreatedAt"`
+	ID        string    `json:"ID"`
+	IngressID string    `json:"IngressID"`
+	Name      string    `json:"Name"`
+}
+
+// KraudDomainCreate defines model for Kraud.DomainCreate.
+type KraudDomainCreate struct {
+	// Ingress ID, will use the default ingress if not specified
+	IngressID *string `json:"IngressID,omitempty"`
+	Name      string  `json:"Name"`
+}
+
+// KraudDomainList defines model for Kraud.DomainList.
+type KraudDomainList struct {
+	Items []KraudDomain `json:"items"`
+}
+
 // Image is a docker image for a specific architecture
 type KraudImage struct {
 	Config string                `json:"Config"`
@@ -1569,6 +1589,7 @@ type KraudImageNameList struct {
 type KraudLayer struct {
 	ID       string `json:"ID"`
 	OciID    string `json:"OciID"`
+	Lost     bool   `json:"lost"`
 	Refcount int    `json:"refcount"`
 	Sha256   string `json:"sha256"`
 	Size     uint64 `json:"size"`
@@ -5420,7 +5441,7 @@ type ContainerStateStatus struct {
 func (t *ContainerStateStatus) ToValue() string {
 	return t.value
 }
-func (t *ContainerStateStatus) MarshalJSON() ([]byte, error) {
+func (t ContainerStateStatus) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *ContainerStateStatus) UnmarshalJSON(data []byte) error {
@@ -5473,7 +5494,7 @@ type EndpointPortConfigProtocol struct {
 func (t *EndpointPortConfigProtocol) ToValue() string {
 	return t.value
 }
-func (t *EndpointPortConfigProtocol) MarshalJSON() ([]byte, error) {
+func (t EndpointPortConfigProtocol) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *EndpointPortConfigProtocol) UnmarshalJSON(data []byte) error {
@@ -5518,7 +5539,7 @@ type EndpointPortConfigPublishMode struct {
 func (t *EndpointPortConfigPublishMode) ToValue() string {
 	return t.value
 }
-func (t *EndpointPortConfigPublishMode) MarshalJSON() ([]byte, error) {
+func (t EndpointPortConfigPublishMode) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *EndpointPortConfigPublishMode) UnmarshalJSON(data []byte) error {
@@ -5551,7 +5572,7 @@ type EndpointSpecMode struct {
 func (t *EndpointSpecMode) ToValue() string {
 	return t.value
 }
-func (t *EndpointSpecMode) MarshalJSON() ([]byte, error) {
+func (t EndpointSpecMode) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *EndpointSpecMode) UnmarshalJSON(data []byte) error {
@@ -5589,7 +5610,7 @@ type HealthStatus struct {
 func (t *HealthStatus) ToValue() string {
 	return t.value
 }
-func (t *HealthStatus) MarshalJSON() ([]byte, error) {
+func (t HealthStatus) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *HealthStatus) UnmarshalJSON(data []byte) error {
@@ -5636,7 +5657,7 @@ type HostConfigCgroupnsMode struct {
 func (t *HostConfigCgroupnsMode) ToValue() string {
 	return t.value
 }
-func (t *HostConfigCgroupnsMode) MarshalJSON() ([]byte, error) {
+func (t HostConfigCgroupnsMode) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *HostConfigCgroupnsMode) UnmarshalJSON(data []byte) error {
@@ -5669,7 +5690,7 @@ type HostConfigIsolation struct {
 func (t *HostConfigIsolation) ToValue() string {
 	return t.value
 }
-func (t *HostConfigIsolation) MarshalJSON() ([]byte, error) {
+func (t HostConfigIsolation) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *HostConfigIsolation) UnmarshalJSON(data []byte) error {
@@ -5706,7 +5727,7 @@ type HostConfigLogConfigType struct {
 func (t *HostConfigLogConfigType) ToValue() string {
 	return t.value
 }
-func (t *HostConfigLogConfigType) MarshalJSON() ([]byte, error) {
+func (t HostConfigLogConfigType) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *HostConfigLogConfigType) UnmarshalJSON(data []byte) error {
@@ -5767,7 +5788,7 @@ type LocalNodeState struct {
 func (t *LocalNodeState) ToValue() string {
 	return t.value
 }
-func (t *LocalNodeState) MarshalJSON() ([]byte, error) {
+func (t LocalNodeState) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *LocalNodeState) UnmarshalJSON(data []byte) error {
@@ -5816,7 +5837,7 @@ type MountBindOptionsPropagation struct {
 func (t *MountBindOptionsPropagation) ToValue() string {
 	return t.value
 }
-func (t *MountBindOptionsPropagation) MarshalJSON() ([]byte, error) {
+func (t MountBindOptionsPropagation) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *MountBindOptionsPropagation) UnmarshalJSON(data []byte) error {
@@ -5870,7 +5891,7 @@ type MountType struct {
 func (t *MountType) ToValue() string {
 	return t.value
 }
-func (t *MountType) MarshalJSON() ([]byte, error) {
+func (t MountType) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *MountType) UnmarshalJSON(data []byte) error {
@@ -5916,7 +5937,7 @@ type MountPointType struct {
 func (t *MountPointType) ToValue() string {
 	return t.value
 }
-func (t *MountPointType) MarshalJSON() ([]byte, error) {
+func (t MountPointType) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *MountPointType) UnmarshalJSON(data []byte) error {
@@ -5957,7 +5978,7 @@ type NodeSpecAvailability struct {
 func (t *NodeSpecAvailability) ToValue() string {
 	return t.value
 }
-func (t *NodeSpecAvailability) MarshalJSON() ([]byte, error) {
+func (t NodeSpecAvailability) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *NodeSpecAvailability) UnmarshalJSON(data []byte) error {
@@ -5994,7 +6015,7 @@ type NodeSpecRole struct {
 func (t *NodeSpecRole) ToValue() string {
 	return t.value
 }
-func (t *NodeSpecRole) MarshalJSON() ([]byte, error) {
+func (t NodeSpecRole) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *NodeSpecRole) UnmarshalJSON(data []byte) error {
@@ -6027,7 +6048,7 @@ type NodeState struct {
 func (t *NodeState) ToValue() string {
 	return t.value
 }
-func (t *NodeState) MarshalJSON() ([]byte, error) {
+func (t NodeState) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *NodeState) UnmarshalJSON(data []byte) error {
@@ -6068,7 +6089,7 @@ type PortType struct {
 func (t *PortType) ToValue() string {
 	return t.value
 }
-func (t *PortType) MarshalJSON() ([]byte, error) {
+func (t PortType) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *PortType) UnmarshalJSON(data []byte) error {
@@ -6105,7 +6126,7 @@ type Reachability struct {
 func (t *Reachability) ToValue() string {
 	return t.value
 }
-func (t *Reachability) MarshalJSON() ([]byte, error) {
+func (t Reachability) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *Reachability) UnmarshalJSON(data []byte) error {
@@ -6146,7 +6167,7 @@ type RestartPolicyName struct {
 func (t *RestartPolicyName) ToValue() string {
 	return t.value
 }
-func (t *RestartPolicyName) MarshalJSON() ([]byte, error) {
+func (t RestartPolicyName) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *RestartPolicyName) UnmarshalJSON(data []byte) error {
@@ -6192,7 +6213,7 @@ type ServiceSpecRollbackConfigFailureAction struct {
 func (t *ServiceSpecRollbackConfigFailureAction) ToValue() string {
 	return t.value
 }
-func (t *ServiceSpecRollbackConfigFailureAction) MarshalJSON() ([]byte, error) {
+func (t ServiceSpecRollbackConfigFailureAction) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *ServiceSpecRollbackConfigFailureAction) UnmarshalJSON(data []byte) error {
@@ -6227,7 +6248,7 @@ type ServiceSpecRollbackConfigOrder struct {
 func (t *ServiceSpecRollbackConfigOrder) ToValue() string {
 	return t.value
 }
-func (t *ServiceSpecRollbackConfigOrder) MarshalJSON() ([]byte, error) {
+func (t ServiceSpecRollbackConfigOrder) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *ServiceSpecRollbackConfigOrder) UnmarshalJSON(data []byte) error {
@@ -6261,7 +6282,7 @@ type ServiceSpecUpdateConfigFailureAction struct {
 func (t *ServiceSpecUpdateConfigFailureAction) ToValue() string {
 	return t.value
 }
-func (t *ServiceSpecUpdateConfigFailureAction) MarshalJSON() ([]byte, error) {
+func (t ServiceSpecUpdateConfigFailureAction) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *ServiceSpecUpdateConfigFailureAction) UnmarshalJSON(data []byte) error {
@@ -6300,7 +6321,7 @@ type ServiceSpecUpdateConfigOrder struct {
 func (t *ServiceSpecUpdateConfigOrder) ToValue() string {
 	return t.value
 }
-func (t *ServiceSpecUpdateConfigOrder) MarshalJSON() ([]byte, error) {
+func (t ServiceSpecUpdateConfigOrder) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *ServiceSpecUpdateConfigOrder) UnmarshalJSON(data []byte) error {
@@ -6333,7 +6354,7 @@ type ServiceUpdateStatusState struct {
 func (t *ServiceUpdateStatusState) ToValue() string {
 	return t.value
 }
-func (t *ServiceUpdateStatusState) MarshalJSON() ([]byte, error) {
+func (t ServiceUpdateStatusState) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *ServiceUpdateStatusState) UnmarshalJSON(data []byte) error {
@@ -6371,7 +6392,7 @@ type SwarmSpecCAConfigExternalCAsProtocol struct {
 func (t *SwarmSpecCAConfigExternalCAsProtocol) ToValue() string {
 	return t.value
 }
-func (t *SwarmSpecCAConfigExternalCAsProtocol) MarshalJSON() ([]byte, error) {
+func (t SwarmSpecCAConfigExternalCAsProtocol) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *SwarmSpecCAConfigExternalCAsProtocol) UnmarshalJSON(data []byte) error {
@@ -6400,7 +6421,7 @@ type SystemInfoCgroupDriver struct {
 func (t *SystemInfoCgroupDriver) ToValue() string {
 	return t.value
 }
-func (t *SystemInfoCgroupDriver) MarshalJSON() ([]byte, error) {
+func (t SystemInfoCgroupDriver) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *SystemInfoCgroupDriver) UnmarshalJSON(data []byte) error {
@@ -6437,7 +6458,7 @@ type SystemInfoCgroupVersion struct {
 func (t *SystemInfoCgroupVersion) ToValue() string {
 	return t.value
 }
-func (t *SystemInfoCgroupVersion) MarshalJSON() ([]byte, error) {
+func (t SystemInfoCgroupVersion) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *SystemInfoCgroupVersion) UnmarshalJSON(data []byte) error {
@@ -6476,7 +6497,7 @@ type SystemInfoIsolation struct {
 func (t *SystemInfoIsolation) ToValue() string {
 	return t.value
 }
-func (t *SystemInfoIsolation) MarshalJSON() ([]byte, error) {
+func (t SystemInfoIsolation) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *SystemInfoIsolation) UnmarshalJSON(data []byte) error {
@@ -6513,7 +6534,7 @@ type TaskSpecRestartPolicyCondition struct {
 func (t *TaskSpecRestartPolicyCondition) ToValue() string {
 	return t.value
 }
-func (t *TaskSpecRestartPolicyCondition) MarshalJSON() ([]byte, error) {
+func (t TaskSpecRestartPolicyCondition) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *TaskSpecRestartPolicyCondition) UnmarshalJSON(data []byte) error {
@@ -6551,7 +6572,7 @@ type TaskSpecContainerSpecIsolation struct {
 func (t *TaskSpecContainerSpecIsolation) ToValue() string {
 	return t.value
 }
-func (t *TaskSpecContainerSpecIsolation) MarshalJSON() ([]byte, error) {
+func (t TaskSpecContainerSpecIsolation) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *TaskSpecContainerSpecIsolation) UnmarshalJSON(data []byte) error {
@@ -6589,7 +6610,7 @@ type VolumeScope struct {
 func (t *VolumeScope) ToValue() string {
 	return t.value
 }
-func (t *VolumeScope) MarshalJSON() ([]byte, error) {
+func (t VolumeScope) MarshalJSON() ([]byte, error) {
 	return json.Marshal(t.value)
 }
 func (t *VolumeScope) UnmarshalJSON(data []byte) error {
@@ -6738,6 +6759,9 @@ type VmmReportContainerStateJSONBody KrVmmContainerReport
 // VmmReportPodStateJSONBody defines parameters for VmmReportPodState.
 type VmmReportPodStateJSONBody KrVmmPodReport
 
+// CreateDomainJSONBody defines parameters for CreateDomain.
+type CreateDomainJSONBody KraudDomainCreate
+
 // CreateFeedJSONBody defines parameters for CreateFeed.
 type CreateFeedJSONBody KraudCreateFeed
 
@@ -7818,6 +7842,14 @@ func (VmmReportPodStateJSONRequestBody) Bind(*http.Request) error {
 	return nil
 }
 
+// CreateDomainJSONRequestBody defines body for CreateDomain for application/json ContentType.
+type CreateDomainJSONRequestBody CreateDomainJSONBody
+
+// Bind implements render.Binder.
+func (CreateDomainJSONRequestBody) Bind(*http.Request) error {
+	return nil
+}
+
 // CreateFeedJSONRequestBody defines body for CreateFeed for application/json ContentType.
 type CreateFeedJSONRequestBody CreateFeedJSONBody
 
@@ -8512,6 +8544,26 @@ func InspectKraudDeploymentJSON200Response(body KraudDeployment) *Response {
 	}
 }
 
+// ListDomainsJSON200Response is a constructor method for a ListDomains response.
+// A *Response is returned with the configured status code and content type from the spec.
+func ListDomainsJSON200Response(body KraudDomainList) *Response {
+	return &Response{
+		body:        body,
+		Code:        200,
+		contentType: "application/json",
+	}
+}
+
+// CreateDomainJSON200Response is a constructor method for a CreateDomain response.
+// A *Response is returned with the configured status code and content type from the spec.
+func CreateDomainJSON200Response(body KraudDomain) *Response {
+	return &Response{
+		body:        body,
+		Code:        200,
+		contentType: "application/json",
+	}
+}
+
 // GetEventsStreamJSON200Response is a constructor method for a GetEventsStream response.
 // A *Response is returned with the configured status code and content type from the spec.
 func GetEventsStreamJSON200Response(body KraudEvent) *Response {
diff --git a/api/openapi.yaml b/api/openapi.yaml
index 8362a5e..db1175b 100644
--- a/api/openapi.yaml
+++ b/api/openapi.yaml
@@ -2004,6 +2004,42 @@ components:
             required:
                 - items
             type: object
+        Kraud.Domain:
+            properties:
+                CreatedAt:
+                    format: date-time
+                    type: string
+                ID:
+                    type: string
+                IngressID:
+                    type: string
+                Name:
+                    type: string
+            required:
+                - ID
+                - Name
+                - CreatedAt
+                - IngressID
+            type: object
+        Kraud.DomainCreate:
+            properties:
+                IngressID:
+                    description: Ingress ID, will use the default ingress if not specified
+                    type: string
+                Name:
+                    type: string
+            required:
+                - Name
+            type: object
+        Kraud.DomainList:
+            properties:
+                items:
+                    items:
+                        $ref: '#/components/schemas/Kraud.Domain'
+                    type: array
+            required:
+                - items
+            type: object
         Kraud.Image:
             description: Image is a docker image for a specific architecture
             properties:
@@ -2059,6 +2095,8 @@ components:
                     type: string
                 OciID:
                     type: string
+                lost:
+                    type: boolean
                 refcount:
                     type: integer
                 sha256:
@@ -2072,6 +2110,7 @@ components:
                 - sha256
                 - OciID
                 - refcount
+                - lost
             type: object
         Kraud.LayerList:
             properties:
@@ -10615,6 +10654,32 @@ paths:
                             schema:
                                 $ref: '#/components/schemas/Kraud.Deployment'
                     description: OK
+    /apis/kraudcloud.com/v1/domains:
+        get:
+            operationId: listDomains
+            responses:
+                200:
+                    content:
+                        application/json:
+                            schema:
+                                $ref: '#/components/schemas/Kraud.DomainList'
+                    description: OK
+        post:
+            operationId: createDomain
+            requestBody:
+                content:
+                    application/json:
+                        schema:
+                            $ref: '#/components/schemas/Kraud.DomainCreate'
+            responses:
+                200:
+                    content:
+                        application/json:
+                            schema:
+                                $ref: '#/components/schemas/Kraud.Domain'
+                    description: OK
+                "401":
+                    description: Unauthorized
     /apis/kraudcloud.com/v1/events/stream.json:
         get:
             description: Get events, one line per event
@@ -11253,6 +11318,18 @@ paths:
                                 $ref: '#/components/schemas/Kraud.VolumeList'
                     description: OK
     /apis/kraudcloud.com/v1/volumes/{q}:
+        delete:
+            operationId: deleteKraudVolume
+            parameters:
+                - description: aid or uuid
+                  in: path
+                  name: q
+                  required: true
+                  schema:
+                    type: string
+            responses:
+                204:
+                    description: OK
         get:
             operationId: inspectKraudVolume
             parameters:
diff --git a/domains.go b/domains.go
index 4f07a90..daddad8 100644
--- a/domains.go
+++ b/domains.go
@@ -2,6 +2,8 @@ package main
 
 import (
 	"fmt"
+
+	"github.com/kraudcloud/cli/api"
 	"github.com/spf13/cobra"
 )
 
@@ -14,6 +16,7 @@ func domainsCMD() *cobra.Command {
 	}
 
 	c.AddCommand(domainsLs())
+	c.AddCommand(DomainsAdd())
 
 	return c
 }
@@ -54,3 +57,37 @@ func domainsLs() *cobra.Command {
 
 	return c
 }
+
+func DomainsAdd() *cobra.Command {
+	ingressID := ""
+	c := &cobra.Command{
+		Use:   "add <domain>",
+		Short: "add domain",
+		Args:  cobra.ExactArgs(1),
+		Run: func(cmd *cobra.Command, args []string) {
+			domain := args[0]
+
+			_, err := API().CreateDomain(cmd.Context(), api.KraudDomainCreate{
+				Name:      domain,
+				IngressID: optNil(ingressID),
+			})
+			if err != nil {
+				log.Fatalln(err)
+			}
+
+			fmt.Println("Domain added")
+		},
+	}
+
+	c.Flags().StringVar(&ingressID, "ingress", "", "ingress id")
+	return c
+}
+
+// optNil returns nil if v is the zero value of T, otherwise returns a pointer to v.
+func optNil[T comparable](v T) *T {
+	var zero T
+	if v == zero {
+		return nil
+	}
+	return &v
+}
