diff --git a/pkg/extension/extension.go b/pkg/extension/extension.go
index fb8044c7a2f4c76b775840c5628319196a0493ae..5277dd50ffe748595aa744773770117f6cb214b2 100644
--- a/pkg/extension/extension.go
+++ b/pkg/extension/extension.go
@@ -3,6 +3,8 @@ package extension
 import (
 	"context"
 	"fmt"
+	"net/url"
+	"strings"
 
 	"git.perx.ru/perxis/perxis-go/pkg/content"
 	"git.perx.ru/perxis/perxis-go/pkg/errors"
@@ -105,3 +107,46 @@ func ExtensionFromError(err error) string {
 	ext, _ := v.(string)
 	return ext
 }
+
+type ParsedActionURL struct {
+	actionID    string
+	extensionID string
+	scheme      string
+}
+
+func (p *ParsedActionURL) New() *ParsedActionURL {
+	return &ParsedActionURL{}
+}
+
+func (p *ParsedActionURL) GetActionID() string {
+	return p.actionID
+}
+
+func (p *ParsedActionURL) GetExtensionID() string {
+	return p.extensionID
+}
+
+func (p *ParsedActionURL) GetScheme() string {
+	return p.scheme
+}
+
+func (p *ParsedActionURL) Parse(action string) error {
+	u, err := url.Parse(action)
+	if err != nil {
+		return err
+	}
+	p.scheme = u.Scheme
+	if p.GetScheme() == "grpc" {
+		path := u.Path
+		if strings.HasPrefix(u.Path, "/") {
+			path = u.Path[1:]
+		}
+		splitPath := strings.Split(path, "/")
+		if len(splitPath) < 2 {
+			return errors.Errorf("incorrect action URL, no action id: '%s'", action)
+		}
+		p.extensionID = splitPath[0]
+		p.actionID = splitPath[1]
+	}
+	return nil
+}