diff --git a/cmd/policy/main.go b/cmd/policy/main.go
index b8257f6c50cc1f31254ef182e5b11826ee9fa8cb..cd489f786f0bdd81dd3ecdfbaf5fb3cbdb36fae3 100644
--- a/cmd/policy/main.go
+++ b/cmd/policy/main.go
@@ -86,9 +86,6 @@ func main() {
 	// create rego policy cache
 	regocache := regocache.New()
 
-	// create policy changes notifier
-	notifier := notify.New(events)
-
 	// connect to mongo db
 	db, err := mongo.Connect(
 		context.Background(),
@@ -109,6 +106,9 @@ func main() {
 		logger.Fatal("error connecting to database", zap.Error(err))
 	}
 
+	// create policy changes notifier
+	notifier := notify.New(events, httpClient, storage, logger)
+
 	// subscribe the cache for policy data changes
 	storage.AddPolicyChangeSubscribers(regocache, notifier)
 
diff --git a/design/design.go b/design/design.go
index a1af34032ad4f377d54b00ff642a5addf19c13ab..971fdbf748bdffdcef01d051eb75384ead902fd5 100644
--- a/design/design.go
+++ b/design/design.go
@@ -1,7 +1,9 @@
 // nolint:revive
 package design
 
-import . "goa.design/goa/v3/dsl"
+import (
+	. "goa.design/goa/v3/dsl"
+)
 
 var _ = API("policy", func() {
 	Title("Policy Service")
@@ -75,6 +77,16 @@ var _ = Service("policy", func() {
 			Response(StatusOK)
 		})
 	})
+
+	Method("Webhooks", func() {
+		Description("Gives ability to user to subscribe for policy change via webhooks")
+		Payload(WebhooksRequest)
+		Result(Any)
+		HTTP(func() {
+			POST("/policy/{group}/{policyname}/{version}/notifychange")
+			Response(StatusOK)
+		})
+	})
 })
 
 var _ = Service("health", func() {
diff --git a/design/types.go b/design/types.go
index 2b2ed7d68e94798420624ca64685d279340f4eb6..8d47f542be96ae79d1d56eb091387e65bdd3ae77 100644
--- a/design/types.go
+++ b/design/types.go
@@ -1,7 +1,9 @@
 // nolint:revive
 package design
 
-import . "goa.design/goa/v3/dsl"
+import (
+	. "goa.design/goa/v3/dsl"
+)
 
 var EvaluateRequest = Type("EvaluateRequest", func() {
 	Field(1, "group", String, "Policy group.", func() {
@@ -62,3 +64,12 @@ var PoliciesResult = Type("PoliciesResult", func() {
 	Field(1, "policies", ArrayOf(Policy), "JSON array of policies.")
 	Required("policies")
 })
+
+var WebhooksRequest = Type("WebHooksRequest", func() {
+	Field(1, "webhook_url", String, "Subscriber webhook url.")
+	Field(2, "subscriber", String, "Name of the subscriber for policy.")
+	Field(3, "policyname", String, "Policy name.")
+	Field(4, "group", String, "Policy group.")
+	Field(5, "version", String, "Policy version.")
+	Required("webhook_url", "subscriber", "group", "policyname", "version")
+})
diff --git a/gen/http/cli/policy/cli.go b/gen/http/cli/policy/cli.go
index 65eb4e07570da777903af00b7b5a80ad12600f26..0ef0f3fe48e6c1275204613abd12a128c2eeed76 100644
--- a/gen/http/cli/policy/cli.go
+++ b/gen/http/cli/policy/cli.go
@@ -24,14 +24,14 @@ import (
 //	command (subcommand1|subcommand2|...)
 func UsageCommands() string {
 	return `health (liveness|readiness)
-policy (evaluate|lock|unlock|list-policies)
+policy (evaluate|lock|unlock|list-policies|webhooks)
 `
 }
 
 // UsageExamples produces an example of a valid invocation of the CLI tool.
 func UsageExamples() string {
 	return os.Args[0] + ` health liveness` + "\n" +
-		os.Args[0] + ` policy evaluate --body "Quibusdam ab repellendus in illum." --group "example" --policy-name "example" --version "1.0" --evaluation-id "Nihil repudiandae dolore quod sunt aut." --ttl 4633716418015214972` + "\n" +
+		os.Args[0] + ` policy evaluate --body "Earum velit illum quia aliquam atque voluptatum." --group "example" --policy-name "example" --version "1.0" --evaluation-id "Omnis quasi aut consequuntur." --ttl 2830259876533307070` + "\n" +
 		""
 }
 
@@ -76,6 +76,12 @@ func ParseEndpoint(
 		policyListPoliciesRegoFlag       = policyListPoliciesFlags.String("rego", "", "")
 		policyListPoliciesDataFlag       = policyListPoliciesFlags.String("data", "", "")
 		policyListPoliciesDataConfigFlag = policyListPoliciesFlags.String("data-config", "", "")
+
+		policyWebhooksFlags          = flag.NewFlagSet("webhooks", flag.ExitOnError)
+		policyWebhooksBodyFlag       = policyWebhooksFlags.String("body", "REQUIRED", "")
+		policyWebhooksGroupFlag      = policyWebhooksFlags.String("group", "REQUIRED", "Policy group.")
+		policyWebhooksPolicynameFlag = policyWebhooksFlags.String("policyname", "REQUIRED", "Policy name.")
+		policyWebhooksVersionFlag    = policyWebhooksFlags.String("version", "REQUIRED", "Policy version.")
 	)
 	healthFlags.Usage = healthUsage
 	healthLivenessFlags.Usage = healthLivenessUsage
@@ -86,6 +92,7 @@ func ParseEndpoint(
 	policyLockFlags.Usage = policyLockUsage
 	policyUnlockFlags.Usage = policyUnlockUsage
 	policyListPoliciesFlags.Usage = policyListPoliciesUsage
+	policyWebhooksFlags.Usage = policyWebhooksUsage
 
 	if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
 		return nil, nil, err
@@ -145,6 +152,9 @@ func ParseEndpoint(
 			case "list-policies":
 				epf = policyListPoliciesFlags
 
+			case "webhooks":
+				epf = policyWebhooksFlags
+
 			}
 
 		}
@@ -192,6 +202,9 @@ func ParseEndpoint(
 			case "list-policies":
 				endpoint = c.ListPolicies()
 				data, err = policyc.BuildListPoliciesPayload(*policyListPoliciesLockedFlag, *policyListPoliciesRegoFlag, *policyListPoliciesDataFlag, *policyListPoliciesDataConfigFlag)
+			case "webhooks":
+				endpoint = c.Webhooks()
+				data, err = policyc.BuildWebhooksPayload(*policyWebhooksBodyFlag, *policyWebhooksGroupFlag, *policyWebhooksPolicynameFlag, *policyWebhooksVersionFlag)
 			}
 		}
 	}
@@ -247,6 +260,7 @@ COMMAND:
     lock: Lock a policy so that it cannot be evaluated.
     unlock: Unlock a policy so it can be evaluated again.
     list-policies: List policies from storage with optional filters.
+    webhooks: Gives ability to user to subscribe for policy change via webhooks
 
 Additional help:
     %[1]s policy COMMAND --help
@@ -264,7 +278,7 @@ Evaluate executes a policy with the given 'data' as input.
     -ttl INT: 
 
 Example:
-    %[1]s policy evaluate --body "Quibusdam ab repellendus in illum." --group "example" --policy-name "example" --version "1.0" --evaluation-id "Nihil repudiandae dolore quod sunt aut." --ttl 4633716418015214972
+    %[1]s policy evaluate --body "Earum velit illum quia aliquam atque voluptatum." --group "example" --policy-name "example" --version "1.0" --evaluation-id "Omnis quasi aut consequuntur." --ttl 2830259876533307070
 `, os.Args[0])
 }
 
@@ -277,7 +291,7 @@ Lock a policy so that it cannot be evaluated.
     -version STRING: Policy version.
 
 Example:
-    %[1]s policy lock --group "Aliquam atque voluptatum ut dolorem." --policy-name "Aut facere veniam repudiandae id." --version "Aut minus alias."
+    %[1]s policy lock --group "Aut voluptas." --policy-name "Sint nam voluptatem ea consequatur similique et." --version "Non mollitia nesciunt impedit facere."
 `, os.Args[0])
 }
 
@@ -290,7 +304,7 @@ Unlock a policy so it can be evaluated again.
     -version STRING: Policy version.
 
 Example:
-    %[1]s policy unlock --group "Aut voluptas." --policy-name "Sint nam voluptatem ea consequatur similique et." --version "Non mollitia nesciunt impedit facere."
+    %[1]s policy unlock --group "In quis nesciunt autem et." --policy-name "Sunt in et quia cum." --version "Commodi nemo fugiat id praesentium accusantium expedita."
 `, os.Args[0])
 }
 
@@ -304,6 +318,23 @@ List policies from storage with optional filters.
     -data-config BOOL: 
 
 Example:
-    %[1]s policy list-policies --locked false --rego true --data false --data-config false
+    %[1]s policy list-policies --locked false --rego true --data false --data-config true
+`, os.Args[0])
+}
+
+func policyWebhooksUsage() {
+	fmt.Fprintf(os.Stderr, `%[1]s [flags] policy webhooks -body JSON -group STRING -policyname STRING -version STRING
+
+Gives ability to user to subscribe for policy change via webhooks
+    -body JSON: 
+    -group STRING: Policy group.
+    -policyname STRING: Policy name.
+    -version STRING: Policy version.
+
+Example:
+    %[1]s policy webhooks --body '{
+      "subscriber": "Est totam officia necessitatibus tempore.",
+      "webhook_url": "Ad ab perspiciatis voluptatem pariatur corporis est."
+   }' --group "Animi consequuntur consequatur vel rerum." --policyname "Ipsam nam." --version "Vitae dolores quas et aperiam dolores reiciendis."
 `, os.Args[0])
 }
diff --git a/gen/http/openapi.json b/gen/http/openapi.json
index 9305711eca0a6d7ccd6bb112a789ee5292605307..f8384375ce127787df963daa5ec7895db7726367 100644
--- a/gen/http/openapi.json
+++ b/gen/http/openapi.json
@@ -1 +1 @@
-{"swagger":"2.0","info":{"title":"Policy Service","description":"The policy service exposes HTTP API for executing policies.","version":""},"host":"localhost:8081","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/policy/{group}/{policyName}/{version}/evaluation":{"get":{"tags":["policy"],"summary":"Evaluate policy","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"policy#Evaluate#1","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"type":"string"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"type":"string"},{"name":"version","in":"path","description":"Policy version.","required":true,"type":"string"},{"name":"x-evaluation-id","in":"header","description":"EvaluationID allows overwriting the randomly generated evaluationID","required":false,"type":"string"},{"name":"x-cache-ttl","in":"header","description":"Policy result cache TTL in seconds","required":false,"type":"integer"},{"name":"any","in":"body","description":"Input data passed to the policy execution runtime.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"},"headers":{"ETag":{"description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","type":"string"}}}},"schemes":["http"]},"post":{"tags":["policy"],"summary":"Evaluate policy","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"policy#Evaluate#2","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"type":"string"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"type":"string"},{"name":"version","in":"path","description":"Policy version.","required":true,"type":"string"},{"name":"x-evaluation-id","in":"header","description":"EvaluationID allows overwriting the randomly generated evaluationID","required":false,"type":"string"},{"name":"x-cache-ttl","in":"header","description":"Policy result cache TTL in seconds","required":false,"type":"integer"},{"name":"any","in":"body","description":"Input data passed to the policy execution runtime.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"},"headers":{"ETag":{"description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","type":"string"}}}},"schemes":["http"]}},"/policy/{group}/{policyName}/{version}/evaluation/did.json":{"get":{"tags":["policy"],"summary":"Evaluate policy","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"policy#Evaluate","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"type":"string"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"type":"string"},{"name":"version","in":"path","description":"Policy version.","required":true,"type":"string"},{"name":"x-evaluation-id","in":"header","description":"EvaluationID allows overwriting the randomly generated evaluationID","required":false,"type":"string"},{"name":"x-cache-ttl","in":"header","description":"Policy result cache TTL in seconds","required":false,"type":"integer"},{"name":"any","in":"body","description":"Input data passed to the policy execution runtime.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"},"headers":{"ETag":{"description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","type":"string"}}}},"schemes":["http"]}},"/policy/{group}/{policyName}/{version}/lock":{"post":{"tags":["policy"],"summary":"Lock policy","description":"Lock a policy so that it cannot be evaluated.","operationId":"policy#Lock","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"type":"string"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"type":"string"},{"name":"version","in":"path","description":"Policy version.","required":true,"type":"string"}],"responses":{"200":{"description":"OK response."}},"schemes":["http"]},"delete":{"tags":["policy"],"summary":"Unlock policy","description":"Unlock a policy so it can be evaluated again.","operationId":"policy#Unlock","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"type":"string"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"type":"string"},{"name":"version","in":"path","description":"Policy version.","required":true,"type":"string"}],"responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/v1/policies":{"get":{"tags":["policy"],"summary":"ListPolicies policy","description":"List policies from storage with optional filters.","operationId":"policy#ListPolicies","parameters":[{"name":"locked","in":"query","description":"Filter to return locked/unlocked policies (optional).","required":false,"type":"boolean"},{"name":"rego","in":"query","description":"Include policy source code in results (optional).","required":false,"type":"boolean"},{"name":"data","in":"query","description":"Include policy static data in results (optional). ","required":false,"type":"boolean"},{"name":"dataConfig","in":"query","description":"Include static data config (optional).","required":false,"type":"boolean"}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/PolicyListPoliciesResponseBody","required":["policies"]}}},"schemes":["http"]}}},"definitions":{"PolicyListPoliciesResponseBody":{"title":"PolicyListPoliciesResponseBody","type":"object","properties":{"policies":{"type":"array","items":{"$ref":"#/definitions/PolicyResponseBody"},"description":"JSON array of policies.","example":[{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."}]}},"example":{"policies":[{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."}]},"required":["policies"]},"PolicyResponseBody":{"title":"PolicyResponseBody","type":"object","properties":{"data":{"type":"string","description":"Policy static data.","example":"Accusamus enim."},"dataConfig":{"type":"string","description":"Policy static data optional configuration.","example":"Recusandae est rerum corrupti quia."},"group":{"type":"string","description":"Policy group.","example":"Optio quia et laborum."},"lastUpdate":{"type":"integer","description":"Last update (Unix timestamp).","example":1029654258457164464,"format":"int64"},"locked":{"type":"boolean","description":"Locked specifies if the policy is locked or allowed to execute.","example":true},"policyName":{"type":"string","description":"Policy name.","example":"Quia non voluptatibus error."},"rego":{"type":"string","description":"Policy rego source code.","example":"Ut amet."},"version":{"type":"string","description":"Policy version.","example":"In libero perspiciatis voluptatum ut soluta."}},"example":{"data":"Totam officia necessitatibus tempore nulla animi.","dataConfig":"Consequatur vel rerum rem ipsam nam.","group":"Adipisci inventore ipsum voluptatibus recusandae.","lastUpdate":1724369781608544610,"locked":true,"policyName":"Architecto itaque voluptatum voluptas ad.","rego":"Ab perspiciatis voluptatem pariatur corporis est rem.","version":"Nisi distinctio vitae."},"required":["group","policyName","version","locked","lastUpdate"]}}}
\ No newline at end of file
+{"swagger":"2.0","info":{"title":"Policy Service","description":"The policy service exposes HTTP API for executing policies.","version":""},"host":"localhost:8081","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/policy/{group}/{policyName}/{version}/evaluation":{"get":{"tags":["policy"],"summary":"Evaluate policy","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"policy#Evaluate#1","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"type":"string"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"type":"string"},{"name":"version","in":"path","description":"Policy version.","required":true,"type":"string"},{"name":"x-evaluation-id","in":"header","description":"EvaluationID allows overwriting the randomly generated evaluationID","required":false,"type":"string"},{"name":"x-cache-ttl","in":"header","description":"Policy result cache TTL in seconds","required":false,"type":"integer"},{"name":"any","in":"body","description":"Input data passed to the policy execution runtime.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"},"headers":{"ETag":{"description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","type":"string"}}}},"schemes":["http"]},"post":{"tags":["policy"],"summary":"Evaluate policy","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"policy#Evaluate#2","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"type":"string"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"type":"string"},{"name":"version","in":"path","description":"Policy version.","required":true,"type":"string"},{"name":"x-evaluation-id","in":"header","description":"EvaluationID allows overwriting the randomly generated evaluationID","required":false,"type":"string"},{"name":"x-cache-ttl","in":"header","description":"Policy result cache TTL in seconds","required":false,"type":"integer"},{"name":"any","in":"body","description":"Input data passed to the policy execution runtime.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"},"headers":{"ETag":{"description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","type":"string"}}}},"schemes":["http"]}},"/policy/{group}/{policyName}/{version}/evaluation/did.json":{"get":{"tags":["policy"],"summary":"Evaluate policy","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"policy#Evaluate","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"type":"string"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"type":"string"},{"name":"version","in":"path","description":"Policy version.","required":true,"type":"string"},{"name":"x-evaluation-id","in":"header","description":"EvaluationID allows overwriting the randomly generated evaluationID","required":false,"type":"string"},{"name":"x-cache-ttl","in":"header","description":"Policy result cache TTL in seconds","required":false,"type":"integer"},{"name":"any","in":"body","description":"Input data passed to the policy execution runtime.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"},"headers":{"ETag":{"description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","type":"string"}}}},"schemes":["http"]}},"/policy/{group}/{policyName}/{version}/lock":{"post":{"tags":["policy"],"summary":"Lock policy","description":"Lock a policy so that it cannot be evaluated.","operationId":"policy#Lock","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"type":"string"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"type":"string"},{"name":"version","in":"path","description":"Policy version.","required":true,"type":"string"}],"responses":{"200":{"description":"OK response."}},"schemes":["http"]},"delete":{"tags":["policy"],"summary":"Unlock policy","description":"Unlock a policy so it can be evaluated again.","operationId":"policy#Unlock","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"type":"string"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"type":"string"},{"name":"version","in":"path","description":"Policy version.","required":true,"type":"string"}],"responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/policy/{group}/{policyname}/{version}/notifychange":{"post":{"tags":["policy"],"summary":"Webhooks policy","description":"Gives ability to user to subscribe for policy change via webhooks","operationId":"policy#Webhooks","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"type":"string"},{"name":"policyname","in":"path","description":"Policy name.","required":true,"type":"string"},{"name":"version","in":"path","description":"Policy version.","required":true,"type":"string"},{"name":"WebhooksRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/PolicyWebhooksRequestBody","required":["webhook_url","subscriber"]}}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"}}},"schemes":["http"]}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/v1/policies":{"get":{"tags":["policy"],"summary":"ListPolicies policy","description":"List policies from storage with optional filters.","operationId":"policy#ListPolicies","parameters":[{"name":"locked","in":"query","description":"Filter to return locked/unlocked policies (optional).","required":false,"type":"boolean"},{"name":"rego","in":"query","description":"Include policy source code in results (optional).","required":false,"type":"boolean"},{"name":"data","in":"query","description":"Include policy static data in results (optional). ","required":false,"type":"boolean"},{"name":"dataConfig","in":"query","description":"Include static data config (optional).","required":false,"type":"boolean"}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/PolicyListPoliciesResponseBody","required":["policies"]}}},"schemes":["http"]}}},"definitions":{"PolicyListPoliciesResponseBody":{"title":"PolicyListPoliciesResponseBody","type":"object","properties":{"policies":{"type":"array","items":{"$ref":"#/definitions/PolicyResponseBody"},"description":"JSON array of policies.","example":[{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."},{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."},{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."}]}},"example":{"policies":[{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."},{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."},{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."},{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."}]},"required":["policies"]},"PolicyResponseBody":{"title":"PolicyResponseBody","type":"object","properties":{"data":{"type":"string","description":"Policy static data.","example":"Ipsa ad voluptatum maxime ut."},"dataConfig":{"type":"string","description":"Policy static data optional configuration.","example":"Aut asperiores."},"group":{"type":"string","description":"Policy group.","example":"Veritatis quam qui nostrum eaque."},"lastUpdate":{"type":"integer","description":"Last update (Unix timestamp).","example":1131015782715696616,"format":"int64"},"locked":{"type":"boolean","description":"Locked specifies if the policy is locked or allowed to execute.","example":false},"policyName":{"type":"string","description":"Policy name.","example":"Maiores et minus."},"rego":{"type":"string","description":"Policy rego source code.","example":"Delectus rerum molestiae possimus cum laboriosam."},"version":{"type":"string","description":"Policy version.","example":"Et dolores."}},"example":{"data":"Similique architecto.","dataConfig":"Sunt ut est ut molestias.","group":"Error minus vel voluptate quasi.","lastUpdate":2308837710267791288,"locked":true,"policyName":"Omnis molestiae tempora sed repellendus.","rego":"Vel sunt dolorem ea architecto iure.","version":"Debitis consectetur."},"required":["group","policyName","version","locked","lastUpdate"]},"PolicyWebhooksRequestBody":{"title":"PolicyWebhooksRequestBody","type":"object","properties":{"subscriber":{"type":"string","description":"Name of the subscriber for policy.","example":"Dolorum suscipit quae."},"webhook_url":{"type":"string","description":"Subscriber webhook url.","example":"Dolore laborum aperiam aut."}},"example":{"subscriber":"Accusamus et voluptatibus cupiditate ea.","webhook_url":"Et unde rerum dolore."},"required":["webhook_url","subscriber"]}}}
\ No newline at end of file
diff --git a/gen/http/openapi.yaml b/gen/http/openapi.yaml
index 6e529672c8c09484fbb8eb1b22fdb475f84e7b54..3f9c608a1b6d489fe057feca0e33bca839ae4c4f 100644
--- a/gen/http/openapi.yaml
+++ b/gen/http/openapi.yaml
@@ -234,6 +234,45 @@ paths:
                     description: OK response.
             schemes:
                 - http
+    /policy/{group}/{policyname}/{version}/notifychange:
+        post:
+            tags:
+                - policy
+            summary: Webhooks policy
+            description: Gives ability to user to subscribe for policy change via webhooks
+            operationId: policy#Webhooks
+            parameters:
+                - name: group
+                  in: path
+                  description: Policy group.
+                  required: true
+                  type: string
+                - name: policyname
+                  in: path
+                  description: Policy name.
+                  required: true
+                  type: string
+                - name: version
+                  in: path
+                  description: Policy version.
+                  required: true
+                  type: string
+                - name: WebhooksRequestBody
+                  in: body
+                  required: true
+                  schema:
+                    $ref: '#/definitions/PolicyWebhooksRequestBody'
+                    required:
+                        - webhook_url
+                        - subscriber
+            responses:
+                "200":
+                    description: OK response.
+                    schema:
+                        type: string
+                        format: binary
+            schemes:
+                - http
     /readiness:
         get:
             tags:
@@ -293,64 +332,64 @@ definitions:
                     $ref: '#/definitions/PolicyResponseBody'
                 description: JSON array of policies.
                 example:
-                    - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                      dataConfig: Qui non quia.
-                      group: Sequi adipisci et nulla.
-                      lastUpdate: 8181859392515170659
-                      locked: false
-                      policyName: Consequatur accusamus.
-                      rego: Sunt in et quia cum.
-                      version: In quis nesciunt autem et.
-                    - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                      dataConfig: Qui non quia.
-                      group: Sequi adipisci et nulla.
-                      lastUpdate: 8181859392515170659
-                      locked: false
-                      policyName: Consequatur accusamus.
-                      rego: Sunt in et quia cum.
-                      version: In quis nesciunt autem et.
-                    - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                      dataConfig: Qui non quia.
-                      group: Sequi adipisci et nulla.
-                      lastUpdate: 8181859392515170659
-                      locked: false
-                      policyName: Consequatur accusamus.
-                      rego: Sunt in et quia cum.
-                      version: In quis nesciunt autem et.
+                    - data: Accusamus enim.
+                      dataConfig: Recusandae est rerum corrupti quia.
+                      group: Optio quia et laborum.
+                      lastUpdate: 1029654258457164464
+                      locked: true
+                      policyName: Error maxime quasi quia non voluptatibus error.
+                      rego: Ut amet.
+                      version: In libero perspiciatis voluptatum ut soluta.
+                    - data: Accusamus enim.
+                      dataConfig: Recusandae est rerum corrupti quia.
+                      group: Optio quia et laborum.
+                      lastUpdate: 1029654258457164464
+                      locked: true
+                      policyName: Error maxime quasi quia non voluptatibus error.
+                      rego: Ut amet.
+                      version: In libero perspiciatis voluptatum ut soluta.
+                    - data: Accusamus enim.
+                      dataConfig: Recusandae est rerum corrupti quia.
+                      group: Optio quia et laborum.
+                      lastUpdate: 1029654258457164464
+                      locked: true
+                      policyName: Error maxime quasi quia non voluptatibus error.
+                      rego: Ut amet.
+                      version: In libero perspiciatis voluptatum ut soluta.
         example:
             policies:
-                - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                  dataConfig: Qui non quia.
-                  group: Sequi adipisci et nulla.
-                  lastUpdate: 8181859392515170659
-                  locked: false
-                  policyName: Consequatur accusamus.
-                  rego: Sunt in et quia cum.
-                  version: In quis nesciunt autem et.
-                - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                  dataConfig: Qui non quia.
-                  group: Sequi adipisci et nulla.
-                  lastUpdate: 8181859392515170659
-                  locked: false
-                  policyName: Consequatur accusamus.
-                  rego: Sunt in et quia cum.
-                  version: In quis nesciunt autem et.
-                - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                  dataConfig: Qui non quia.
-                  group: Sequi adipisci et nulla.
-                  lastUpdate: 8181859392515170659
-                  locked: false
-                  policyName: Consequatur accusamus.
-                  rego: Sunt in et quia cum.
-                  version: In quis nesciunt autem et.
-                - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                  dataConfig: Qui non quia.
-                  group: Sequi adipisci et nulla.
-                  lastUpdate: 8181859392515170659
-                  locked: false
-                  policyName: Consequatur accusamus.
-                  rego: Sunt in et quia cum.
-                  version: In quis nesciunt autem et.
+                - data: Accusamus enim.
+                  dataConfig: Recusandae est rerum corrupti quia.
+                  group: Optio quia et laborum.
+                  lastUpdate: 1029654258457164464
+                  locked: true
+                  policyName: Error maxime quasi quia non voluptatibus error.
+                  rego: Ut amet.
+                  version: In libero perspiciatis voluptatum ut soluta.
+                - data: Accusamus enim.
+                  dataConfig: Recusandae est rerum corrupti quia.
+                  group: Optio quia et laborum.
+                  lastUpdate: 1029654258457164464
+                  locked: true
+                  policyName: Error maxime quasi quia non voluptatibus error.
+                  rego: Ut amet.
+                  version: In libero perspiciatis voluptatum ut soluta.
+                - data: Accusamus enim.
+                  dataConfig: Recusandae est rerum corrupti quia.
+                  group: Optio quia et laborum.
+                  lastUpdate: 1029654258457164464
+                  locked: true
+                  policyName: Error maxime quasi quia non voluptatibus error.
+                  rego: Ut amet.
+                  version: In libero perspiciatis voluptatum ut soluta.
+                - data: Accusamus enim.
+                  dataConfig: Recusandae est rerum corrupti quia.
+                  group: Optio quia et laborum.
+                  lastUpdate: 1029654258457164464
+                  locked: true
+                  policyName: Error maxime quasi quia non voluptatibus error.
+                  rego: Ut amet.
+                  version: In libero perspiciatis voluptatum ut soluta.
         required:
             - policies
     PolicyResponseBody:
@@ -360,48 +399,66 @@ definitions:
             data:
                 type: string
                 description: Policy static data.
-                example: Accusamus enim.
+                example: Ipsa ad voluptatum maxime ut.
             dataConfig:
                 type: string
                 description: Policy static data optional configuration.
-                example: Recusandae est rerum corrupti quia.
+                example: Aut asperiores.
             group:
                 type: string
                 description: Policy group.
-                example: Optio quia et laborum.
+                example: Veritatis quam qui nostrum eaque.
             lastUpdate:
                 type: integer
                 description: Last update (Unix timestamp).
-                example: 1029654258457164464
+                example: 1131015782715696616
                 format: int64
             locked:
                 type: boolean
                 description: Locked specifies if the policy is locked or allowed to execute.
-                example: true
+                example: false
             policyName:
                 type: string
                 description: Policy name.
-                example: Quia non voluptatibus error.
+                example: Maiores et minus.
             rego:
                 type: string
                 description: Policy rego source code.
-                example: Ut amet.
+                example: Delectus rerum molestiae possimus cum laboriosam.
             version:
                 type: string
                 description: Policy version.
-                example: In libero perspiciatis voluptatum ut soluta.
+                example: Et dolores.
         example:
-            data: Totam officia necessitatibus tempore nulla animi.
-            dataConfig: Consequatur vel rerum rem ipsam nam.
-            group: Adipisci inventore ipsum voluptatibus recusandae.
-            lastUpdate: 1724369781608544610
+            data: Similique architecto.
+            dataConfig: Sunt ut est ut molestias.
+            group: Error minus vel voluptate quasi.
+            lastUpdate: 2308837710267791288
             locked: true
-            policyName: Architecto itaque voluptatum voluptas ad.
-            rego: Ab perspiciatis voluptatem pariatur corporis est rem.
-            version: Nisi distinctio vitae.
+            policyName: Omnis molestiae tempora sed repellendus.
+            rego: Vel sunt dolorem ea architecto iure.
+            version: Debitis consectetur.
         required:
             - group
             - policyName
             - version
             - locked
             - lastUpdate
+    PolicyWebhooksRequestBody:
+        title: PolicyWebhooksRequestBody
+        type: object
+        properties:
+            subscriber:
+                type: string
+                description: Name of the subscriber for policy.
+                example: Dolorum suscipit quae.
+            webhook_url:
+                type: string
+                description: Subscriber webhook url.
+                example: Dolore laborum aperiam aut.
+        example:
+            subscriber: Accusamus et voluptatibus cupiditate ea.
+            webhook_url: Et unde rerum dolore.
+        required:
+            - webhook_url
+            - subscriber
diff --git a/gen/http/openapi3.json b/gen/http/openapi3.json
index dc818a939caf50b3aac951cb4a916c3a9a07581f..dce151929456b7701c7b8f384d1f2591995077c2 100644
--- a/gen/http/openapi3.json
+++ b/gen/http/openapi3.json
@@ -1 +1 @@
-{"openapi":"3.0.3","info":{"title":"Policy Service","description":"The policy service exposes HTTP API for executing policies.","version":"1.0"},"servers":[{"url":"http://localhost:8081","description":"Policy Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/policy/{group}/{policyName}/{version}/evaluation":{"get":{"tags":["policy"],"summary":"Evaluate policy","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"policy#Evaluate#1","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"schema":{"type":"string","description":"Policy group.","example":"example"},"example":"example"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"schema":{"type":"string","description":"Policy name.","example":"example"},"example":"example"},{"name":"version","in":"path","description":"Policy version.","required":true,"schema":{"type":"string","description":"Policy version.","example":"1.0"},"example":"1.0"},{"name":"x-evaluation-id","in":"header","description":"EvaluationID allows overwriting the randomly generated evaluationID","allowEmptyValue":true,"schema":{"type":"string","description":"EvaluationID allows overwriting the randomly generated evaluationID","example":"did:web:example.com"},"example":"did:web:example.com"},{"name":"x-cache-ttl","in":"header","description":"Policy result cache TTL in seconds","allowEmptyValue":true,"schema":{"type":"integer","description":"Policy result cache TTL in seconds","example":60,"format":"int64"},"example":60}],"requestBody":{"description":"Input data passed to the policy execution runtime.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Input data passed to the policy execution runtime.","example":"Aperiam dolores reiciendis ut voluptate amet.","format":"binary"},"example":"Et quis nisi vitae iure."}}},"responses":{"200":{"description":"OK response.","headers":{"ETag":{"description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","required":true,"schema":{"type":"string","description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","example":"Sed sit."},"example":"Et eaque."}},"content":{"application/json":{"schema":{"type":"string","description":"Arbitrary JSON response.","example":"Aut et.","format":"binary"},"example":"Et mollitia."}}}}},"post":{"tags":["policy"],"summary":"Evaluate policy","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"policy#Evaluate#2","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"schema":{"type":"string","description":"Policy group.","example":"example"},"example":"example"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"schema":{"type":"string","description":"Policy name.","example":"example"},"example":"example"},{"name":"version","in":"path","description":"Policy version.","required":true,"schema":{"type":"string","description":"Policy version.","example":"1.0"},"example":"1.0"},{"name":"x-evaluation-id","in":"header","description":"EvaluationID allows overwriting the randomly generated evaluationID","allowEmptyValue":true,"schema":{"type":"string","description":"EvaluationID allows overwriting the randomly generated evaluationID","example":"did:web:example.com"},"example":"did:web:example.com"},{"name":"x-cache-ttl","in":"header","description":"Policy result cache TTL in seconds","allowEmptyValue":true,"schema":{"type":"integer","description":"Policy result cache TTL in seconds","example":60,"format":"int64"},"example":60}],"requestBody":{"description":"Input data passed to the policy execution runtime.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Input data passed to the policy execution runtime.","example":"Aperiam dolores reiciendis ut voluptate amet.","format":"binary"},"example":"Non quo ut molestias rerum sunt."}}},"responses":{"200":{"description":"OK response.","headers":{"ETag":{"description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","required":true,"schema":{"type":"string","description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","example":"Omnis dolores totam voluptatem rerum."},"example":"Est impedit."}},"content":{"application/json":{"schema":{"type":"string","description":"Arbitrary JSON response.","example":"Aut et.","format":"binary"},"example":"Consequatur ut suscipit."}}}}}},"/policy/{group}/{policyName}/{version}/evaluation/did.json":{"get":{"tags":["policy"],"summary":"Evaluate policy","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"policy#Evaluate","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"schema":{"type":"string","description":"Policy group.","example":"example"},"example":"example"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"schema":{"type":"string","description":"Policy name.","example":"example"},"example":"example"},{"name":"version","in":"path","description":"Policy version.","required":true,"schema":{"type":"string","description":"Policy version.","example":"1.0"},"example":"1.0"},{"name":"x-evaluation-id","in":"header","description":"EvaluationID allows overwriting the randomly generated evaluationID","allowEmptyValue":true,"schema":{"type":"string","description":"EvaluationID allows overwriting the randomly generated evaluationID","example":"did:web:example.com"},"example":"did:web:example.com"},{"name":"x-cache-ttl","in":"header","description":"Policy result cache TTL in seconds","allowEmptyValue":true,"schema":{"type":"integer","description":"Policy result cache TTL in seconds","example":60,"format":"int64"},"example":60}],"requestBody":{"description":"Input data passed to the policy execution runtime.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Input data passed to the policy execution runtime.","example":"Aperiam dolores reiciendis ut voluptate amet.","format":"binary"},"example":"Dolore laborum aperiam aut."}}},"responses":{"200":{"description":"OK response.","headers":{"ETag":{"description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","required":true,"schema":{"type":"string","description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","example":"Dolorum suscipit quae."},"example":"Accusamus et voluptatibus cupiditate ea."}},"content":{"application/json":{"schema":{"type":"string","description":"Arbitrary JSON response.","example":"Aut et.","format":"binary"},"example":"Inventore ut doloremque recusandae."}}}}}},"/policy/{group}/{policyName}/{version}/lock":{"delete":{"tags":["policy"],"summary":"Unlock policy","description":"Unlock a policy so it can be evaluated again.","operationId":"policy#Unlock","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"schema":{"type":"string","description":"Policy group.","example":"Explicabo expedita ipsum minus ipsam at vel."},"example":"Nisi et praesentium ut reiciendis."},{"name":"policyName","in":"path","description":"Policy name.","required":true,"schema":{"type":"string","description":"Policy name.","example":"Dolorum cupiditate provident."},"example":"Dolor dolorem modi aut officiis veritatis impedit."},{"name":"version","in":"path","description":"Policy version.","required":true,"schema":{"type":"string","description":"Policy version.","example":"Recusandae eligendi."},"example":"Id quibusdam quia deserunt officiis."}],"responses":{"200":{"description":"OK response."}}},"post":{"tags":["policy"],"summary":"Lock policy","description":"Lock a policy so that it cannot be evaluated.","operationId":"policy#Lock","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"schema":{"type":"string","description":"Policy group.","example":"Neque et sed modi accusantium."},"example":"Rerum asperiores nulla."},{"name":"policyName","in":"path","description":"Policy name.","required":true,"schema":{"type":"string","description":"Policy name.","example":"Tenetur rerum necessitatibus fugit."},"example":"Ut velit aut nobis repellendus."},{"name":"version","in":"path","description":"Policy version.","required":true,"schema":{"type":"string","description":"Policy version.","example":"Rem et occaecati quam."},"example":"Laborum harum voluptate et ut similique doloremque."}],"responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/policies":{"get":{"tags":["policy"],"summary":"ListPolicies policy","description":"List policies from storage with optional filters.","operationId":"policy#ListPolicies","parameters":[{"name":"locked","in":"query","description":"Filter to return locked/unlocked policies (optional).","allowEmptyValue":true,"schema":{"type":"boolean","description":"Filter to return locked/unlocked policies (optional).","example":false},"example":true},{"name":"rego","in":"query","description":"Include policy source code in results (optional).","allowEmptyValue":true,"schema":{"type":"boolean","description":"Include policy source code in results (optional).","example":false},"example":true},{"name":"data","in":"query","description":"Include policy static data in results (optional). ","allowEmptyValue":true,"schema":{"type":"boolean","description":"Include policy static data in results (optional). ","example":false},"example":false},{"name":"dataConfig","in":"query","description":"Include static data config (optional).","allowEmptyValue":true,"schema":{"type":"boolean","description":"Include static data config (optional).","example":false},"example":true}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PoliciesResult"},"example":{"policies":[{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."}]}}}}}}}},"components":{"schemas":{"PoliciesResult":{"type":"object","properties":{"policies":{"type":"array","items":{"$ref":"#/components/schemas/Policy"},"description":"JSON array of policies.","example":[{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."}]}},"example":{"policies":[{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."},{"data":"Commodi nemo fugiat id praesentium accusantium expedita.","dataConfig":"Qui non quia.","group":"Sequi adipisci et nulla.","lastUpdate":8181859392515170659,"locked":false,"policyName":"Consequatur accusamus.","rego":"Sunt in et quia cum.","version":"In quis nesciunt autem et."}]},"required":["policies"]},"Policy":{"type":"object","properties":{"data":{"type":"string","description":"Policy static data.","example":"Ipsa ad voluptatum maxime ut."},"dataConfig":{"type":"string","description":"Policy static data optional configuration.","example":"Aut asperiores."},"group":{"type":"string","description":"Policy group.","example":"Veritatis quam qui nostrum eaque."},"lastUpdate":{"type":"integer","description":"Last update (Unix timestamp).","example":1131015782715696616,"format":"int64"},"locked":{"type":"boolean","description":"Locked specifies if the policy is locked or allowed to execute.","example":false},"policyName":{"type":"string","description":"Policy name.","example":"Maiores et minus."},"rego":{"type":"string","description":"Policy rego source code.","example":"Delectus rerum molestiae possimus cum laboriosam."},"version":{"type":"string","description":"Policy version.","example":"Et dolores."}},"example":{"data":"Similique architecto.","dataConfig":"Sunt ut est ut molestias.","group":"Error minus vel voluptate quasi.","lastUpdate":2308837710267791288,"locked":true,"policyName":"Omnis molestiae tempora sed repellendus.","rego":"Vel sunt dolorem ea architecto iure.","version":"Debitis consectetur."},"required":["group","policyName","version","locked","lastUpdate"]}}},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"policy","description":"Policy Service provides evaluation of policies through Open Policy Agent."}]}
\ No newline at end of file
+{"openapi":"3.0.3","info":{"title":"Policy Service","description":"The policy service exposes HTTP API for executing policies.","version":"1.0"},"servers":[{"url":"http://localhost:8081","description":"Policy Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/policy/{group}/{policyName}/{version}/evaluation":{"get":{"tags":["policy"],"summary":"Evaluate policy","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"policy#Evaluate#1","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"schema":{"type":"string","description":"Policy group.","example":"example"},"example":"example"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"schema":{"type":"string","description":"Policy name.","example":"example"},"example":"example"},{"name":"version","in":"path","description":"Policy version.","required":true,"schema":{"type":"string","description":"Policy version.","example":"1.0"},"example":"1.0"},{"name":"x-evaluation-id","in":"header","description":"EvaluationID allows overwriting the randomly generated evaluationID","allowEmptyValue":true,"schema":{"type":"string","description":"EvaluationID allows overwriting the randomly generated evaluationID","example":"did:web:example.com"},"example":"did:web:example.com"},{"name":"x-cache-ttl","in":"header","description":"Policy result cache TTL in seconds","allowEmptyValue":true,"schema":{"type":"integer","description":"Policy result cache TTL in seconds","example":60,"format":"int64"},"example":60}],"requestBody":{"description":"Input data passed to the policy execution runtime.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Input data passed to the policy execution runtime.","example":"Inventore ut doloremque recusandae.","format":"binary"},"example":"Aut accusantium in."}}},"responses":{"200":{"description":"OK response.","headers":{"ETag":{"description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","required":true,"schema":{"type":"string","description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","example":"Culpa deserunt voluptatem culpa."},"example":"Cupiditate qui quo."}},"content":{"application/json":{"schema":{"type":"string","description":"Arbitrary JSON response.","example":"Et quis nisi vitae iure.","format":"binary"},"example":"Dignissimos enim."}}}}},"post":{"tags":["policy"],"summary":"Evaluate policy","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"policy#Evaluate#2","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"schema":{"type":"string","description":"Policy group.","example":"example"},"example":"example"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"schema":{"type":"string","description":"Policy name.","example":"example"},"example":"example"},{"name":"version","in":"path","description":"Policy version.","required":true,"schema":{"type":"string","description":"Policy version.","example":"1.0"},"example":"1.0"},{"name":"x-evaluation-id","in":"header","description":"EvaluationID allows overwriting the randomly generated evaluationID","allowEmptyValue":true,"schema":{"type":"string","description":"EvaluationID allows overwriting the randomly generated evaluationID","example":"did:web:example.com"},"example":"did:web:example.com"},{"name":"x-cache-ttl","in":"header","description":"Policy result cache TTL in seconds","allowEmptyValue":true,"schema":{"type":"integer","description":"Policy result cache TTL in seconds","example":60,"format":"int64"},"example":60}],"requestBody":{"description":"Input data passed to the policy execution runtime.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Input data passed to the policy execution runtime.","example":"Inventore ut doloremque recusandae.","format":"binary"},"example":"Error et sunt maxime aperiam."}}},"responses":{"200":{"description":"OK response.","headers":{"ETag":{"description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","required":true,"schema":{"type":"string","description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","example":"Et sit qui fugit enim labore."},"example":"Molestiae fugiat harum quia corporis ullam natus."}},"content":{"application/json":{"schema":{"type":"string","description":"Arbitrary JSON response.","example":"Et quis nisi vitae iure.","format":"binary"},"example":"Animi omnis minima fuga numquam."}}}}}},"/policy/{group}/{policyName}/{version}/evaluation/did.json":{"get":{"tags":["policy"],"summary":"Evaluate policy","description":"Evaluate executes a policy with the given 'data' as input.","operationId":"policy#Evaluate","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"schema":{"type":"string","description":"Policy group.","example":"example"},"example":"example"},{"name":"policyName","in":"path","description":"Policy name.","required":true,"schema":{"type":"string","description":"Policy name.","example":"example"},"example":"example"},{"name":"version","in":"path","description":"Policy version.","required":true,"schema":{"type":"string","description":"Policy version.","example":"1.0"},"example":"1.0"},{"name":"x-evaluation-id","in":"header","description":"EvaluationID allows overwriting the randomly generated evaluationID","allowEmptyValue":true,"schema":{"type":"string","description":"EvaluationID allows overwriting the randomly generated evaluationID","example":"did:web:example.com"},"example":"did:web:example.com"},{"name":"x-cache-ttl","in":"header","description":"Policy result cache TTL in seconds","allowEmptyValue":true,"schema":{"type":"integer","description":"Policy result cache TTL in seconds","example":60,"format":"int64"},"example":60}],"requestBody":{"description":"Input data passed to the policy execution runtime.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Input data passed to the policy execution runtime.","example":"Inventore ut doloremque recusandae.","format":"binary"},"example":"Laborum dolor dolorem modi aut."}}},"responses":{"200":{"description":"OK response.","headers":{"ETag":{"description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","required":true,"schema":{"type":"string","description":"ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.","example":"Veritatis impedit rerum recusandae eligendi in."},"example":"Sapiente unde doloremque quae ullam qui optio."}},"content":{"application/json":{"schema":{"type":"string","description":"Arbitrary JSON response.","example":"Et quis nisi vitae iure.","format":"binary"},"example":"Iure rerum non cumque sapiente laborum voluptas."}}}}}},"/policy/{group}/{policyName}/{version}/lock":{"delete":{"tags":["policy"],"summary":"Unlock policy","description":"Unlock a policy so it can be evaluated again.","operationId":"policy#Unlock","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"schema":{"type":"string","description":"Policy group.","example":"Consequatur aut ipsam."},"example":"Aut provident ducimus vero adipisci nemo."},{"name":"policyName","in":"path","description":"Policy name.","required":true,"schema":{"type":"string","description":"Policy name.","example":"Itaque laborum."},"example":"Quos saepe dolorum qui tenetur aut."},{"name":"version","in":"path","description":"Policy version.","required":true,"schema":{"type":"string","description":"Policy version.","example":"Iusto mollitia rerum quis ut et."},"example":"Ipsam est alias officiis."}],"responses":{"200":{"description":"OK response."}}},"post":{"tags":["policy"],"summary":"Lock policy","description":"Lock a policy so that it cannot be evaluated.","operationId":"policy#Lock","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"schema":{"type":"string","description":"Policy group.","example":"Ipsum explicabo assumenda delectus."},"example":"Eius sed."},{"name":"policyName","in":"path","description":"Policy name.","required":true,"schema":{"type":"string","description":"Policy name.","example":"Rerum saepe dolores laborum odio."},"example":"Eos nemo repudiandae."},{"name":"version","in":"path","description":"Policy version.","required":true,"schema":{"type":"string","description":"Policy version.","example":"Eveniet voluptas rerum."},"example":"Facilis tempora dolor consectetur."}],"responses":{"200":{"description":"OK response."}}}},"/policy/{group}/{policyname}/{version}/notifychange":{"post":{"tags":["policy"],"summary":"Webhooks policy","description":"Gives ability to user to subscribe for policy change via webhooks","operationId":"policy#Webhooks","parameters":[{"name":"group","in":"path","description":"Policy group.","required":true,"schema":{"type":"string","description":"Policy group.","example":"Aut quas eos qui minima."},"example":"Est non."},{"name":"policyname","in":"path","description":"Policy name.","required":true,"schema":{"type":"string","description":"Policy name.","example":"Minima aut in quis et qui."},"example":"Deleniti natus eos cumque asperiores."},{"name":"version","in":"path","description":"Policy version.","required":true,"schema":{"type":"string","description":"Policy version.","example":"Commodi illo quidem omnis eveniet et."},"example":"Adipisci harum."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhooksRequestBody"},"example":{"subscriber":"Est totam officia necessitatibus tempore.","webhook_url":"Ad ab perspiciatis voluptatem pariatur corporis est."}}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Ut reiciendis fugit dolorum cupiditate.","format":"binary"},"example":"Ratione sit numquam non cupiditate sed omnis."}}}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/policies":{"get":{"tags":["policy"],"summary":"ListPolicies policy","description":"List policies from storage with optional filters.","operationId":"policy#ListPolicies","parameters":[{"name":"locked","in":"query","description":"Filter to return locked/unlocked policies (optional).","allowEmptyValue":true,"schema":{"type":"boolean","description":"Filter to return locked/unlocked policies (optional).","example":false},"example":false},{"name":"rego","in":"query","description":"Include policy source code in results (optional).","allowEmptyValue":true,"schema":{"type":"boolean","description":"Include policy source code in results (optional).","example":false},"example":false},{"name":"data","in":"query","description":"Include policy static data in results (optional). ","allowEmptyValue":true,"schema":{"type":"boolean","description":"Include policy static data in results (optional). ","example":true},"example":true},{"name":"dataConfig","in":"query","description":"Include static data config (optional).","allowEmptyValue":true,"schema":{"type":"boolean","description":"Include static data config (optional).","example":true},"example":true}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PoliciesResult"},"example":{"policies":[{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."},{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."},{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."},{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."}]}}}}}}}},"components":{"schemas":{"PoliciesResult":{"type":"object","properties":{"policies":{"type":"array","items":{"$ref":"#/components/schemas/Policy"},"description":"JSON array of policies.","example":[{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."},{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."}]}},"example":{"policies":[{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."},{"data":"Accusamus enim.","dataConfig":"Recusandae est rerum corrupti quia.","group":"Optio quia et laborum.","lastUpdate":1029654258457164464,"locked":true,"policyName":"Error maxime quasi quia non voluptatibus error.","rego":"Ut amet.","version":"In libero perspiciatis voluptatum ut soluta."}]},"required":["policies"]},"Policy":{"type":"object","properties":{"data":{"type":"string","description":"Policy static data.","example":"Non quo ut molestias rerum sunt."},"dataConfig":{"type":"string","description":"Policy static data optional configuration.","example":"Omnis dolores totam voluptatem rerum."},"group":{"type":"string","description":"Policy group.","example":"Iusto ut."},"lastUpdate":{"type":"integer","description":"Last update (Unix timestamp).","example":3092150594834775360,"format":"int64"},"locked":{"type":"boolean","description":"Locked specifies if the policy is locked or allowed to execute.","example":false},"policyName":{"type":"string","description":"Policy name.","example":"Sed sit."},"rego":{"type":"string","description":"Policy rego source code.","example":"Et mollitia."},"version":{"type":"string","description":"Policy version.","example":"Et eaque."}},"example":{"data":"Rerum asperiores nulla.","dataConfig":"Tenetur rerum necessitatibus fugit.","group":"Est impedit.","lastUpdate":2958895584654309878,"locked":false,"policyName":"Enim omnis.","rego":"Neque et sed modi accusantium.","version":"Consequatur ut suscipit."},"required":["group","policyName","version","locked","lastUpdate"]},"WebhooksRequestBody":{"type":"object","properties":{"subscriber":{"type":"string","description":"Name of the subscriber for policy.","example":"Harum voluptate et ut similique doloremque quis."},"webhook_url":{"type":"string","description":"Subscriber webhook url.","example":"Repellendus quis rem et occaecati quam tempora."}},"example":{"subscriber":"Vel saepe nisi et.","webhook_url":"Expedita ipsum minus ipsam."},"required":["webhook_url","subscriber"]}}},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"policy","description":"Policy Service provides evaluation of policies through Open Policy Agent."}]}
\ No newline at end of file
diff --git a/gen/http/openapi3.yaml b/gen/http/openapi3.yaml
index e49a8b9a48f6b8f8eeec706997f46bcb09ae812b..2e47c1a30d9321501ff5d251f769147b509c0878 100644
--- a/gen/http/openapi3.yaml
+++ b/gen/http/openapi3.yaml
@@ -78,9 +78,9 @@ paths:
                         schema:
                             type: string
                             description: Input data passed to the policy execution runtime.
-                            example: Aperiam dolores reiciendis ut voluptate amet.
+                            example: Inventore ut doloremque recusandae.
                             format: binary
-                        example: Et quis nisi vitae iure.
+                        example: Aut accusantium in.
             responses:
                 "200":
                     description: OK response.
@@ -91,16 +91,16 @@ paths:
                             schema:
                                 type: string
                                 description: ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.
-                                example: Sed sit.
-                            example: Et eaque.
+                                example: Culpa deserunt voluptatem culpa.
+                            example: Cupiditate qui quo.
                     content:
                         application/json:
                             schema:
                                 type: string
                                 description: Arbitrary JSON response.
-                                example: Aut et.
+                                example: Et quis nisi vitae iure.
                                 format: binary
-                            example: Et mollitia.
+                            example: Dignissimos enim.
         post:
             tags:
                 - policy
@@ -162,9 +162,9 @@ paths:
                         schema:
                             type: string
                             description: Input data passed to the policy execution runtime.
-                            example: Aperiam dolores reiciendis ut voluptate amet.
+                            example: Inventore ut doloremque recusandae.
                             format: binary
-                        example: Non quo ut molestias rerum sunt.
+                        example: Error et sunt maxime aperiam.
             responses:
                 "200":
                     description: OK response.
@@ -175,16 +175,16 @@ paths:
                             schema:
                                 type: string
                                 description: ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.
-                                example: Omnis dolores totam voluptatem rerum.
-                            example: Est impedit.
+                                example: Et sit qui fugit enim labore.
+                            example: Molestiae fugiat harum quia corporis ullam natus.
                     content:
                         application/json:
                             schema:
                                 type: string
                                 description: Arbitrary JSON response.
-                                example: Aut et.
+                                example: Et quis nisi vitae iure.
                                 format: binary
-                            example: Consequatur ut suscipit.
+                            example: Animi omnis minima fuga numquam.
     /policy/{group}/{policyName}/{version}/evaluation/did.json:
         get:
             tags:
@@ -247,9 +247,9 @@ paths:
                         schema:
                             type: string
                             description: Input data passed to the policy execution runtime.
-                            example: Aperiam dolores reiciendis ut voluptate amet.
+                            example: Inventore ut doloremque recusandae.
                             format: binary
-                        example: Dolore laborum aperiam aut.
+                        example: Laborum dolor dolorem modi aut.
             responses:
                 "200":
                     description: OK response.
@@ -260,16 +260,16 @@ paths:
                             schema:
                                 type: string
                                 description: ETag contains unique identifier of the policy evaluation and can be used to later retrieve the results from Cache.
-                                example: Dolorum suscipit quae.
-                            example: Accusamus et voluptatibus cupiditate ea.
+                                example: Veritatis impedit rerum recusandae eligendi in.
+                            example: Sapiente unde doloremque quae ullam qui optio.
                     content:
                         application/json:
                             schema:
                                 type: string
                                 description: Arbitrary JSON response.
-                                example: Aut et.
+                                example: Et quis nisi vitae iure.
                                 format: binary
-                            example: Inventore ut doloremque recusandae.
+                            example: Iure rerum non cumque sapiente laborum voluptas.
     /policy/{group}/{policyName}/{version}/lock:
         delete:
             tags:
@@ -285,8 +285,8 @@ paths:
                   schema:
                     type: string
                     description: Policy group.
-                    example: Explicabo expedita ipsum minus ipsam at vel.
-                  example: Nisi et praesentium ut reiciendis.
+                    example: Consequatur aut ipsam.
+                  example: Aut provident ducimus vero adipisci nemo.
                 - name: policyName
                   in: path
                   description: Policy name.
@@ -294,8 +294,8 @@ paths:
                   schema:
                     type: string
                     description: Policy name.
-                    example: Dolorum cupiditate provident.
-                  example: Dolor dolorem modi aut officiis veritatis impedit.
+                    example: Itaque laborum.
+                  example: Quos saepe dolorum qui tenetur aut.
                 - name: version
                   in: path
                   description: Policy version.
@@ -303,8 +303,8 @@ paths:
                   schema:
                     type: string
                     description: Policy version.
-                    example: Recusandae eligendi.
-                  example: Id quibusdam quia deserunt officiis.
+                    example: Iusto mollitia rerum quis ut et.
+                  example: Ipsam est alias officiis.
             responses:
                 "200":
                     description: OK response.
@@ -322,8 +322,8 @@ paths:
                   schema:
                     type: string
                     description: Policy group.
-                    example: Neque et sed modi accusantium.
-                  example: Rerum asperiores nulla.
+                    example: Ipsum explicabo assumenda delectus.
+                  example: Eius sed.
                 - name: policyName
                   in: path
                   description: Policy name.
@@ -331,8 +331,8 @@ paths:
                   schema:
                     type: string
                     description: Policy name.
-                    example: Tenetur rerum necessitatibus fugit.
-                  example: Ut velit aut nobis repellendus.
+                    example: Rerum saepe dolores laborum odio.
+                  example: Eos nemo repudiandae.
                 - name: version
                   in: path
                   description: Policy version.
@@ -340,11 +340,65 @@ paths:
                   schema:
                     type: string
                     description: Policy version.
-                    example: Rem et occaecati quam.
-                  example: Laborum harum voluptate et ut similique doloremque.
+                    example: Eveniet voluptas rerum.
+                  example: Facilis tempora dolor consectetur.
             responses:
                 "200":
                     description: OK response.
+    /policy/{group}/{policyname}/{version}/notifychange:
+        post:
+            tags:
+                - policy
+            summary: Webhooks policy
+            description: Gives ability to user to subscribe for policy change via webhooks
+            operationId: policy#Webhooks
+            parameters:
+                - name: group
+                  in: path
+                  description: Policy group.
+                  required: true
+                  schema:
+                    type: string
+                    description: Policy group.
+                    example: Aut quas eos qui minima.
+                  example: Est non.
+                - name: policyname
+                  in: path
+                  description: Policy name.
+                  required: true
+                  schema:
+                    type: string
+                    description: Policy name.
+                    example: Minima aut in quis et qui.
+                  example: Deleniti natus eos cumque asperiores.
+                - name: version
+                  in: path
+                  description: Policy version.
+                  required: true
+                  schema:
+                    type: string
+                    description: Policy version.
+                    example: Commodi illo quidem omnis eveniet et.
+                  example: Adipisci harum.
+            requestBody:
+                required: true
+                content:
+                    application/json:
+                        schema:
+                            $ref: '#/components/schemas/WebhooksRequestBody'
+                        example:
+                            subscriber: Est totam officia necessitatibus tempore.
+                            webhook_url: Ad ab perspiciatis voluptatem pariatur corporis est.
+            responses:
+                "200":
+                    description: OK response.
+                    content:
+                        application/json:
+                            schema:
+                                type: string
+                                example: Ut reiciendis fugit dolorum cupiditate.
+                                format: binary
+                            example: Ratione sit numquam non cupiditate sed omnis.
     /readiness:
         get:
             tags:
@@ -370,7 +424,7 @@ paths:
                     type: boolean
                     description: Filter to return locked/unlocked policies (optional).
                     example: false
-                  example: true
+                  example: false
                 - name: rego
                   in: query
                   description: Include policy source code in results (optional).
@@ -379,7 +433,7 @@ paths:
                     type: boolean
                     description: Include policy source code in results (optional).
                     example: false
-                  example: true
+                  example: false
                 - name: data
                   in: query
                   description: 'Include policy static data in results (optional). '
@@ -387,8 +441,8 @@ paths:
                   schema:
                     type: boolean
                     description: 'Include policy static data in results (optional). '
-                    example: false
-                  example: false
+                    example: true
+                  example: true
                 - name: dataConfig
                   in: query
                   description: Include static data config (optional).
@@ -396,7 +450,7 @@ paths:
                   schema:
                     type: boolean
                     description: Include static data config (optional).
-                    example: false
+                    example: true
                   example: true
             responses:
                 "200":
@@ -407,38 +461,38 @@ paths:
                                 $ref: '#/components/schemas/PoliciesResult'
                             example:
                                 policies:
-                                    - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                                      dataConfig: Qui non quia.
-                                      group: Sequi adipisci et nulla.
-                                      lastUpdate: 8181859392515170659
-                                      locked: false
-                                      policyName: Consequatur accusamus.
-                                      rego: Sunt in et quia cum.
-                                      version: In quis nesciunt autem et.
-                                    - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                                      dataConfig: Qui non quia.
-                                      group: Sequi adipisci et nulla.
-                                      lastUpdate: 8181859392515170659
-                                      locked: false
-                                      policyName: Consequatur accusamus.
-                                      rego: Sunt in et quia cum.
-                                      version: In quis nesciunt autem et.
-                                    - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                                      dataConfig: Qui non quia.
-                                      group: Sequi adipisci et nulla.
-                                      lastUpdate: 8181859392515170659
-                                      locked: false
-                                      policyName: Consequatur accusamus.
-                                      rego: Sunt in et quia cum.
-                                      version: In quis nesciunt autem et.
-                                    - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                                      dataConfig: Qui non quia.
-                                      group: Sequi adipisci et nulla.
-                                      lastUpdate: 8181859392515170659
-                                      locked: false
-                                      policyName: Consequatur accusamus.
-                                      rego: Sunt in et quia cum.
-                                      version: In quis nesciunt autem et.
+                                    - data: Accusamus enim.
+                                      dataConfig: Recusandae est rerum corrupti quia.
+                                      group: Optio quia et laborum.
+                                      lastUpdate: 1029654258457164464
+                                      locked: true
+                                      policyName: Error maxime quasi quia non voluptatibus error.
+                                      rego: Ut amet.
+                                      version: In libero perspiciatis voluptatum ut soluta.
+                                    - data: Accusamus enim.
+                                      dataConfig: Recusandae est rerum corrupti quia.
+                                      group: Optio quia et laborum.
+                                      lastUpdate: 1029654258457164464
+                                      locked: true
+                                      policyName: Error maxime quasi quia non voluptatibus error.
+                                      rego: Ut amet.
+                                      version: In libero perspiciatis voluptatum ut soluta.
+                                    - data: Accusamus enim.
+                                      dataConfig: Recusandae est rerum corrupti quia.
+                                      group: Optio quia et laborum.
+                                      lastUpdate: 1029654258457164464
+                                      locked: true
+                                      policyName: Error maxime quasi quia non voluptatibus error.
+                                      rego: Ut amet.
+                                      version: In libero perspiciatis voluptatum ut soluta.
+                                    - data: Accusamus enim.
+                                      dataConfig: Recusandae est rerum corrupti quia.
+                                      group: Optio quia et laborum.
+                                      lastUpdate: 1029654258457164464
+                                      locked: true
+                                      policyName: Error maxime quasi quia non voluptatibus error.
+                                      rego: Ut amet.
+                                      version: In libero perspiciatis voluptatum ut soluta.
 components:
     schemas:
         PoliciesResult:
@@ -450,64 +504,40 @@ components:
                         $ref: '#/components/schemas/Policy'
                     description: JSON array of policies.
                     example:
-                        - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                          dataConfig: Qui non quia.
-                          group: Sequi adipisci et nulla.
-                          lastUpdate: 8181859392515170659
-                          locked: false
-                          policyName: Consequatur accusamus.
-                          rego: Sunt in et quia cum.
-                          version: In quis nesciunt autem et.
-                        - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                          dataConfig: Qui non quia.
-                          group: Sequi adipisci et nulla.
-                          lastUpdate: 8181859392515170659
-                          locked: false
-                          policyName: Consequatur accusamus.
-                          rego: Sunt in et quia cum.
-                          version: In quis nesciunt autem et.
-                        - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                          dataConfig: Qui non quia.
-                          group: Sequi adipisci et nulla.
-                          lastUpdate: 8181859392515170659
-                          locked: false
-                          policyName: Consequatur accusamus.
-                          rego: Sunt in et quia cum.
-                          version: In quis nesciunt autem et.
+                        - data: Accusamus enim.
+                          dataConfig: Recusandae est rerum corrupti quia.
+                          group: Optio quia et laborum.
+                          lastUpdate: 1029654258457164464
+                          locked: true
+                          policyName: Error maxime quasi quia non voluptatibus error.
+                          rego: Ut amet.
+                          version: In libero perspiciatis voluptatum ut soluta.
+                        - data: Accusamus enim.
+                          dataConfig: Recusandae est rerum corrupti quia.
+                          group: Optio quia et laborum.
+                          lastUpdate: 1029654258457164464
+                          locked: true
+                          policyName: Error maxime quasi quia non voluptatibus error.
+                          rego: Ut amet.
+                          version: In libero perspiciatis voluptatum ut soluta.
             example:
                 policies:
-                    - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                      dataConfig: Qui non quia.
-                      group: Sequi adipisci et nulla.
-                      lastUpdate: 8181859392515170659
-                      locked: false
-                      policyName: Consequatur accusamus.
-                      rego: Sunt in et quia cum.
-                      version: In quis nesciunt autem et.
-                    - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                      dataConfig: Qui non quia.
-                      group: Sequi adipisci et nulla.
-                      lastUpdate: 8181859392515170659
-                      locked: false
-                      policyName: Consequatur accusamus.
-                      rego: Sunt in et quia cum.
-                      version: In quis nesciunt autem et.
-                    - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                      dataConfig: Qui non quia.
-                      group: Sequi adipisci et nulla.
-                      lastUpdate: 8181859392515170659
-                      locked: false
-                      policyName: Consequatur accusamus.
-                      rego: Sunt in et quia cum.
-                      version: In quis nesciunt autem et.
-                    - data: Commodi nemo fugiat id praesentium accusantium expedita.
-                      dataConfig: Qui non quia.
-                      group: Sequi adipisci et nulla.
-                      lastUpdate: 8181859392515170659
-                      locked: false
-                      policyName: Consequatur accusamus.
-                      rego: Sunt in et quia cum.
-                      version: In quis nesciunt autem et.
+                    - data: Accusamus enim.
+                      dataConfig: Recusandae est rerum corrupti quia.
+                      group: Optio quia et laborum.
+                      lastUpdate: 1029654258457164464
+                      locked: true
+                      policyName: Error maxime quasi quia non voluptatibus error.
+                      rego: Ut amet.
+                      version: In libero perspiciatis voluptatum ut soluta.
+                    - data: Accusamus enim.
+                      dataConfig: Recusandae est rerum corrupti quia.
+                      group: Optio quia et laborum.
+                      lastUpdate: 1029654258457164464
+                      locked: true
+                      policyName: Error maxime quasi quia non voluptatibus error.
+                      rego: Ut amet.
+                      version: In libero perspiciatis voluptatum ut soluta.
             required:
                 - policies
         Policy:
@@ -516,19 +546,19 @@ components:
                 data:
                     type: string
                     description: Policy static data.
-                    example: Ipsa ad voluptatum maxime ut.
+                    example: Non quo ut molestias rerum sunt.
                 dataConfig:
                     type: string
                     description: Policy static data optional configuration.
-                    example: Aut asperiores.
+                    example: Omnis dolores totam voluptatem rerum.
                 group:
                     type: string
                     description: Policy group.
-                    example: Veritatis quam qui nostrum eaque.
+                    example: Iusto ut.
                 lastUpdate:
                     type: integer
                     description: Last update (Unix timestamp).
-                    example: 1131015782715696616
+                    example: 3092150594834775360
                     format: int64
                 locked:
                     type: boolean
@@ -537,30 +567,47 @@ components:
                 policyName:
                     type: string
                     description: Policy name.
-                    example: Maiores et minus.
+                    example: Sed sit.
                 rego:
                     type: string
                     description: Policy rego source code.
-                    example: Delectus rerum molestiae possimus cum laboriosam.
+                    example: Et mollitia.
                 version:
                     type: string
                     description: Policy version.
-                    example: Et dolores.
+                    example: Et eaque.
             example:
-                data: Similique architecto.
-                dataConfig: Sunt ut est ut molestias.
-                group: Error minus vel voluptate quasi.
-                lastUpdate: 2308837710267791288
-                locked: true
-                policyName: Omnis molestiae tempora sed repellendus.
-                rego: Vel sunt dolorem ea architecto iure.
-                version: Debitis consectetur.
+                data: Rerum asperiores nulla.
+                dataConfig: Tenetur rerum necessitatibus fugit.
+                group: Est impedit.
+                lastUpdate: 2958895584654309878
+                locked: false
+                policyName: Enim omnis.
+                rego: Neque et sed modi accusantium.
+                version: Consequatur ut suscipit.
             required:
                 - group
                 - policyName
                 - version
                 - locked
                 - lastUpdate
+        WebhooksRequestBody:
+            type: object
+            properties:
+                subscriber:
+                    type: string
+                    description: Name of the subscriber for policy.
+                    example: Harum voluptate et ut similique doloremque quis.
+                webhook_url:
+                    type: string
+                    description: Subscriber webhook url.
+                    example: Repellendus quis rem et occaecati quam tempora.
+            example:
+                subscriber: Vel saepe nisi et.
+                webhook_url: Expedita ipsum minus ipsam.
+            required:
+                - webhook_url
+                - subscriber
 tags:
     - name: health
       description: Health service provides health check endpoints.
diff --git a/gen/http/policy/client/cli.go b/gen/http/policy/client/cli.go
index c032452f7ed3cb2596000498d6a11acabb8f2773..fbd0d51da31d090091af5598c4d0c55ab21109e9 100644
--- a/gen/http/policy/client/cli.go
+++ b/gen/http/policy/client/cli.go
@@ -23,7 +23,7 @@ func BuildEvaluatePayload(policyEvaluateBody string, policyEvaluateGroup string,
 	{
 		err = json.Unmarshal([]byte(policyEvaluateBody), &body)
 		if err != nil {
-			return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "\"Quibusdam ab repellendus in illum.\"")
+			return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "\"Earum velit illum quia aliquam atque voluptatum.\"")
 		}
 	}
 	var group string
@@ -171,3 +171,37 @@ func BuildListPoliciesPayload(policyListPoliciesLocked string, policyListPolicie
 
 	return v, nil
 }
+
+// BuildWebhooksPayload builds the payload for the policy Webhooks endpoint
+// from CLI flags.
+func BuildWebhooksPayload(policyWebhooksBody string, policyWebhooksGroup string, policyWebhooksPolicyname string, policyWebhooksVersion string) (*policy.WebHooksRequest, error) {
+	var err error
+	var body WebhooksRequestBody
+	{
+		err = json.Unmarshal([]byte(policyWebhooksBody), &body)
+		if err != nil {
+			return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "'{\n      \"subscriber\": \"Est totam officia necessitatibus tempore.\",\n      \"webhook_url\": \"Ad ab perspiciatis voluptatem pariatur corporis est.\"\n   }'")
+		}
+	}
+	var group string
+	{
+		group = policyWebhooksGroup
+	}
+	var policyname string
+	{
+		policyname = policyWebhooksPolicyname
+	}
+	var version string
+	{
+		version = policyWebhooksVersion
+	}
+	v := &policy.WebHooksRequest{
+		WebhookURL: body.WebhookURL,
+		Subscriber: body.Subscriber,
+	}
+	v.Group = group
+	v.Policyname = policyname
+	v.Version = version
+
+	return v, nil
+}
diff --git a/gen/http/policy/client/client.go b/gen/http/policy/client/client.go
index afcf58c9ff68a7f4a4f708f7b555a90114059207..435cb3eb4fc22beb5429130272e604b6fd84876f 100644
--- a/gen/http/policy/client/client.go
+++ b/gen/http/policy/client/client.go
@@ -31,6 +31,10 @@ type Client struct {
 	// ListPolicies endpoint.
 	ListPoliciesDoer goahttp.Doer
 
+	// Webhooks Doer is the HTTP client used to make requests to the Webhooks
+	// endpoint.
+	WebhooksDoer goahttp.Doer
+
 	// RestoreResponseBody controls whether the response bodies are reset after
 	// decoding so they can be read again.
 	RestoreResponseBody bool
@@ -55,6 +59,7 @@ func NewClient(
 		LockDoer:            doer,
 		UnlockDoer:          doer,
 		ListPoliciesDoer:    doer,
+		WebhooksDoer:        doer,
 		RestoreResponseBody: restoreBody,
 		scheme:              scheme,
 		host:                host,
@@ -148,3 +153,27 @@ func (c *Client) ListPolicies() goa.Endpoint {
 		return decodeResponse(resp)
 	}
 }
+
+// Webhooks returns an endpoint that makes HTTP requests to the policy service
+// Webhooks server.
+func (c *Client) Webhooks() goa.Endpoint {
+	var (
+		encodeRequest  = EncodeWebhooksRequest(c.encoder)
+		decodeResponse = DecodeWebhooksResponse(c.decoder, c.RestoreResponseBody)
+	)
+	return func(ctx context.Context, v any) (any, error) {
+		req, err := c.BuildWebhooksRequest(ctx, v)
+		if err != nil {
+			return nil, err
+		}
+		err = encodeRequest(req, v)
+		if err != nil {
+			return nil, err
+		}
+		resp, err := c.WebhooksDoer.Do(req)
+		if err != nil {
+			return nil, goahttp.ErrRequestError("policy", "Webhooks", err)
+		}
+		return decodeResponse(resp)
+	}
+}
diff --git a/gen/http/policy/client/encode_decode.go b/gen/http/policy/client/encode_decode.go
index 417538d82bfd8fffd8819c87b9aab48745cd6445..8f864fb47dcd31ef495a11c203d9a1036dbfbebf 100644
--- a/gen/http/policy/client/encode_decode.go
+++ b/gen/http/policy/client/encode_decode.go
@@ -315,6 +315,86 @@ func DecodeListPoliciesResponse(decoder func(*http.Response) goahttp.Decoder, re
 	}
 }
 
+// BuildWebhooksRequest instantiates a HTTP request object with method and path
+// set to call the "policy" service "Webhooks" endpoint
+func (c *Client) BuildWebhooksRequest(ctx context.Context, v any) (*http.Request, error) {
+	var (
+		group      string
+		policyname string
+		version    string
+	)
+	{
+		p, ok := v.(*policy.WebHooksRequest)
+		if !ok {
+			return nil, goahttp.ErrInvalidType("policy", "Webhooks", "*policy.WebHooksRequest", v)
+		}
+		group = p.Group
+		policyname = p.Policyname
+		version = p.Version
+	}
+	u := &url.URL{Scheme: c.scheme, Host: c.host, Path: WebhooksPolicyPath(group, policyname, version)}
+	req, err := http.NewRequest("POST", u.String(), nil)
+	if err != nil {
+		return nil, goahttp.ErrInvalidURL("policy", "Webhooks", u.String(), err)
+	}
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	return req, nil
+}
+
+// EncodeWebhooksRequest returns an encoder for requests sent to the policy
+// Webhooks server.
+func EncodeWebhooksRequest(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, any) error {
+	return func(req *http.Request, v any) error {
+		p, ok := v.(*policy.WebHooksRequest)
+		if !ok {
+			return goahttp.ErrInvalidType("policy", "Webhooks", "*policy.WebHooksRequest", v)
+		}
+		body := NewWebhooksRequestBody(p)
+		if err := encoder(req).Encode(&body); err != nil {
+			return goahttp.ErrEncodingError("policy", "Webhooks", err)
+		}
+		return nil
+	}
+}
+
+// DecodeWebhooksResponse returns a decoder for responses returned by the
+// policy Webhooks endpoint. restoreBody controls whether the response body
+// should be restored after having been read.
+func DecodeWebhooksResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (any, error) {
+	return func(resp *http.Response) (any, error) {
+		if restoreBody {
+			b, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return nil, err
+			}
+			resp.Body = io.NopCloser(bytes.NewBuffer(b))
+			defer func() {
+				resp.Body = io.NopCloser(bytes.NewBuffer(b))
+			}()
+		} else {
+			defer resp.Body.Close()
+		}
+		switch resp.StatusCode {
+		case http.StatusOK:
+			var (
+				body any
+				err  error
+			)
+			err = decoder(resp).Decode(&body)
+			if err != nil {
+				return nil, goahttp.ErrDecodingError("policy", "Webhooks", err)
+			}
+			return body, nil
+		default:
+			body, _ := io.ReadAll(resp.Body)
+			return nil, goahttp.ErrInvalidResponse("policy", "Webhooks", resp.StatusCode, string(body))
+		}
+	}
+}
+
 // unmarshalPolicyResponseBodyToPolicyPolicy builds a value of type
 // *policy.Policy from a value of type *PolicyResponseBody.
 func unmarshalPolicyResponseBodyToPolicyPolicy(v *PolicyResponseBody) *policy.Policy {
diff --git a/gen/http/policy/client/paths.go b/gen/http/policy/client/paths.go
index a5da8845a897c497d06e6dc0ed55e98437560100..06a7d6be4315a562a788f5d8418b78268ffeceb7 100644
--- a/gen/http/policy/client/paths.go
+++ b/gen/http/policy/client/paths.go
@@ -40,3 +40,8 @@ func UnlockPolicyPath(group string, policyName string, version string) string {
 func ListPoliciesPolicyPath() string {
 	return "/v1/policies"
 }
+
+// WebhooksPolicyPath returns the URL path to the policy service Webhooks HTTP endpoint.
+func WebhooksPolicyPath(group string, policyname string, version string) string {
+	return fmt.Sprintf("/policy/%v/%v/%v/notifychange", group, policyname, version)
+}
diff --git a/gen/http/policy/client/types.go b/gen/http/policy/client/types.go
index 4f9370b3baf08b33de636c9855b34fbb7e16873d..f17e6ed9c0ad0a3a5cf312f4cd2848d7d76765be 100644
--- a/gen/http/policy/client/types.go
+++ b/gen/http/policy/client/types.go
@@ -12,6 +12,15 @@ import (
 	goa "goa.design/goa/v3/pkg"
 )
 
+// WebhooksRequestBody is the type of the "policy" service "Webhooks" endpoint
+// HTTP request body.
+type WebhooksRequestBody struct {
+	// Subscriber webhook url.
+	WebhookURL string `form:"webhook_url" json:"webhook_url" xml:"webhook_url"`
+	// Name of the subscriber for policy.
+	Subscriber string `form:"subscriber" json:"subscriber" xml:"subscriber"`
+}
+
 // ListPoliciesResponseBody is the type of the "policy" service "ListPolicies"
 // endpoint HTTP response body.
 type ListPoliciesResponseBody struct {
@@ -39,6 +48,16 @@ type PolicyResponseBody struct {
 	LastUpdate *int64 `form:"lastUpdate,omitempty" json:"lastUpdate,omitempty" xml:"lastUpdate,omitempty"`
 }
 
+// NewWebhooksRequestBody builds the HTTP request body from the payload of the
+// "Webhooks" endpoint of the "policy" service.
+func NewWebhooksRequestBody(p *policy.WebHooksRequest) *WebhooksRequestBody {
+	body := &WebhooksRequestBody{
+		WebhookURL: p.WebhookURL,
+		Subscriber: p.Subscriber,
+	}
+	return body
+}
+
 // NewEvaluateResultOK builds a "policy" service "Evaluate" endpoint result
 // from a HTTP "OK" response.
 func NewEvaluateResultOK(body any, eTag string) *policy.EvaluateResult {
diff --git a/gen/http/policy/server/encode_decode.go b/gen/http/policy/server/encode_decode.go
index 8556a4be5eb12a836422f45341b5a3b9d0cf2cc5..d37f26d769134a4a9973a04c934dfe5f43360033 100644
--- a/gen/http/policy/server/encode_decode.go
+++ b/gen/http/policy/server/encode_decode.go
@@ -214,6 +214,54 @@ func DecodeListPoliciesRequest(mux goahttp.Muxer, decoder func(*http.Request) go
 	}
 }
 
+// EncodeWebhooksResponse returns an encoder for responses returned by the
+// policy Webhooks endpoint.
+func EncodeWebhooksResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, any) error {
+	return func(ctx context.Context, w http.ResponseWriter, v any) error {
+		res, _ := v.(any)
+		enc := encoder(ctx, w)
+		body := res
+		w.WriteHeader(http.StatusOK)
+		return enc.Encode(body)
+	}
+}
+
+// DecodeWebhooksRequest returns a decoder for requests sent to the policy
+// Webhooks endpoint.
+func DecodeWebhooksRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (any, error) {
+	return func(r *http.Request) (any, error) {
+		var (
+			body WebhooksRequestBody
+			err  error
+		)
+		err = decoder(r).Decode(&body)
+		if err != nil {
+			if err == io.EOF {
+				return nil, goa.MissingPayloadError()
+			}
+			return nil, goa.DecodePayloadError(err.Error())
+		}
+		err = ValidateWebhooksRequestBody(&body)
+		if err != nil {
+			return nil, err
+		}
+
+		var (
+			group      string
+			policyname string
+			version    string
+
+			params = mux.Vars(r)
+		)
+		group = params["group"]
+		policyname = params["policyname"]
+		version = params["version"]
+		payload := NewWebhooksWebHooksRequest(&body, group, policyname, version)
+
+		return payload, nil
+	}
+}
+
 // marshalPolicyPolicyToPolicyResponseBody builds a value of type
 // *PolicyResponseBody from a value of type *policy.Policy.
 func marshalPolicyPolicyToPolicyResponseBody(v *policy.Policy) *PolicyResponseBody {
diff --git a/gen/http/policy/server/paths.go b/gen/http/policy/server/paths.go
index f224fbe4c1bc4f5ef5c1d86d22d95f746c08feec..8e398de2d13d4091bdcc65cc9f0f2c1fc02b9330 100644
--- a/gen/http/policy/server/paths.go
+++ b/gen/http/policy/server/paths.go
@@ -40,3 +40,8 @@ func UnlockPolicyPath(group string, policyName string, version string) string {
 func ListPoliciesPolicyPath() string {
 	return "/v1/policies"
 }
+
+// WebhooksPolicyPath returns the URL path to the policy service Webhooks HTTP endpoint.
+func WebhooksPolicyPath(group string, policyname string, version string) string {
+	return fmt.Sprintf("/policy/%v/%v/%v/notifychange", group, policyname, version)
+}
diff --git a/gen/http/policy/server/server.go b/gen/http/policy/server/server.go
index 2043d7396d4c8ca1b50983eda1b7664ee9e11a2b..e93b79a7e18d3edeb0bf627a4756cb7bc8a49e48 100644
--- a/gen/http/policy/server/server.go
+++ b/gen/http/policy/server/server.go
@@ -23,6 +23,7 @@ type Server struct {
 	Lock         http.Handler
 	Unlock       http.Handler
 	ListPolicies http.Handler
+	Webhooks     http.Handler
 }
 
 // MountPoint holds information about the mounted endpoints.
@@ -58,11 +59,13 @@ func New(
 			{"Lock", "POST", "/policy/{group}/{policyName}/{version}/lock"},
 			{"Unlock", "DELETE", "/policy/{group}/{policyName}/{version}/lock"},
 			{"ListPolicies", "GET", "/v1/policies"},
+			{"Webhooks", "POST", "/policy/{group}/{policyname}/{version}/notifychange"},
 		},
 		Evaluate:     NewEvaluateHandler(e.Evaluate, mux, decoder, encoder, errhandler, formatter),
 		Lock:         NewLockHandler(e.Lock, mux, decoder, encoder, errhandler, formatter),
 		Unlock:       NewUnlockHandler(e.Unlock, mux, decoder, encoder, errhandler, formatter),
 		ListPolicies: NewListPoliciesHandler(e.ListPolicies, mux, decoder, encoder, errhandler, formatter),
+		Webhooks:     NewWebhooksHandler(e.Webhooks, mux, decoder, encoder, errhandler, formatter),
 	}
 }
 
@@ -75,6 +78,7 @@ func (s *Server) Use(m func(http.Handler) http.Handler) {
 	s.Lock = m(s.Lock)
 	s.Unlock = m(s.Unlock)
 	s.ListPolicies = m(s.ListPolicies)
+	s.Webhooks = m(s.Webhooks)
 }
 
 // MethodNames returns the methods served.
@@ -86,6 +90,7 @@ func Mount(mux goahttp.Muxer, h *Server) {
 	MountLockHandler(mux, h.Lock)
 	MountUnlockHandler(mux, h.Unlock)
 	MountListPoliciesHandler(mux, h.ListPolicies)
+	MountWebhooksHandler(mux, h.Webhooks)
 }
 
 // Mount configures the mux to serve the policy endpoints.
@@ -298,3 +303,54 @@ func NewListPoliciesHandler(
 		}
 	})
 }
+
+// MountWebhooksHandler configures the mux to serve the "policy" service
+// "Webhooks" endpoint.
+func MountWebhooksHandler(mux goahttp.Muxer, h http.Handler) {
+	f, ok := h.(http.HandlerFunc)
+	if !ok {
+		f = func(w http.ResponseWriter, r *http.Request) {
+			h.ServeHTTP(w, r)
+		}
+	}
+	mux.Handle("POST", "/policy/{group}/{policyname}/{version}/notifychange", f)
+}
+
+// NewWebhooksHandler creates a HTTP handler which loads the HTTP request and
+// calls the "policy" service "Webhooks" endpoint.
+func NewWebhooksHandler(
+	endpoint goa.Endpoint,
+	mux goahttp.Muxer,
+	decoder func(*http.Request) goahttp.Decoder,
+	encoder func(context.Context, http.ResponseWriter) goahttp.Encoder,
+	errhandler func(context.Context, http.ResponseWriter, error),
+	formatter func(ctx context.Context, err error) goahttp.Statuser,
+) http.Handler {
+	var (
+		decodeRequest  = DecodeWebhooksRequest(mux, decoder)
+		encodeResponse = EncodeWebhooksResponse(encoder)
+		encodeError    = goahttp.ErrorEncoder(encoder, formatter)
+	)
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept"))
+		ctx = context.WithValue(ctx, goa.MethodKey, "Webhooks")
+		ctx = context.WithValue(ctx, goa.ServiceKey, "policy")
+		payload, err := decodeRequest(r)
+		if err != nil {
+			if err := encodeError(ctx, w, err); err != nil {
+				errhandler(ctx, w, err)
+			}
+			return
+		}
+		res, err := endpoint(ctx, payload)
+		if err != nil {
+			if err := encodeError(ctx, w, err); err != nil {
+				errhandler(ctx, w, err)
+			}
+			return
+		}
+		if err := encodeResponse(ctx, w, res); err != nil {
+			errhandler(ctx, w, err)
+		}
+	})
+}
diff --git a/gen/http/policy/server/types.go b/gen/http/policy/server/types.go
index 31b816ef74eb879775e220f44c2da4d73d4df8b4..5b878ce0066eddccb820c2bad7800f69e1b85d88 100644
--- a/gen/http/policy/server/types.go
+++ b/gen/http/policy/server/types.go
@@ -9,8 +9,18 @@ package server
 
 import (
 	policy "gitlab.eclipse.org/eclipse/xfsc/tsa/policy/gen/policy"
+	goa "goa.design/goa/v3/pkg"
 )
 
+// WebhooksRequestBody is the type of the "policy" service "Webhooks" endpoint
+// HTTP request body.
+type WebhooksRequestBody struct {
+	// Subscriber webhook url.
+	WebhookURL *string `form:"webhook_url,omitempty" json:"webhook_url,omitempty" xml:"webhook_url,omitempty"`
+	// Name of the subscriber for policy.
+	Subscriber *string `form:"subscriber,omitempty" json:"subscriber,omitempty" xml:"subscriber,omitempty"`
+}
+
 // ListPoliciesResponseBody is the type of the "policy" service "ListPolicies"
 // endpoint HTTP response body.
 type ListPoliciesResponseBody struct {
@@ -99,3 +109,28 @@ func NewListPoliciesPoliciesRequest(locked *bool, rego *bool, data *bool, dataCo
 
 	return v
 }
+
+// NewWebhooksWebHooksRequest builds a policy service Webhooks endpoint payload.
+func NewWebhooksWebHooksRequest(body *WebhooksRequestBody, group string, policyname string, version string) *policy.WebHooksRequest {
+	v := &policy.WebHooksRequest{
+		WebhookURL: *body.WebhookURL,
+		Subscriber: *body.Subscriber,
+	}
+	v.Group = group
+	v.Policyname = policyname
+	v.Version = version
+
+	return v
+}
+
+// ValidateWebhooksRequestBody runs the validations defined on
+// WebhooksRequestBody
+func ValidateWebhooksRequestBody(body *WebhooksRequestBody) (err error) {
+	if body.WebhookURL == nil {
+		err = goa.MergeErrors(err, goa.MissingFieldError("webhook_url", "body"))
+	}
+	if body.Subscriber == nil {
+		err = goa.MergeErrors(err, goa.MissingFieldError("subscriber", "body"))
+	}
+	return
+}
diff --git a/gen/policy/client.go b/gen/policy/client.go
index 49cb8cd5cac1433254711a75ee6c0a94f0e91687..26088b1527348298ff3636a986370e9e762cb135 100644
--- a/gen/policy/client.go
+++ b/gen/policy/client.go
@@ -19,15 +19,17 @@ type Client struct {
 	LockEndpoint         goa.Endpoint
 	UnlockEndpoint       goa.Endpoint
 	ListPoliciesEndpoint goa.Endpoint
+	WebhooksEndpoint     goa.Endpoint
 }
 
 // NewClient initializes a "policy" service client given the endpoints.
-func NewClient(evaluate, lock, unlock, listPolicies goa.Endpoint) *Client {
+func NewClient(evaluate, lock, unlock, listPolicies, webhooks goa.Endpoint) *Client {
 	return &Client{
 		EvaluateEndpoint:     evaluate,
 		LockEndpoint:         lock,
 		UnlockEndpoint:       unlock,
 		ListPoliciesEndpoint: listPolicies,
+		WebhooksEndpoint:     webhooks,
 	}
 }
 
@@ -62,3 +64,13 @@ func (c *Client) ListPolicies(ctx context.Context, p *PoliciesRequest) (res *Pol
 	}
 	return ires.(*PoliciesResult), nil
 }
+
+// Webhooks calls the "Webhooks" endpoint of the "policy" service.
+func (c *Client) Webhooks(ctx context.Context, p *WebHooksRequest) (res any, err error) {
+	var ires any
+	ires, err = c.WebhooksEndpoint(ctx, p)
+	if err != nil {
+		return
+	}
+	return ires.(any), nil
+}
diff --git a/gen/policy/endpoints.go b/gen/policy/endpoints.go
index e1c82db041f06b640cfcc82dfcf81e65272001c2..7b2afbe9474495eaceee08f254d1812b14f1e600 100644
--- a/gen/policy/endpoints.go
+++ b/gen/policy/endpoints.go
@@ -19,6 +19,7 @@ type Endpoints struct {
 	Lock         goa.Endpoint
 	Unlock       goa.Endpoint
 	ListPolicies goa.Endpoint
+	Webhooks     goa.Endpoint
 }
 
 // NewEndpoints wraps the methods of the "policy" service with endpoints.
@@ -28,6 +29,7 @@ func NewEndpoints(s Service) *Endpoints {
 		Lock:         NewLockEndpoint(s),
 		Unlock:       NewUnlockEndpoint(s),
 		ListPolicies: NewListPoliciesEndpoint(s),
+		Webhooks:     NewWebhooksEndpoint(s),
 	}
 }
 
@@ -37,6 +39,7 @@ func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) {
 	e.Lock = m(e.Lock)
 	e.Unlock = m(e.Unlock)
 	e.ListPolicies = m(e.ListPolicies)
+	e.Webhooks = m(e.Webhooks)
 }
 
 // NewEvaluateEndpoint returns an endpoint function that calls the method
@@ -74,3 +77,12 @@ func NewListPoliciesEndpoint(s Service) goa.Endpoint {
 		return s.ListPolicies(ctx, p)
 	}
 }
+
+// NewWebhooksEndpoint returns an endpoint function that calls the method
+// "Webhooks" of service "policy".
+func NewWebhooksEndpoint(s Service) goa.Endpoint {
+	return func(ctx context.Context, req any) (any, error) {
+		p := req.(*WebHooksRequest)
+		return s.Webhooks(ctx, p)
+	}
+}
diff --git a/gen/policy/service.go b/gen/policy/service.go
index 2ca613b9186fc1be5c01ab16a0671819c7c90dc7..7f05e1b38eba0796490fa157fabd2a94963449f9 100644
--- a/gen/policy/service.go
+++ b/gen/policy/service.go
@@ -21,6 +21,8 @@ type Service interface {
 	Unlock(context.Context, *UnlockRequest) (err error)
 	// List policies from storage with optional filters.
 	ListPolicies(context.Context, *PoliciesRequest) (res *PoliciesResult, err error)
+	// Gives ability to user to subscribe for policy change via webhooks
+	Webhooks(context.Context, *WebHooksRequest) (res any, err error)
 }
 
 // ServiceName is the name of the service as defined in the design. This is the
@@ -31,7 +33,7 @@ const ServiceName = "policy"
 // MethodNames lists the service method names as defined in the design. These
 // are the same values that are set in the endpoint request contexts under the
 // MethodKey key.
-var MethodNames = [4]string{"Evaluate", "Lock", "Unlock", "ListPolicies"}
+var MethodNames = [5]string{"Evaluate", "Lock", "Unlock", "ListPolicies", "Webhooks"}
 
 // EvaluateRequest is the payload type of the policy service Evaluate method.
 type EvaluateRequest struct {
@@ -112,3 +114,17 @@ type UnlockRequest struct {
 	// Policy version.
 	Version string
 }
+
+// WebHooksRequest is the payload type of the policy service Webhooks method.
+type WebHooksRequest struct {
+	// Subscriber webhook url.
+	WebhookURL string
+	// Name of the subscriber for policy.
+	Subscriber string
+	// Policy name.
+	Policyname string
+	// Policy group.
+	Group string
+	// Policy version.
+	Version string
+}
diff --git a/internal/notify/notify.go b/internal/notify/notify.go
index 4f52c85eb87523dec1dd28241a8991937999b519..6417cfed9f4f7f64226e854de40b7fb92d116871 100644
--- a/internal/notify/notify.go
+++ b/internal/notify/notify.go
@@ -1,17 +1,32 @@
 package notify
 
 import (
+	"bytes"
 	"context"
+	"encoding/json"
+	"fmt"
+	"net/http"
+
+	"gitlab.eclipse.org/eclipse/xfsc/tsa/policy/internal/storage"
+	"go.uber.org/zap"
 )
 
 //go:generate counterfeiter . Events
+//go:generate counterfeiter . Storage
 
 type Events interface {
 	Send(ctx context.Context, data any) error
 }
 
+type Storage interface {
+	FindAllSubscribed(ctx context.Context, policyName, policyGroup, policyVersion string) ([]*storage.Subscriber, error)
+}
+
 type Notifier struct {
-	events Events
+	events  Events
+	storage Storage
+	client  *http.Client
+	logger  *zap.Logger
 }
 
 type EventPolicyChange struct {
@@ -22,12 +37,59 @@ type EventPolicyChange struct {
 
 // New creates a policy change notifier for interested subscribers.
 // It can notify for policy changes both via MessageQueue or Web hooks.
-func New(events Events) *Notifier {
-	return &Notifier{events: events}
+func New(events Events, client *http.Client, storage Storage, logger *zap.Logger) *Notifier {
+	return &Notifier{events: events, client: client, storage: storage, logger: logger}
 }
 
 // PolicyDataChange is called when the policies source code or data are updated
 // in storage. The function will notify subscribers of the given changes.
-func (n *Notifier) PolicyDataChange(ctx context.Context, event *EventPolicyChange) error {
-	return n.events.Send(ctx, event)
+func (n *Notifier) PolicyDataChange(ctx context.Context, policyName, policyGroup, policyVersion string) error {
+	data := &EventPolicyChange{Name: policyName, Version: policyVersion, Group: policyGroup}
+
+	n.notifySubscribers(ctx, data)
+
+	return n.events.Send(ctx, data)
+}
+
+func (n *Notifier) notifySubscribers(ctx context.Context, data *EventPolicyChange) {
+	logger := n.logger.With(
+		zap.String("operation", "notifySubscribers"),
+		zap.String("group", data.Group),
+		zap.String("policy", data.Name),
+		zap.String("version", data.Version),
+	)
+
+	byteData, err := json.Marshal(data)
+	if err != nil {
+		logger.Error("error while marshal the data", zap.Error(err))
+	}
+
+	subscribers, err := n.storage.FindAllSubscribed(ctx, data.Name, data.Group, data.Version)
+	if err != nil {
+		logger.Error("error while getting subscribers", zap.Error(err))
+	}
+
+	for _, subscriber := range subscribers {
+		req, err := http.NewRequestWithContext(ctx, http.MethodPost, subscriber.WebhookURL, bytes.NewBuffer(byteData))
+		if err != nil {
+			err = fmt.Errorf("error while creating request for sending data to subscriber: %s with URL: %s: %w", subscriber.Name, subscriber.WebhookURL, err)
+			logger.Error("error creating request", zap.Error(err))
+		}
+		req.Header.Set("Content-Type", "application/json")
+
+		res, err := n.client.Do(req)
+		if err != nil {
+			err = fmt.Errorf("error while trying to send data to subscriber: %s with URL: %s: %w", subscriber.Name, subscriber.WebhookURL, err)
+			logger.Error("error sending data", zap.Error(err))
+		}
+
+		if res != nil {
+			defer res.Body.Close()
+
+			if res.StatusCode >= http.StatusBadRequest {
+				err = fmt.Errorf("error: subscriber %s with URL %s didn't respond with status code %d: %w", subscriber.Name, subscriber.WebhookURL, res.StatusCode, err)
+				logger.Error("client did not respond", zap.Error(err))
+			}
+		}
+	}
 }
diff --git a/internal/notify/notify_test.go b/internal/notify/notify_test.go
index ed6aadbce9512cf526dac0cd1b7c533e3209bb35..2b81e0f73fb3089ab28e203854c44166c35fe08a 100644
--- a/internal/notify/notify_test.go
+++ b/internal/notify/notify_test.go
@@ -3,17 +3,21 @@ package notify_test
 import (
 	"context"
 	"fmt"
+	"net/http"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 	"gitlab.eclipse.org/eclipse/xfsc/tsa/policy/internal/notify"
 	"gitlab.eclipse.org/eclipse/xfsc/tsa/policy/internal/notify/notifyfakes"
+	"gitlab.eclipse.org/eclipse/xfsc/tsa/policy/internal/storage"
+	"go.uber.org/zap"
 )
 
 func TestNotify_PolicyDataChange(t *testing.T) {
 	tests := []struct {
 		name              string
 		events            notify.Events
+		storage           notify.Storage
 		eventPolicyChange *notify.EventPolicyChange
 
 		errText string
@@ -21,6 +25,9 @@ func TestNotify_PolicyDataChange(t *testing.T) {
 		{
 			name:              "error when sending event",
 			eventPolicyChange: &notify.EventPolicyChange{Name: "exampleName", Version: "exampleVersion", Group: "exampleGroup"},
+			storage: &notifyfakes.FakeStorage{FindAllSubscribedStub: func(ctx context.Context, s1, s2, s3 string) ([]*storage.Subscriber, error) {
+				return []*storage.Subscriber{}, nil
+			}},
 			events: &notifyfakes.FakeEvents{SendStub: func(ctx context.Context, a any) error {
 				return fmt.Errorf("some error")
 			}},
@@ -31,6 +38,9 @@ func TestNotify_PolicyDataChange(t *testing.T) {
 		{
 			name:              "sending event is successful",
 			eventPolicyChange: &notify.EventPolicyChange{Name: "exampleName", Version: "exampleVersion", Group: "exampleGroup"},
+			storage: &notifyfakes.FakeStorage{FindAllSubscribedStub: func(ctx context.Context, s1, s2, s3 string) ([]*storage.Subscriber, error) {
+				return []*storage.Subscriber{}, nil
+			}},
 			events: &notifyfakes.FakeEvents{SendStub: func(ctx context.Context, a any) error {
 				return nil
 			}},
@@ -39,8 +49,8 @@ func TestNotify_PolicyDataChange(t *testing.T) {
 
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			notifier := notify.New(test.events)
-			err := notifier.PolicyDataChange(context.Background(), test.eventPolicyChange)
+			notifier := notify.New(test.events, http.DefaultClient, test.storage, zap.NewNop())
+			err := notifier.PolicyDataChange(context.Background(), test.eventPolicyChange.Name, test.eventPolicyChange.Group, test.eventPolicyChange.Version)
 			if test.errText != "" {
 				assert.ErrorContains(t, err, test.errText)
 			} else {
diff --git a/internal/notify/notifyfakes/fake_storage.go b/internal/notify/notifyfakes/fake_storage.go
new file mode 100644
index 0000000000000000000000000000000000000000..c42f298c057048ad2173177993b48f7bfd63c448
--- /dev/null
+++ b/internal/notify/notifyfakes/fake_storage.go
@@ -0,0 +1,124 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package notifyfakes
+
+import (
+	"context"
+	"sync"
+
+	"gitlab.eclipse.org/eclipse/xfsc/tsa/policy/internal/notify"
+	"gitlab.eclipse.org/eclipse/xfsc/tsa/policy/internal/storage"
+)
+
+type FakeStorage struct {
+	FindAllSubscribedStub        func(context.Context, string, string, string) ([]*storage.Subscriber, error)
+	findAllSubscribedMutex       sync.RWMutex
+	findAllSubscribedArgsForCall []struct {
+		arg1 context.Context
+		arg2 string
+		arg3 string
+		arg4 string
+	}
+	findAllSubscribedReturns struct {
+		result1 []*storage.Subscriber
+		result2 error
+	}
+	findAllSubscribedReturnsOnCall map[int]struct {
+		result1 []*storage.Subscriber
+		result2 error
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *FakeStorage) FindAllSubscribed(arg1 context.Context, arg2 string, arg3 string, arg4 string) ([]*storage.Subscriber, error) {
+	fake.findAllSubscribedMutex.Lock()
+	ret, specificReturn := fake.findAllSubscribedReturnsOnCall[len(fake.findAllSubscribedArgsForCall)]
+	fake.findAllSubscribedArgsForCall = append(fake.findAllSubscribedArgsForCall, struct {
+		arg1 context.Context
+		arg2 string
+		arg3 string
+		arg4 string
+	}{arg1, arg2, arg3, arg4})
+	stub := fake.FindAllSubscribedStub
+	fakeReturns := fake.findAllSubscribedReturns
+	fake.recordInvocation("FindAllSubscribed", []interface{}{arg1, arg2, arg3, arg4})
+	fake.findAllSubscribedMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3, arg4)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *FakeStorage) FindAllSubscribedCallCount() int {
+	fake.findAllSubscribedMutex.RLock()
+	defer fake.findAllSubscribedMutex.RUnlock()
+	return len(fake.findAllSubscribedArgsForCall)
+}
+
+func (fake *FakeStorage) FindAllSubscribedCalls(stub func(context.Context, string, string, string) ([]*storage.Subscriber, error)) {
+	fake.findAllSubscribedMutex.Lock()
+	defer fake.findAllSubscribedMutex.Unlock()
+	fake.FindAllSubscribedStub = stub
+}
+
+func (fake *FakeStorage) FindAllSubscribedArgsForCall(i int) (context.Context, string, string, string) {
+	fake.findAllSubscribedMutex.RLock()
+	defer fake.findAllSubscribedMutex.RUnlock()
+	argsForCall := fake.findAllSubscribedArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4
+}
+
+func (fake *FakeStorage) FindAllSubscribedReturns(result1 []*storage.Subscriber, result2 error) {
+	fake.findAllSubscribedMutex.Lock()
+	defer fake.findAllSubscribedMutex.Unlock()
+	fake.FindAllSubscribedStub = nil
+	fake.findAllSubscribedReturns = struct {
+		result1 []*storage.Subscriber
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *FakeStorage) FindAllSubscribedReturnsOnCall(i int, result1 []*storage.Subscriber, result2 error) {
+	fake.findAllSubscribedMutex.Lock()
+	defer fake.findAllSubscribedMutex.Unlock()
+	fake.FindAllSubscribedStub = nil
+	if fake.findAllSubscribedReturnsOnCall == nil {
+		fake.findAllSubscribedReturnsOnCall = make(map[int]struct {
+			result1 []*storage.Subscriber
+			result2 error
+		})
+	}
+	fake.findAllSubscribedReturnsOnCall[i] = struct {
+		result1 []*storage.Subscriber
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *FakeStorage) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.findAllSubscribedMutex.RLock()
+	defer fake.findAllSubscribedMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *FakeStorage) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ notify.Storage = new(FakeStorage)
diff --git a/internal/regocache/regocache.go b/internal/regocache/regocache.go
index e100e032e6d41beb48963225e4d3723775a93cf9..bbe8c7687459bd1d41e8835d831a2c1307e80162 100644
--- a/internal/regocache/regocache.go
+++ b/internal/regocache/regocache.go
@@ -7,7 +7,6 @@ import (
 	"context"
 	"sync"
 
-	"gitlab.eclipse.org/eclipse/xfsc/tsa/policy/internal/notify"
 	"gitlab.eclipse.org/eclipse/xfsc/tsa/policy/internal/storage"
 )
 
@@ -43,7 +42,7 @@ func (c *Cache) Purge() {
 }
 
 // PolicyDataChange triggers purge on the cache.
-func (c *Cache) PolicyDataChange(_ context.Context, _ *notify.EventPolicyChange) error {
+func (c *Cache) PolicyDataChange(_ context.Context, _, _, _ string) error {
 	c.Purge()
 	return nil
 }
diff --git a/internal/regocache/regocache_test.go b/internal/regocache/regocache_test.go
index 0205858b6fac472675dd976f2a339e2ebc50ea6b..281e92c72b5ff8230acc79c9885d425c07b99907 100644
--- a/internal/regocache/regocache_test.go
+++ b/internal/regocache/regocache_test.go
@@ -73,7 +73,7 @@ func TestCache_PolicyDataChange(t *testing.T) {
 	cache := regocache.New()
 	cache.Set("key1", &p1)
 
-	err := cache.PolicyDataChange(context.Background(), nil)
+	err := cache.PolicyDataChange(context.Background(), "", "", "")
 	assert.Nil(t, err)
 	q2, ok := cache.Get("key1")
 	assert.False(t, ok)
diff --git a/internal/service/policy/policyfakes/fake_storage.go b/internal/service/policy/policyfakes/fake_storage.go
index acf20f5ae889e77e6fbc799dccdfa87270d15293..da008faa9c5cb5fcfd18e65df24bcedf3073f6d0 100644
--- a/internal/service/policy/policyfakes/fake_storage.go
+++ b/internal/service/policy/policyfakes/fake_storage.go
@@ -10,6 +10,34 @@ import (
 )
 
 type FakeStorage struct {
+	CreateSubscriberStub        func(context.Context, *storage.Subscriber) error
+	createSubscriberMutex       sync.RWMutex
+	createSubscriberArgsForCall []struct {
+		arg1 context.Context
+		arg2 *storage.Subscriber
+	}
+	createSubscriberReturns struct {
+		result1 error
+	}
+	createSubscriberReturnsOnCall map[int]struct {
+		result1 error
+	}
+	FindAllSubscribedStub        func(context.Context, string, string, string) ([]*storage.Subscriber, error)
+	findAllSubscribedMutex       sync.RWMutex
+	findAllSubscribedArgsForCall []struct {
+		arg1 context.Context
+		arg2 string
+		arg3 string
+		arg4 string
+	}
+	findAllSubscribedReturns struct {
+		result1 []*storage.Subscriber
+		result2 error
+	}
+	findAllSubscribedReturnsOnCall map[int]struct {
+		result1 []*storage.Subscriber
+		result2 error
+	}
 	GetPoliciesStub        func(context.Context, *bool) ([]*storage.Policy, error)
 	getPoliciesMutex       sync.RWMutex
 	getPoliciesArgsForCall []struct {
@@ -59,6 +87,135 @@ type FakeStorage struct {
 	invocationsMutex sync.RWMutex
 }
 
+func (fake *FakeStorage) CreateSubscriber(arg1 context.Context, arg2 *storage.Subscriber) error {
+	fake.createSubscriberMutex.Lock()
+	ret, specificReturn := fake.createSubscriberReturnsOnCall[len(fake.createSubscriberArgsForCall)]
+	fake.createSubscriberArgsForCall = append(fake.createSubscriberArgsForCall, struct {
+		arg1 context.Context
+		arg2 *storage.Subscriber
+	}{arg1, arg2})
+	stub := fake.CreateSubscriberStub
+	fakeReturns := fake.createSubscriberReturns
+	fake.recordInvocation("CreateSubscriber", []interface{}{arg1, arg2})
+	fake.createSubscriberMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *FakeStorage) CreateSubscriberCallCount() int {
+	fake.createSubscriberMutex.RLock()
+	defer fake.createSubscriberMutex.RUnlock()
+	return len(fake.createSubscriberArgsForCall)
+}
+
+func (fake *FakeStorage) CreateSubscriberCalls(stub func(context.Context, *storage.Subscriber) error) {
+	fake.createSubscriberMutex.Lock()
+	defer fake.createSubscriberMutex.Unlock()
+	fake.CreateSubscriberStub = stub
+}
+
+func (fake *FakeStorage) CreateSubscriberArgsForCall(i int) (context.Context, *storage.Subscriber) {
+	fake.createSubscriberMutex.RLock()
+	defer fake.createSubscriberMutex.RUnlock()
+	argsForCall := fake.createSubscriberArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *FakeStorage) CreateSubscriberReturns(result1 error) {
+	fake.createSubscriberMutex.Lock()
+	defer fake.createSubscriberMutex.Unlock()
+	fake.CreateSubscriberStub = nil
+	fake.createSubscriberReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *FakeStorage) CreateSubscriberReturnsOnCall(i int, result1 error) {
+	fake.createSubscriberMutex.Lock()
+	defer fake.createSubscriberMutex.Unlock()
+	fake.CreateSubscriberStub = nil
+	if fake.createSubscriberReturnsOnCall == nil {
+		fake.createSubscriberReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.createSubscriberReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *FakeStorage) FindAllSubscribed(arg1 context.Context, arg2 string, arg3 string, arg4 string) ([]*storage.Subscriber, error) {
+	fake.findAllSubscribedMutex.Lock()
+	ret, specificReturn := fake.findAllSubscribedReturnsOnCall[len(fake.findAllSubscribedArgsForCall)]
+	fake.findAllSubscribedArgsForCall = append(fake.findAllSubscribedArgsForCall, struct {
+		arg1 context.Context
+		arg2 string
+		arg3 string
+		arg4 string
+	}{arg1, arg2, arg3, arg4})
+	stub := fake.FindAllSubscribedStub
+	fakeReturns := fake.findAllSubscribedReturns
+	fake.recordInvocation("FindAllSubscribed", []interface{}{arg1, arg2, arg3, arg4})
+	fake.findAllSubscribedMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3, arg4)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *FakeStorage) FindAllSubscribedCallCount() int {
+	fake.findAllSubscribedMutex.RLock()
+	defer fake.findAllSubscribedMutex.RUnlock()
+	return len(fake.findAllSubscribedArgsForCall)
+}
+
+func (fake *FakeStorage) FindAllSubscribedCalls(stub func(context.Context, string, string, string) ([]*storage.Subscriber, error)) {
+	fake.findAllSubscribedMutex.Lock()
+	defer fake.findAllSubscribedMutex.Unlock()
+	fake.FindAllSubscribedStub = stub
+}
+
+func (fake *FakeStorage) FindAllSubscribedArgsForCall(i int) (context.Context, string, string, string) {
+	fake.findAllSubscribedMutex.RLock()
+	defer fake.findAllSubscribedMutex.RUnlock()
+	argsForCall := fake.findAllSubscribedArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4
+}
+
+func (fake *FakeStorage) FindAllSubscribedReturns(result1 []*storage.Subscriber, result2 error) {
+	fake.findAllSubscribedMutex.Lock()
+	defer fake.findAllSubscribedMutex.Unlock()
+	fake.FindAllSubscribedStub = nil
+	fake.findAllSubscribedReturns = struct {
+		result1 []*storage.Subscriber
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *FakeStorage) FindAllSubscribedReturnsOnCall(i int, result1 []*storage.Subscriber, result2 error) {
+	fake.findAllSubscribedMutex.Lock()
+	defer fake.findAllSubscribedMutex.Unlock()
+	fake.FindAllSubscribedStub = nil
+	if fake.findAllSubscribedReturnsOnCall == nil {
+		fake.findAllSubscribedReturnsOnCall = make(map[int]struct {
+			result1 []*storage.Subscriber
+			result2 error
+		})
+	}
+	fake.findAllSubscribedReturnsOnCall[i] = struct {
+		result1 []*storage.Subscriber
+		result2 error
+	}{result1, result2}
+}
+
 func (fake *FakeStorage) GetPolicies(arg1 context.Context, arg2 *bool) ([]*storage.Policy, error) {
 	fake.getPoliciesMutex.Lock()
 	ret, specificReturn := fake.getPoliciesReturnsOnCall[len(fake.getPoliciesArgsForCall)]
@@ -259,6 +416,10 @@ func (fake *FakeStorage) SetPolicyLockReturnsOnCall(i int, result1 error) {
 func (fake *FakeStorage) Invocations() map[string][][]interface{} {
 	fake.invocationsMutex.RLock()
 	defer fake.invocationsMutex.RUnlock()
+	fake.createSubscriberMutex.RLock()
+	defer fake.createSubscriberMutex.RUnlock()
+	fake.findAllSubscribedMutex.RLock()
+	defer fake.findAllSubscribedMutex.RUnlock()
 	fake.getPoliciesMutex.RLock()
 	defer fake.getPoliciesMutex.RUnlock()
 	fake.policyMutex.RLock()
diff --git a/internal/service/policy/service.go b/internal/service/policy/service.go
index 819c997cb8391c8dc54716ce302e945f8c56fff0..ed8355d2e9f2e55204ee72282c85fde29d71c5c4 100644
--- a/internal/service/policy/service.go
+++ b/internal/service/policy/service.go
@@ -30,6 +30,7 @@ type Storage interface {
 	Policy(ctx context.Context, group, name, version string) (*storage.Policy, error)
 	SetPolicyLock(ctx context.Context, group, name, version string, lock bool) error
 	GetPolicies(ctx context.Context, locked *bool) ([]*storage.Policy, error)
+	CreateSubscriber(ctx context.Context, subscriber *storage.Subscriber) error
 }
 
 type RegoCache interface {
@@ -241,6 +242,21 @@ func (s *Service) ListPolicies(ctx context.Context, req *policy.PoliciesRequest)
 	return &policy.PoliciesResult{Policies: policiesResult}, nil
 }
 
+func (s *Service) Webhooks(ctx context.Context, req *policy.WebHooksRequest) (any, error) {
+	err := s.storage.CreateSubscriber(ctx, &storage.Subscriber{
+		Name:          req.Subscriber,
+		WebhookURL:    req.WebhookURL,
+		PolicyName:    req.Policyname,
+		PolicyGroup:   req.Group,
+		PolicyVersion: req.Version,
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	return nil, nil
+}
+
 // prepareQuery tries to get a prepared query from the regocache.
 // If the policyCache entry is not found, it will try to prepare a new
 // query and will set it into the policyCache for future use.
diff --git a/internal/storage/storage.go b/internal/storage/storage.go
index 81c1dd83116bfae8bde0250213aff9d868d2beb4..5781696f83f9284f72469cad29475a255d886771 100644
--- a/internal/storage/storage.go
+++ b/internal/storage/storage.go
@@ -12,10 +12,10 @@ import (
 	zap "go.uber.org/zap"
 
 	"gitlab.eclipse.org/eclipse/xfsc/tsa/golib/errors"
-	"gitlab.eclipse.org/eclipse/xfsc/tsa/policy/internal/notify"
 )
 
 const (
+	subscriberCollectionName = "subscribers"
 	lockedField              = "locked"
 	dataField                = "data"
 	nextDataRefreshTimeField = "nextDataRefreshTime"
@@ -23,7 +23,7 @@ const (
 )
 
 type PolicyChangeSubscriber interface {
-	PolicyDataChange(ctx context.Context, event *notify.EventPolicyChange) error
+	PolicyDataChange(ctx context.Context, policyName, policyGroup, policyVersion string) error
 }
 
 type Policy struct {
@@ -43,6 +43,7 @@ type Policy struct {
 type Storage struct {
 	db          *mongo.Client
 	policy      *mongo.Collection
+	subscriber  *mongo.Collection
 	subscribers []PolicyChangeSubscriber
 	logger      *zap.Logger
 }
@@ -52,10 +53,13 @@ func New(db *mongo.Client, dbname, collection string, logger *zap.Logger) (*Stor
 		return nil, err
 	}
 
+	database := db.Database(dbname)
+
 	return &Storage{
-		db:     db,
-		policy: db.Database(dbname).Collection(collection),
-		logger: logger,
+		db:         db,
+		policy:     database.Collection(collection),
+		subscriber: database.Collection(subscriberCollectionName),
+		logger:     logger,
 	}, nil
 }
 
@@ -128,10 +132,7 @@ func (s *Storage) ListenPolicyDataChanges(ctx context.Context) error {
 		policy := policyEvent.Policy
 
 		for _, subscriber := range s.subscribers {
-			err := subscriber.PolicyDataChange(
-				ctx,
-				&notify.EventPolicyChange{Name: policy.Name, Version: policy.Version, Group: policy.Group},
-			)
+			err := subscriber.PolicyDataChange(ctx, policy.Name, policy.Group, policy.Version)
 			if err != nil {
 				return err
 			}
diff --git a/internal/storage/subscribers.go b/internal/storage/subscribers.go
new file mode 100644
index 0000000000000000000000000000000000000000..5ddf9b9402aeea5a88cb208fe7ec0544e1b7cdf6
--- /dev/null
+++ b/internal/storage/subscribers.go
@@ -0,0 +1,54 @@
+package storage
+
+import (
+	"context"
+	"time"
+
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+)
+
+type Subscriber struct {
+	ID            primitive.ObjectID `bson:"_id"`
+	Name          string
+	WebhookURL    string
+	PolicyName    string
+	PolicyGroup   string
+	PolicyVersion string
+	CreatedAt     time.Time
+	UpdatedAt     time.Time
+	DeletedAt     *time.Time
+}
+
+func (s *Storage) CreateSubscriber(ctx context.Context, subscriber *Subscriber) error {
+	subscriber.CreatedAt = time.Now()
+	subscriber.UpdatedAt = time.Now()
+	subscriber.ID = primitive.NewObjectID()
+
+	_, err := s.subscriber.InsertOne(ctx, subscriber)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (s *Storage) FindAllSubscribed(ctx context.Context, policyName, policyGroup, policyVersion string) ([]*Subscriber, error) {
+	cursor, err := s.subscriber.Find(ctx, bson.M{
+		"policyname":    policyName,
+		"policygroup":   policyGroup,
+		"policyversion": policyVersion,
+	})
+
+	if err != nil {
+		return nil, err
+	}
+
+	subscribers := []*Subscriber{}
+
+	if err := cursor.All(ctx, &subscribers); err != nil {
+		return nil, err
+	}
+
+	return subscribers, nil
+}