diff --git a/id/collection.go b/id/collection.go
index 18e1008b078d9f4350ee367b85d0489e75bc6293..50bf64ee6b7c02cd5629120ccf288155d85877a8 100644
--- a/id/collection.go
+++ b/id/collection.go
@@ -13,7 +13,7 @@ type CollectionID struct {
 func (t *CollectionID) Type() string { return Collection }
 
 func (t *CollectionID) String() string {
-	return Join(t.EnvironmentID.String(), t.CollectionID)
+	return Join(t.EnvironmentID.String(), CollectionsPrefix, t.CollectionID)
 }
 
 func (t *CollectionID) ToMap() map[string]any {
@@ -30,22 +30,6 @@ func (t *CollectionID) FromMap(m map[string]any) error {
 	return nil
 }
 
-func (t *CollectionID) FromString(id string) error {
-	parts := Split(id)
-	return t.fromParts(parts)
-}
-
-func (t *CollectionID) fromParts(parts []string) error {
-	if err := t.EnvironmentID.fromParts(parts); err != nil {
-		return err
-	}
-	if len(parts) < 6 || parts[4] != CollectionsPrefix {
-		return ErrInvalidID
-	}
-	t.CollectionID = parts[5]
-	return nil
-}
-
 func (t *CollectionID) Validate() error {
 	if t.CollectionID == "" {
 		return ErrInvalidID
@@ -53,3 +37,19 @@ func (t *CollectionID) Validate() error {
 
 	return t.EnvironmentID.Validate()
 }
+
+func parseCollectionID(parts []string) (*CollectionID, error) {
+	if len(parts) != 6 || parts[0] != EnvironmentsPrefix {
+		return nil, ErrInvalidID
+	}
+
+	envID, err := parseEnvironmentID(parts[:4])
+	if err != nil {
+		return nil, err
+	}
+
+	var id CollectionID
+	id.CollectionID = parts[5]
+	id.EnvironmentID = *envID
+	return &id, nil
+}
diff --git a/id/environment.go b/id/environment.go
index f5ceab37fc8d8c7131ac923dd0ac8912ebe2e182..4958a33f73b4e2c8d8edbb76bda7b1d7705cfbd2 100644
--- a/id/environment.go
+++ b/id/environment.go
@@ -13,7 +13,10 @@ type EnvironmentID struct {
 func (t *EnvironmentID) Type() string { return Environment }
 
 func (t *EnvironmentID) String() string {
-	return Join(t.SpaceID.String(), t.EnvironmentID)
+	return Join(t.SpaceID.String(),
+		EnvironmentsPrefix, t.EnvironmentID,
+	)
+
 }
 
 func (t *EnvironmentID) ToMap() map[string]any {
@@ -30,22 +33,6 @@ func (t *EnvironmentID) FromMap(m map[string]any) error {
 	return nil
 }
 
-func (t *EnvironmentID) FromString(id string) error {
-	parts := Split(id)
-	return t.fromParts(parts)
-}
-
-func (t *EnvironmentID) fromParts(parts []string) error {
-	if err := t.SpaceID.fromParts(parts); err != nil {
-		return err
-	}
-	if len(parts) < 4 || parts[2] != EnvironmentsPrefix {
-		return ErrInvalidID
-	}
-	t.EnvironmentID = parts[3]
-	return nil
-}
-
 func (t *EnvironmentID) Validate() error {
 	if t.EnvironmentID == "" {
 		return ErrInvalidID
@@ -53,3 +40,19 @@ func (t *EnvironmentID) Validate() error {
 
 	return t.SpaceID.Validate()
 }
+
+func parseEnvironmentID(parts []string) (*EnvironmentID, error) {
+	if len(parts) != 4 || parts[2] != EnvironmentsPrefix {
+		return nil, ErrInvalidID
+	}
+
+	spaceID, err := parseSpaceID(parts[:2])
+	if err != nil {
+		return nil, err
+	}
+
+	var id EnvironmentID
+	id.EnvironmentID = parts[3]
+	id.SpaceID = *spaceID
+	return &id, nil
+}
diff --git a/id/id.go b/id/id.go
index 8f9ee6b8971aeae1c635200ba4c616cc943af8ac..a4ff8a5e16f7ef9959560b51b86f0d8f1a0e9137 100644
--- a/id/id.go
+++ b/id/id.go
@@ -13,11 +13,30 @@ type ID interface {
 	String() string
 	Type() string
 	ToMap() map[string]any
-	FromString(string) error
 	FromMap(map[string]any) error
 	Validate() error
 }
 
+func Parse(s string) (ID, error) {
+	parts := Split(s)
+
+	// TODO: Парсим строку, от коротких к длинным
+
+	if id, err := parseSpaceID(parts); err != nil {
+		return id, nil
+	}
+
+	if id, _ := parseEnvironmentID(parts); id != nil {
+		return id, nil
+	}
+
+	if id, _ := parseCollectionID(parts); id != nil {
+		return id, nil
+	}
+
+	return nil, ErrInvalidID
+}
+
 func Split(id string) []string {
 	if id[0] != Separator {
 		return nil
diff --git a/id/json.go b/id/json.go
index ec510485d9025ad6ce4828c7ca8eb720629a511b..04fa39faf5f812a26aa1f9cc2bb1e3cf98f59f1e 100644
--- a/id/json.go
+++ b/id/json.go
@@ -1,3 +1,3 @@
 package id
 
-// Сохранение/чтение в JSON (в строку)
+// TODO: Сохранение/чтение в JSON (в строку)
diff --git a/id/space.go b/id/space.go
index 465412db077d14387afc958d96bb3eb7d6dd18c4..3d9d6c35cba03a45d1cee00d692865e0fc8a5037 100644
--- a/id/space.go
+++ b/id/space.go
@@ -26,22 +26,19 @@ func (t *SpaceID) FromMap(m map[string]any) error {
 	return nil
 }
 
-func (t *SpaceID) FromString(id string) error {
-	parts := Split(id)
-	return t.fromParts(parts)
-}
-
-func (t *SpaceID) fromParts(parts []string) error {
-	if len(parts) < 2 || parts[0] != SpacesPrefix {
+func (t *SpaceID) Validate() error {
+	if t.SpaceID == "" {
 		return ErrInvalidID
 	}
-	t.SpaceID = parts[1]
 	return nil
 }
 
-func (t *SpaceID) Validate() error {
-	if t.SpaceID == "" {
-		return ErrInvalidID
+func parseSpaceID(parts []string) (*SpaceID, error) {
+	var id SpaceID
+	if len(parts) != 2 || parts[0] != SpacesPrefix {
+		return nil, ErrInvalidID
 	}
-	return nil
+
+	id.SpaceID = parts[1]
+	return &id, nil
 }