diff --git a/README.md b/README.md
index bb1ec8250993bc54c6958e3a746b0b59f64a415d..f4c9330896c0bc3abac01244617f68fd73e1f678 100644
--- a/README.md
+++ b/README.md
@@ -111,6 +111,8 @@ flowchart LR
 
 ### Policy Development
 
+* [Policy Extensions Functions](./doc/policy_development.md)
+
 Policies are written in the [Rego](https://www.openpolicyagent.org/docs/latest/policy-language/) 
 language. Please refer to the [OPA documentation](https://www.openpolicyagent.org/docs/latest/)
 for detailed overview of Rego and OPA capabilities.
@@ -120,12 +122,13 @@ for detailed overview of Rego and OPA capabilities.
 1. The filename of the policy *must* follow rules for the naming and directory structure:
 the `group`, `policy name` and `version` are directories inside the Git repo and policy file *must* be named
 `policy.rego`.  For example: `/gaiax/example/1.0/policy.rego`.
-2. In the same directory there could be a data file containing static json, which is later passed to the
-policy evaluation runtime. The file *must* be named `data.json`. Example: `/gaiax/example/1.0/data.json`
+2. In the same directory there could be a data file containing static JSON, which is automatically 
+available for use during policy evaluation by using the `data` variable. The file *must* be named `data.json`. 
+Example: `/gaiax/example/1.0/data.json`
 3. The policy package name inside the policy source code file *must* exactly match
 the `group` and `policy` (name) of the policy.
 
-*What does all this mean?*
+*What does it mean?*
 
 Let's see an example for the 1st convention.
 ```
@@ -166,14 +169,24 @@ can be mapped and used for evaluating all kinds of different policies. Without a
 package naming rule, there's no way the service can automatically generate HTTP 
 endpoints for working with arbitrary dynamically uploaded policies.
 
-## GDPR
+### Policy Extensions Functions
+
+A brief documentation for the available Rego extensions functions
+which can be used during policy development.
+
+[Policy Extensions Functions](./doc/policy_development.md)
+
+You can also look at the source code in package [`regofunc`](./internal/regofunc) to understand the
+inner-working and capabilities of the extension functions.
+
+### GDPR
 
 [GDPR](GDPR.md)
 
-## Dependencies
+### Dependencies
 
 [Dependencies](go.mod)
 
-## License
+### License
 
 [Apache 2.0 license](LICENSE)
diff --git a/doc/policy_development.md b/doc/policy_development.md
new file mode 100644
index 0000000000000000000000000000000000000000..b78189aeafc16b90acac9b1cec91949c7adcf7d6
--- /dev/null
+++ b/doc/policy_development.md
@@ -0,0 +1,380 @@
+# Policy Development Extensions
+
+The policy service extends the standard Rego runtime with custom 
+built-in functions and some custom functionalities described here.
+
+### Pure Evaluation Results
+
+In the Rego language there is a blank identifier variable which 
+can be used for assignments. If used like it's shown below, the
+result from the policy evaluation will not be embedded in variable, 
+but will be returned as *pure* result. 
+
+> This is custom functionality developed in the policy service
+> and is not standard behaviour of the OPA Rego runtime.
+
+Below are two examples for what it means.
+
+If the following policy is evaluated, the returned result will be 
+*embedded* in an attribute named `credential`:
+
+```
+package example.createProof
+
+credential := proof.create(input)
+```
+
+Result:
+```json
+{
+    "credential": {
+        "@context": "...",
+        "type": "VerifiableCredential",
+        "credentialSubject": {...},
+        "proof": {...}
+    }
+}
+```
+
+If however a blank identifier is used for the assignment, the result 
+of the policy evaluation won't be embedded in an attribute named
+`credential` but will be returned directly:
+
+```
+package example.createProof
+
+_ := proof.create(input)
+```
+
+Result:
+```json
+{
+    "@context": "...",
+    "type": "VerifiableCredential",
+    "credentialSubject": {...},
+    "proof": {...}
+}
+```
+
+A policy developer can use the blank identifier assignment to skip the
+mapping of a function call to a JSON attribute name. The result of the 
+function call will be returned directly as JSON. 
+
+This is useful in case you want to return a DID document or Verifiable Credential
+from policy evaluation, and the document must not be mapped to an upper level attribute.
+
+### Extension Functions
+
+A number of Rego extension functions are developed and injected in the
+policy service Rego runtime. Here is a list with brief description for
+each one of them.
+
+#### cache.get
+
+The function retrieves JSON data from the Cache service. It accepts
+three parameters used to identify the underlying Cache key. Only the
+first one named `key` is required, the other two may be empty.
+
+Example:
+```
+package example.cacheGet
+
+data := cache.get("mykey", "", "")
+```
+
+#### cache.set
+
+The function inserts JSON data into the Cache service. It accepts
+four parameters. First three are used to identify/construct the 
+underlying Cache key. The last one is the data to be stored.
+
+Example:
+```
+package example.cacheSet
+
+result := cache.set("mykey", "", "", input.data)
+```
+
+#### did.resolve
+
+Resolve DID using the [Universal DID Resolver](https://github.com/decentralized-identity/universal-resolver)
+and return the resolved DID document. 
+
+Example:
+```
+package example.didResolve
+
+result := did.resolve("did:key:z6Mkfriq1MqLBoPWecGoDLjguo1sB9brj6wT3qZ5BxkKpuP6")
+```
+
+#### task.create
+
+Start asynchronous task and pass the given data as task input. The function accepts two
+parameters: task name and the input data.
+
+Example:
+```
+package example.taskCreate
+
+result := task.create("task-name", input.data)
+```
+
+#### tasklist.create
+
+Start asynchronous task list and pass the given data as input. The function accepts two
+parameters: task list name and the input data.   
+
+Example:
+```
+package example.tasklist
+
+result := tasklist.create("task-list-name", input.data)
+```
+
+#### keys.get
+
+Retrieve a specific public key from the signer service. The function accepts one
+argument which is the name of the key. The key is returned in JWK format
+wrapped in a DID verification method envelope.
+
+Example:
+```
+package example.getkey
+
+_ := keys.get("key1")
+```
+
+Result:
+```json
+{
+  "id": "key1",
+  "publicKeyJwk": {
+    "crv": "P-256",
+    "kid": "key1",
+    "kty": "EC",
+    "x": "RTx_2cyYcGVSIRP_826S32BiZxSgnzyXgRYmKP8N2l0",
+    "y": "unnPzMAnbByBMq2l9WWKsDFE-MDvX6hYhrESsjAaT50"
+  },
+  "type": "JsonWebKey2020"
+}
+```
+
+#### keys.getAll
+
+Retrieve all public keys from the signer service. The result is JSON array of
+keys in JWK format wrapped in a DID verification method envelope.
+
+Example:
+```
+package example.getAllKeys
+
+_ := keys.getAll()
+```
+
+Result:
+```json
+[
+  {
+    "id": "key1",
+    "publicKeyJwk": {
+      "crv": "P-256",
+      "kid": "key1",
+      "kty": "EC",
+      "x": "RTx_2cyYcGVSIRP_826S32BiZxSgnzyXgRYmKP8N2l0",
+      "y": "unnPzMAnbByBMq2l9WWKsDFE-MDvX6hYhrESsjAaT50"
+    },
+    "type": "JsonWebKey2020"
+  },
+  {
+    ...
+  }
+]
+```
+
+#### issuer
+
+Retrieve DID issuer value configured in the signer service.
+
+Example:
+```
+package example.getIssuer
+
+did := issuer().did
+```
+
+Result:
+```json
+{
+  "did": "did:key:z6Mkfriq1MqLBoPWecGoDLjguo1sB9brj6wT3qZ5BxkKpuP6"
+}
+```
+
+#### proof.create
+
+Create a proof for Verifiable Credential or Verifiable Presentation.
+The function accepts one argument which represents a VC or VP in JSON format.
+It calls the signer service to generate a proof and returns the response, 
+which is the same VC/VP but with proof section. 
+
+Example Policy:
+```
+package example.createProof
+
+_ := proof.create(input)
+```
+
+Example VC given to policy evaluation:
+```json
+{
+  "@context": [
+    "https://www.w3.org/2018/credentials/v1",
+    "https://w3id.org/security/suites/jws-2020/v1",
+    "https://www.w3.org/2018/credentials/examples/v1"
+  ],
+  "credentialSubject": {
+    "allow": true,
+    "id": "example/examplePolicy/1.0"
+  },
+  "issuanceDate": "2022-07-12T13:59:35.246990412Z",
+  "issuer": "did:web:gaiax.vereign.com:tsa:policy:policy:example:returnDID:1.0:evaluation",
+  "type": "VerifiableCredential"
+}
+```
+
+Example Response:
+```json
+{
+  "@context": [
+    "https://www.w3.org/2018/credentials/v1",
+    "https://w3id.org/security/suites/jws-2020/v1",
+    "https://www.w3.org/2018/credentials/examples/v1"
+  ],
+  "credentialSubject": {
+    "allow": true,
+    "id": "example/examplePolicy/1.0"
+  },
+  "issuanceDate": "2022-07-12T13:59:35.246990412Z",
+  "issuer": "did:web:gaiax.vereign.com:tsa:policy:policy:example:returnDID:1.0:evaluation",
+  "proof": {
+    "created": "2022-07-21T09:57:37.761706653Z",
+    "jws": "eyJhbGciOiJKc29uV2ViU2lnbmF0dXJlMjAyMCIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..MEUCIQCOuTbwqembXOv2wjPhPkjR5Minf27DhO_KbNmXdxRxKQIgK3DTaucbir5SYNi_5Xwj8mpKoXxoKzF5_ZYUJB98IBE",
+    "proofPurpose": "assertionMethod",
+    "type": "JsonWebSignature2020",
+    "verificationMethod": "did:web:gaiax.vereign.com:tsa:policy:policy:example:returnDID:1.0:evaluation#key1"
+  },
+  "type": "VerifiableCredential"
+}
+```
+
+#### proof.verify
+
+Verify a proof for Verifiable Credential or Verifiable Presentation.
+The function accepts one argument which represents a VC or VP in JSON format.
+It calls the signer service to validate the proof.
+
+Example Policy:
+```
+package example.verifyProof
+
+valid := proof.verify(input)
+```
+
+Example VC given to policy evaluation:
+```json
+{
+  "@context": [
+    "https://www.w3.org/2018/credentials/v1",
+    "https://w3id.org/security/suites/jws-2020/v1",
+    "https://www.w3.org/2018/credentials/examples/v1"
+  ],
+  "credentialSubject": {
+    "allow": true,
+    "id": "example/examplePolicy/1.0"
+  },
+  "issuanceDate": "2022-07-12T13:59:35.246990412Z",
+  "issuer": "did:web:gaiax.vereign.com:tsa:policy:policy:example:returnDID:1.0:evaluation",
+  "proof": {
+    "created": "2022-07-21T09:57:37.761706653Z",
+    "jws": "eyJhbGciOiJKc29uV2ViU2lnbmF0dXJlMjAyMCIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..MEUCIQCOuTbwqembXOv2wjPhPkjR5Minf27DhO_KbNmXdxRxKQIgK3DTaucbir5SYNi_5Xwj8mpKoXxoKzF5_ZYUJB98IBE",
+    "proofPurpose": "assertionMethod",
+    "type": "JsonWebSignature2020",
+    "verificationMethod": "did:web:gaiax.vereign.com:tsa:policy:policy:example:returnDID:1.0:evaluation#key1"
+  },
+  "type": "VerifiableCredential"
+}
+```
+
+Result:
+```json
+{
+  "valid": true
+}
+```
+
+#### ocm.getLoginProofInvitation
+
+Get a Proof Invitation URL from OCM's "out-of-band" endpoint.
+This function accepts two arguments. The first argument is an array of scopes used to identify
+credential types in OCM. The second argument is a map between scopes and credential types
+which is statically defined in a `data.json` file.
+
+Example request body:
+```json
+{
+  "scope": ["openid", "email"]
+}
+```
+
+Example `data.json` file containing "scope-to-credential-type" map:
+```json
+{
+  "scopes": {
+    "openid": "principalMemberCredential",
+    "email": "universityCert"
+  }
+}
+```
+
+Example policy:
+
+```rego
+package example.GetLoginProofInvitation
+
+_ = ocm.getLoginProofInvitation(input.scope, data.scopes)
+```
+
+Result:
+
+```json
+{
+    "link": "https://ocm:443/didcomm/?d_m=eyJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vc9tbSJ9fQ",
+    "requestId": "851076fa-da78-444a-9127-e636c5102f40"
+}
+```
+
+#### ocm.GetLoginProofResult
+
+Get a Proof Invitation result from OCM containing a flattened list of claims.
+This function accepts one argument which is the `resuestId` from the
+`ocm.getLoginProofInvitation` result.
+
+Example policy:
+
+```rego
+package example.GetLoginProofResult
+
+_ = ocm.getLoginProofResult(input.requestId)
+```
+
+Result:
+```json
+{
+    "name": "John Doe",
+    "given_name": "John",
+    "family_name": "Doe",
+    "email": "example@example.com",
+    "email_verified": true,
+    "preferred_username": "john",
+    "gender": "NA"
+}
+```