diff --git a/.gitignore b/.gitignore
index 5f8c3feae5ccb8f8500cf0d54ded6da0079cfe02..d7c8d680d0598ba1ac993843cf1d2ee7f45fad02 100644
--- a/.gitignore
+++ b/.gitignore
@@ -129,7 +129,7 @@ asapo_tools/pkg
 
 #version files
 
-common/cpp/include/asapo/common/version.h
+common/cpp/include/asapo/common/internal/version.h
 common/go/src/asapo_common/version/version_lib.go
 
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a26180846d0335d7dd3b4f09f651def6b38b25f1..27c7a0824aafd5d923b714998da6b8de03a3146b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,15 +1,16 @@
-## 21.03.0 (in progress)
+## 21.03.0
 
  IMPROVEMENTS
-<<<<<<< HEAD
 * Producer API - queue limits in Python, for C++ return original data in error custom data      
 * Consumer API - add GetCurrentDatasetCount/get_current_dataset_count function with option to include or exclude incomplete datasets
 * Consumer API - GetStreamList/get_stream_list - can filter finished/unfinished streams now
 * Producer/Consumer API - StreamInfo structure/Python dictionary include more information (is stream finished or not, ...) 
 * Switch to JWT tokens (token has more symbols, expiration time, can be revoked and there are two type of tokens - with read/write access rights)
+* Improved versioning. Producer/Consumer API - introduce GetVersionInfo/get_version_info, compatiblity check between clients and server
 
 BREAKING CHANGES
 * Consumer API (C++ only)- GetStreamList has now extra argument StreamFilter
+* Consumer/Producer libraries need to be updated due to protocol changes
 
 ## 20.12.0
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bdba0ff646a6281f95f0ce701e2744db132003a3..b63879369a8f34781829739606389732150ce49e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,17 @@
 cmake_minimum_required(VERSION 3.7)
 project(ASAPO)
+
+#protocol version changes if one of the microservice API's change
+set (ASAPO_CONSUMER_PROTOCOL "v0.1")
+set (ASAPO_PRODUCER_PROTOCOL "v0.1")
+
+set (ASAPO_DISCOVERY_API_VER "v0.1")
+set (ASAPO_AUTHORIZER_API_VER "v0.1")
+set (ASAPO_BROKER_API_VER "v0.1")
+set (ASAPO_FILE_TRANSFER_SERVICE_API_VER "v0.1")
+set (ASAPO_RECEIVER_API_VER "v0.1")
+set (ASAPO_RDS_API_VER "v0.1")
+
 set(CMAKE_CXX_STANDARD 11)
 IF(WIN32)
     set(CMAKE_CXX_FLAGS_DEBUG "/MTd")
diff --git a/CMakeModules/prepare_version.cmake b/CMakeModules/prepare_version.cmake
index 02bd80de29d1097719e79e97c87df80b850e7a76..7ef56e9486d3c798234c767aedcca48654cf5821 100644
--- a/CMakeModules/prepare_version.cmake
+++ b/CMakeModules/prepare_version.cmake
@@ -1,4 +1,4 @@
 string(TIMESTAMP TIMESTAMP "%H:%M:%S %d.%m.%Y UTC" UTC)
 
-configure_file(${PROJECT_SOURCE_DIR}/common/cpp/include/asapo/common/version.h.in ${PROJECT_SOURCE_DIR}/common/cpp/include/asapo/common/version.h @ONLY)
+configure_file(${PROJECT_SOURCE_DIR}/common/cpp/include/asapo/common/internal/version.h.in ${PROJECT_SOURCE_DIR}/common/cpp/include/asapo/common/internal/version.h @ONLY)
 configure_file(${PROJECT_SOURCE_DIR}/common/go/src/asapo_common/version/version_lib.go.in ${PROJECT_SOURCE_DIR}/common/go/src/asapo_common/version/version_lib.go @ONLY)
diff --git a/CMakeModules/prepare_version_tag.cmake b/CMakeModules/prepare_version_tag.cmake
index 308beae3a9cf818823b21b68b568e6dbdf1e0085..35273cb2576e98f211cd4fb36b662070dc417e92 100644
--- a/CMakeModules/prepare_version_tag.cmake
+++ b/CMakeModules/prepare_version_tag.cmake
@@ -14,7 +14,7 @@ execute_process(COMMAND git rev-parse --abbrev-ref HEAD
 string(STRIP ${BRANCH} BRANCH)
 cleanup(BRANCH)
 
-execute_process(COMMAND git rev-parse --short HEAD
+execute_process(COMMAND git rev-parse --short=10 HEAD
         OUTPUT_VARIABLE ASAPO_VERSION_COMMIT
         WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
 string(STRIP ${ASAPO_VERSION_COMMIT} ASAPO_VERSION_COMMIT)
diff --git a/PROTOCOL-VERSIONS.md b/PROTOCOL-VERSIONS.md
new file mode 100644
index 0000000000000000000000000000000000000000..e47b371f29a04c26cd9b121159f1453bf4a99a17
--- /dev/null
+++ b/PROTOCOL-VERSIONS.md
@@ -0,0 +1,10 @@
+### Producer Protocol
+| Release      | Supported by client | Supported by server  | Status           |
+| ------------ | ------------------- | -------------------- | ---------------- |
+| v0.1         | 21.03.0 - 21.03.0   | 21.03.0  - 21.03.0   | Current version  |
+
+
+### Consumer Protocol
+| Release      | Supported by client | Supported by server  | Status           |
+| ------------ | ------------------- | -------------------- | ---------------- |
+| v0.1         | 21.03.0 - 21.03.0   | 21.03.0  - 21.03.0   | Current version  |
diff --git a/VERSIONS.md b/VERSIONS.md
new file mode 100644
index 0000000000000000000000000000000000000000..67aeaf79892c01d4e1ab4a5b850826d4a5837900
--- /dev/null
+++ b/VERSIONS.md
@@ -0,0 +1,11 @@
+### Producer API
+
+| Release      | API changed | Breaking changes | Protocol | Supported by server up to | Status |
+| ------------ | ----------- |----------------- | -------- | ------------------------- | ------- |
+| 21.03.0      | Yes         | No               | v0.1     | 21.03.0                   | Current version  |
+
+### Consumer API
+
+| Release      | API changed | Breaking changes | Protocol | Supported by server up to | Status |
+| ------------ | ----------- |----------------- | -------- | ------------------------- | ------- |
+| 21.03.0      | Yes         | Yes              | v0.1     | 21.03.0                   | Current version  |
diff --git a/authorizer/src/asapo_authorizer/server/folder_token.go b/authorizer/src/asapo_authorizer/server/folder_token.go
index f29a5b318b87042c040ddbe950927ca778b20a1c..6b80193478187250f1d14df00f754bcd6bde5181 100644
--- a/authorizer/src/asapo_authorizer/server/folder_token.go
+++ b/authorizer/src/asapo_authorizer/server/folder_token.go
@@ -3,6 +3,7 @@ package server
 import (
 	"asapo_common/structs"
 	"asapo_common/utils"
+	"asapo_common/version"
 	"net/http"
 	"time"
 	log "asapo_common/logger"
@@ -11,20 +12,20 @@ import (
 )
 
 type folderTokenRequest struct {
-	Folder string
+	Folder     string
 	BeamtimeId string
 	Token      string
 }
 
 type folderToken struct {
-	Token      string
+	Token string
 }
 
 /*func routeFolderToken(w http.ResponseWriter, r *http.Request) {
 	utils.ProcessJWTAuth(processFolderTokenRequest,settings.secret)(w,r)
 }*/
 
-func prepareJWTToken(request folderTokenRequest) (string,error) {
+func prepareJWTToken(request folderTokenRequest) (string, error) {
 	var claims utils.CustomClaims
 	var extraClaim structs.FolderTokenTokenExtraClaim
 
@@ -35,40 +36,39 @@ func prepareJWTToken(request folderTokenRequest) (string,error) {
 
 }
 
-func folderTokenResponce(token string) []byte{
+func folderTokenResponce(token string) []byte {
 	return []byte(token)
 }
 
 func checkBeamtimeToken(request folderTokenRequest) error {
-	_,err :=  checkToken(request.Token,utils.SubjectFromBeamtime(request.BeamtimeId))
+	_, err := checkToken(request.Token, utils.SubjectFromBeamtime(request.BeamtimeId))
 	return err
 }
 
-
-func extractFolderTokenrequest(r *http.Request) (folderTokenRequest,error) {
+func extractFolderTokenrequest(r *http.Request) (folderTokenRequest, error) {
 	var request folderTokenRequest
-	err := utils.ExtractRequest(r,&request)
+	err := utils.ExtractRequest(r, &request)
 	if err != nil {
-		return folderTokenRequest{},err
+		return folderTokenRequest{}, err
 	}
 
-	if len(request.Folder)==0 ||len(request.BeamtimeId)==0 || len(request.Token) == 0 {
-		return folderTokenRequest{},errors.New("some request fields are empty")
+	if len(request.Folder) == 0 || len(request.BeamtimeId) == 0 || len(request.Token) == 0 {
+		return folderTokenRequest{}, errors.New("some request fields are empty")
 	}
-	return request,nil
+	return request, nil
 
 }
 
 func checkBeamtimeFolder(request folderTokenRequest) error {
-	beamtimeMeta, err := findMeta(SourceCredentials{request.BeamtimeId,"auto","","",""})
+	beamtimeMeta, err := findMeta(SourceCredentials{request.BeamtimeId, "auto", "", "", ""})
 	if err != nil {
-		log.Error("cannot get beamtime meta"+err.Error())
+		log.Error("cannot get beamtime meta" + err.Error())
 		return err
 	}
 
 	folder := filepath.Clean(request.Folder)
-	if (folder != filepath.Clean(beamtimeMeta.OnlinePath) && folder != filepath.Clean(beamtimeMeta.OfflinePath)) {
-		err_string := folder + " does not match beamtime folders "+beamtimeMeta.OnlinePath+" or " +beamtimeMeta.OfflinePath
+	if folder != filepath.Clean(beamtimeMeta.OnlinePath) && folder != filepath.Clean(beamtimeMeta.OfflinePath) {
+		err_string := folder + " does not match beamtime folders " + beamtimeMeta.OnlinePath + " or " + beamtimeMeta.OfflinePath
 		log.Error(err_string)
 		return errors.New(err_string)
 	}
@@ -76,28 +76,37 @@ func checkBeamtimeFolder(request folderTokenRequest) error {
 	return nil
 }
 
+func checkAuthorizerApiVersion(w http.ResponseWriter, r *http.Request) bool {
+	_, ok := utils.PrecheckApiVersion(w, r, version.GetAuthorizerApiVersion())
+	return ok
+}
+
 func routeFolderToken(w http.ResponseWriter, r *http.Request) {
+	if ok := checkAuthorizerApiVersion(w, r); !ok {
+		return
+	}
+
 	request, err := extractFolderTokenrequest(r)
 	if err != nil {
-		utils.WriteServerError(w,err,http.StatusBadRequest)
+		utils.WriteServerError(w, err, http.StatusBadRequest)
 		return
 	}
 
 	err = checkBeamtimeToken(request)
 	if err != nil {
-		utils.WriteServerError(w,err,http.StatusUnauthorized)
+		utils.WriteServerError(w, err, http.StatusUnauthorized)
 		return
 	}
 
 	err = checkBeamtimeFolder(request)
 	if err != nil {
-		utils.WriteServerError(w,err,http.StatusUnauthorized)
+		utils.WriteServerError(w, err, http.StatusUnauthorized)
 		return
 	}
 
 	token, err := prepareJWTToken(request)
 	if err != nil {
-		utils.WriteServerError(w,err,http.StatusInternalServerError)
+		utils.WriteServerError(w, err, http.StatusInternalServerError)
 		return
 	}
 
diff --git a/authorizer/src/asapo_authorizer/server/folder_token_test.go b/authorizer/src/asapo_authorizer/server/folder_token_test.go
index 5b89f3b39ccf62e353b7feb622e214ad9d3de04c..ee9ab2f5088474e753e811c6440196bfa6f2d0ba 100644
--- a/authorizer/src/asapo_authorizer/server/folder_token_test.go
+++ b/authorizer/src/asapo_authorizer/server/folder_token_test.go
@@ -50,7 +50,7 @@ func TestFolderToken(t *testing.T) {
 		if test.status == http.StatusBadRequest {
 			request =makeRequest(authorizationRequest{})
 		}
-		w := doPostRequest("/folder",request,"")
+		w := doPostRequest("/v0.1/folder",request,"")
 		if w.Code == http.StatusOK {
 			body, _ := ioutil.ReadAll(w.Body)
 			claims,_ := utils.CheckJWTToken(string(body),"secret_folder")
@@ -66,3 +66,11 @@ func TestFolderToken(t *testing.T) {
 	}
 }
 
+func TestFolderTokenWrongProtocol(t *testing.T) {
+		request :=  makeRequest(folderTokenRequest{"abs_path","beamtime_id","token"})
+		w := doPostRequest("/v0.2/folder",request,"")
+		assert.Equal(t, http.StatusUnsupportedMediaType, w.Code, "wrong protocol")
+}
+
+
+
diff --git a/authorizer/src/asapo_authorizer/server/listroutes.go b/authorizer/src/asapo_authorizer/server/listroutes.go
index 370dd9dfa5b9cc40fd8f9db92ca4cd4449e06d21..09b695091ffc4ecf686715a5b7a4f10434280cbb 100644
--- a/authorizer/src/asapo_authorizer/server/listroutes.go
+++ b/authorizer/src/asapo_authorizer/server/listroutes.go
@@ -26,7 +26,7 @@ var listRoutes = utils.Routes{
 	utils.Route{
 		"Folder Token",
 		"POST",
-		"/folder",
+		"/{apiver}/folder",
 		routeFolderToken,
 	},
 	utils.Route{
diff --git a/broker/src/asapo_broker/server/get_commands_test.go b/broker/src/asapo_broker/server/get_commands_test.go
index 0fc547da341cf9fdc04312a0480c6f05046929f2..c472ddb4c3948004c412ea6267da70a582a72084 100644
--- a/broker/src/asapo_broker/server/get_commands_test.go
+++ b/broker/src/asapo_broker/server/get_commands_test.go
@@ -58,7 +58,7 @@ func (suite *GetCommandsTestSuite) TestGetCommandsCallsCorrectRoutine() {
 	for _, test := range testsGetCommand {
 		suite.mock_db.On("ProcessRequest", database.Request{DbName: expectedDBName, DbCollectionName: test.stream, GroupId: test.groupid, Op: test.command, ExtraParam: test.externalParam}).Return([]byte("Hello"), nil)
 		logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request "+test.command)))
-		w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + test.reqString+correctTokenSuffix+test.queryParams)
+		w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + test.reqString+correctTokenSuffix+test.queryParams)
 		suite.Equal(http.StatusOK, w.Code, test.command+ " OK")
 		suite.Equal("Hello", string(w.Body.Bytes()), test.command+" sends data")
 	}
diff --git a/broker/src/asapo_broker/server/get_health.go b/broker/src/asapo_broker/server/get_health.go
index ce5f45ee531005cb5817410052b89b3449761028..c4ff315d16533e967019c3e4bbf60cc8404e775d 100644
--- a/broker/src/asapo_broker/server/get_health.go
+++ b/broker/src/asapo_broker/server/get_health.go
@@ -9,6 +9,5 @@ func routeGetHealth(w http.ResponseWriter, r *http.Request) {
 	if err != nil {
 		ReconnectDb()
 	}
-	r.Header.Set("Content-type", "application/json")
 	w.WriteHeader(http.StatusNoContent)
 }
diff --git a/broker/src/asapo_broker/server/get_health_test.go b/broker/src/asapo_broker/server/get_health_test.go
index a318c8d953d8ce3abc179f7fbdc20076a17b3785..67ade394949cf19882fa0fb0b1cf8ea5a3132ef3 100644
--- a/broker/src/asapo_broker/server/get_health_test.go
+++ b/broker/src/asapo_broker/server/get_health_test.go
@@ -34,7 +34,7 @@ func TestGetHealthTestSuite(t *testing.T) {
 
 func (suite *GetHealthTestSuite) TestGetHealthOk() {
 	suite.mock_db.On("Ping").Return(nil)
-	w := doRequest("/health")
+	w := doRequest("/health","GET","","")
 	suite.Equal(http.StatusNoContent, w.Code)
 }
 
@@ -44,6 +44,6 @@ func (suite *GetHealthTestSuite) TestGetHealthTriesToReconnectsToDataBase() {
 
 	ExpectReconnect(suite.mock_db)
 
-	w := doRequest("/health")
+	w := doRequest("/health","GET","","")
 	suite.Equal(http.StatusNoContent, w.Code)
 }
diff --git a/broker/src/asapo_broker/server/get_meta_test.go b/broker/src/asapo_broker/server/get_meta_test.go
index 4eb0e16547b60e7abb07a60f8667d7aadf9ef1bd..550efb653178533801ed305926cedd2ae1609cbf 100644
--- a/broker/src/asapo_broker/server/get_meta_test.go
+++ b/broker/src/asapo_broker/server/get_meta_test.go
@@ -35,7 +35,7 @@ func TestGetMetaTestSuite(t *testing.T) {
 func (suite *GetMetaTestSuite) TestGetMetaOK() {
 	suite.mock_db.On("ProcessRequest", database.Request{DbName: expectedDBName, DbCollectionName: expectedStream, Op: "meta", ExtraParam: "1"}).Return([]byte(""), nil)
 	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request meta")))
-	w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/0/meta"  + "/1" + correctTokenSuffix,"GET")
+	w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/0/meta"  + "/1" + correctTokenSuffix,"GET")
 	suite.Equal(http.StatusOK, w.Code, "meta OK")
 }
 
diff --git a/broker/src/asapo_broker/server/listroutes.go b/broker/src/asapo_broker/server/listroutes.go
index 8d782f58ec83f4351f898c71d7979be495cdc695..b2d87ccf2d9a1d2f1bad08ba88c567658676c6ef 100644
--- a/broker/src/asapo_broker/server/listroutes.go
+++ b/broker/src/asapo_broker/server/listroutes.go
@@ -8,73 +8,73 @@ var listRoutes = utils.Routes{
 	utils.Route{
 		"GetNext",
 		"Get",
-		"/database/{dbname}/{datasource}/{stream}/{groupid}/next",
+		"/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/{groupid}/next",
 		routeGetNext,
 	},
 	utils.Route{
 		"GetSize",
 		"Get",
-		"/database/{dbname}/{datasource}/{stream}/size",
+		"/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/size",
 		routeGetSize,
 	},
 	utils.Route{
 		"GetStreams",
 		"Get",
-		"/database/{dbname}/{datasource}/{stream}/streams",
+		"/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/streams",
 		routeGetStreams,
 	},
 	utils.Route{
 		"GetLast",
 		"Get",
-		"/database/{dbname}/{datasource}/{stream}/0/last",
+		"/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/0/last",
 		routeGetLast,
 	},
 	utils.Route{
 		"GetLastAck",
 		"Get",
-		"/database/{dbname}/{datasource}/{stream}/{groupid}/lastack",
+		"/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/{groupid}/lastack",
 		routeGetLastAck,
 	},
 	utils.Route{
 		"GetNacks",
 		"Get",
-		"/database/{dbname}/{datasource}/{stream}/{groupid}/nacks",
+		"/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/{groupid}/nacks",
 		routeGetNacks,
 	},
 	utils.Route{
 		"GetID",
 		"Get",
-		"/database/{dbname}/{datasource}/{stream}/0/{id}",
+		"/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/0/{id}",
 		routeGetByID,
 	},
 	utils.Route{
 		"GetMeta",
 		"Get",
-		"/database/{dbname}/{datasource}/{stream}/0/meta/{id}",
+		"/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/0/meta/{id}",
 		routeGetMeta,
 	},
 	utils.Route{
 		"CreateGroup",
 		"Post",
-		"/creategroup",
+		"/{apiver}/creategroup",
 		routeCreateGroupID,
 	},
 	utils.Route{
 		"QueryMessages",
 		"Post",
-		"/database/{dbname}/{datasource}/{stream}/0/querymessages",
+		"/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/0/querymessages",
 		routeQueryMessages,
 	},
 	utils.Route{
 		"ResetConter",
 		"Post",
-		"/database/{dbname}/{datasource}/{stream}/{groupid}/resetcounter",
+		"/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/{groupid}/resetcounter",
 		routeResetCounter,
 	},
 	utils.Route{
 		"MessageOp",
 		"Post",
-		"/database/{dbname}/{datasource}/{stream}/{groupid}/{id}",
+		"/{apiver}/beamtime/{beamtime}/{datasource}/{stream}/{groupid}/{id}",
 		routeMessageOp,
 	},
 	utils.Route{
diff --git a/broker/src/asapo_broker/server/post_create_group.go b/broker/src/asapo_broker/server/post_create_group.go
index b9cfb51f7d10ef99083ffa9a28ec937efff816da..008e72f14d4bf36022a094c923ab301d7ed2bf36 100644
--- a/broker/src/asapo_broker/server/post_create_group.go
+++ b/broker/src/asapo_broker/server/post_create_group.go
@@ -7,6 +7,11 @@ import (
 )
 
 func routeCreateGroupID(w http.ResponseWriter, r *http.Request) {
+	if ok := checkBrokerApiVersion(w, r); !ok {
+		return
+	}
+
+
 	guid := xid.New()
 	w.Write([]byte(guid.String()))
 	logger.Debug("generated new group: " + guid.String())
diff --git a/broker/src/asapo_broker/server/post_create_group_test.go b/broker/src/asapo_broker/server/post_create_group_test.go
index 5f19da351eedf60bc8992a3b7827982d659be194..46f6fb09edd9241e5f54aad5dc7e89192db03152 100644
--- a/broker/src/asapo_broker/server/post_create_group_test.go
+++ b/broker/src/asapo_broker/server/post_create_group_test.go
@@ -32,3 +32,8 @@ func TestGetNewGroup(t *testing.T) {
 
 	logger.UnsetMockLog()
 }
+
+func TestGetNewGroupWrongProtocol(t *testing.T) {
+	w := doRequest("/creategroup", "POST","","/v0.2")
+	assert.Equal(t, http.StatusUnsupportedMediaType, w.Code, "wrong request")
+}
diff --git a/broker/src/asapo_broker/server/post_op_image_test.go b/broker/src/asapo_broker/server/post_op_image_test.go
index 259787e41bc9fc41140daf8bdfb844c55f3939d2..fc1a2d4e72499983f88da4eab17786ffd95f6871 100644
--- a/broker/src/asapo_broker/server/post_op_image_test.go
+++ b/broker/src/asapo_broker/server/post_op_image_test.go
@@ -36,19 +36,19 @@ func (suite *MessageOpTestSuite) TestAckMessageOpOK() {
 	query_str := "{\"Id\":1,\"Op\":\"ackmessage\"}"
 	suite.mock_db.On("ProcessRequest", database.Request{DbName: expectedDBName, DbCollectionName: expectedStream, GroupId: expectedGroupID, Op: "ackmessage", ExtraParam: query_str}).Return([]byte(""), nil)
 	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request ackmessage")))
-	w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/1" + correctTokenSuffix,"POST",query_str)
+	w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/1" + correctTokenSuffix,"POST",query_str)
 	suite.Equal(http.StatusOK, w.Code, "ackmessage OK")
 }
 
 
 func (suite *MessageOpTestSuite) TestAckMessageOpErrorWrongOp() {
 	query_str := "\"Id\":1,\"Op\":\"ackmessage\"}"
-	w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/1" + correctTokenSuffix,"POST",query_str)
+	w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/1" + correctTokenSuffix,"POST",query_str)
 	suite.Equal(http.StatusBadRequest, w.Code, "ackmessage wrong")
 }
 
 func (suite *MessageOpTestSuite) TestAckMessageOpErrorWrongID() {
 	query_str := "{\"Id\":1,\"Op\":\"ackmessage\"}"
-	w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/bla" + correctTokenSuffix,"POST",query_str)
+	w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/bla" + correctTokenSuffix,"POST",query_str)
 	suite.Equal(http.StatusBadRequest, w.Code, "ackmessage wrong")
 }
diff --git a/broker/src/asapo_broker/server/post_query_images_test.go b/broker/src/asapo_broker/server/post_query_images_test.go
index 0f2b55c1477c4f27747b3b6ce9effccd9c213a2a..16aca9242eebd867c58f90e5860f3bd9c665cca1 100644
--- a/broker/src/asapo_broker/server/post_query_images_test.go
+++ b/broker/src/asapo_broker/server/post_query_images_test.go
@@ -38,7 +38,7 @@ func (suite *QueryTestSuite) TestQueryOK() {
 	suite.mock_db.On("ProcessRequest", database.Request{DbName: expectedDBName, DbCollectionName: expectedStream,Op: "querymessages", ExtraParam: query_str}).Return([]byte("{}"), nil)
 	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request querymessages")))
 
-	w := doRequest("/database/"+expectedBeamtimeId+"/"+expectedSource+"/"+expectedStream+"/0/querymessages"+correctTokenSuffix, "POST", query_str)
+	w := doRequest("/beamtime/"+expectedBeamtimeId+"/"+expectedSource+"/"+expectedStream+"/0/querymessages"+correctTokenSuffix, "POST", query_str)
 	suite.Equal(http.StatusOK, w.Code, "Query OK")
 }
 
diff --git a/broker/src/asapo_broker/server/post_reset_counter_test.go b/broker/src/asapo_broker/server/post_reset_counter_test.go
index 37f70e2725294ac6aee3ae440000cb24374b16a4..10fb4e1b0a360707df952060f633cb99041d1cfc 100644
--- a/broker/src/asapo_broker/server/post_reset_counter_test.go
+++ b/broker/src/asapo_broker/server/post_reset_counter_test.go
@@ -38,6 +38,6 @@ func (suite *ResetCounterTestSuite) TestResetCounterOK() {
 
 	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request resetcounter")))
 
-	w := doRequest("/database/"+expectedBeamtimeId+"/"+expectedSource+"/"+expectedStream+"/"+expectedGroupID+"/resetcounter"+correctTokenSuffix+"&value=10", "POST")
+	w := doRequest("/beamtime/"+expectedBeamtimeId+"/"+expectedSource+"/"+expectedStream+"/"+expectedGroupID+"/resetcounter"+correctTokenSuffix+"&value=10", "POST")
 	suite.Equal(http.StatusOK, w.Code, "ResetCounter OK")
 }
diff --git a/broker/src/asapo_broker/server/process_request.go b/broker/src/asapo_broker/server/process_request.go
index b5b8e7dd602486fc14292c383b77ec52c15fd609..87b6a5075c842d859a9d40b47666f2b81f96cd8f 100644
--- a/broker/src/asapo_broker/server/process_request.go
+++ b/broker/src/asapo_broker/server/process_request.go
@@ -5,13 +5,14 @@ import (
 	"asapo_common/logger"
 	log "asapo_common/logger"
 	"asapo_common/utils"
+	"asapo_common/version"
 	"github.com/gorilla/mux"
 	"net/http"
 )
 
 func extractRequestParameters(r *http.Request, needGroupID bool) (string, string, string, string, bool) {
 	vars := mux.Vars(r)
-	db_name, ok1 := vars["dbname"]
+	db_name, ok1 := vars["beamtime"]
 
 	datasource, ok3 := vars["datasource"]
 	stream, ok4 := vars["stream"]
@@ -49,8 +50,17 @@ func checkGroupID(w http.ResponseWriter, needGroupID bool, group_id string, db_n
 	return false
 }
 
+func checkBrokerApiVersion(w http.ResponseWriter, r *http.Request) bool {
+	_, ok := utils.PrecheckApiVersion(w, r, version.GetBrokerApiVersion())
+	return ok
+}
+
 func processRequest(w http.ResponseWriter, r *http.Request, op string, extra_param string, needGroupID bool) {
-	r.Header.Set("Content-type", "application/json")
+	if ok := checkBrokerApiVersion(w, r); !ok {
+		return
+	}
+
+
 	w.Header().Set("Access-Control-Allow-Origin", "*")
 	db_name, datasource, stream, group_id, ok := extractRequestParameters(r, needGroupID)
 	if !ok {
diff --git a/broker/src/asapo_broker/server/process_request_test.go b/broker/src/asapo_broker/server/process_request_test.go
index f84907035beb7627df65ef55556eec9863ea96cb..5ce3aa70bb26c91c332a0733d11d17c5b64fc1dd 100644
--- a/broker/src/asapo_broker/server/process_request_test.go
+++ b/broker/src/asapo_broker/server/process_request_test.go
@@ -78,16 +78,20 @@ func doRequest(path string, extra_params ...string) *httptest.ResponseRecorder {
 	if len(extra_params) > 1 {
 		body = strings.NewReader(extra_params[1])
 	}
+	ver := "/v0.1"
+	if len(extra_params) > 2 {
+		ver = extra_params[2]
+	}
 
 	mux := utils.NewRouter(listRoutes)
-	req, _ := http.NewRequest(m, path, body)
+	req, _ := http.NewRequest(m, ver+path, body)
 	w := httptest.NewRecorder()
 	mux.ServeHTTP(w, req)
 	return w
 }
 
 func TestProcessRequestWithoutDatabaseName(t *testing.T) {
-	w := doRequest("/database/next")
+	w := doRequest("/beamtime/next")
 	assert.Equal(t, http.StatusNotFound, w.Code, "no database name")
 }
 
@@ -124,7 +128,7 @@ func TestProcessRequestTestSuite(t *testing.T) {
 func (suite *ProcessRequestTestSuite) TestProcessRequestWithWrongToken() {
 	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("wrong JWT token")))
 
-	w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + suffixWithWrongToken)
+	w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + suffixWithWrongToken)
 
 	suite.Equal(http.StatusUnauthorized, w.Code, "wrong token")
 }
@@ -132,7 +136,7 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestWithWrongToken() {
 func (suite *ProcessRequestTestSuite) TestProcessRequestWithNoToken() {
 	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("cannot extract")))
 
-	w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + wrongTokenSuffix)
+	w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + wrongTokenSuffix)
 
 	suite.Equal(http.StatusUnauthorized, w.Code, "no token")
 }
@@ -146,7 +150,7 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestWithWrongDatabaseName()
 
 	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request next")))
 
-	w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix)
+	w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix)
 
 	suite.Equal(http.StatusConflict, w.Code, "wrong database name")
 }
@@ -162,7 +166,7 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestWithConnectionError() {
 	ExpectReconnect(suite.mock_db)
 	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("reconnected")))
 
-	w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix)
+	w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix)
 	time.Sleep(time.Second)
 	suite.Equal(http.StatusNotFound, w.Code, "data not found")
 }
@@ -177,7 +181,7 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestWithInternalDBError() {
 	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("reconnected")))
 
 	ExpectReconnect(suite.mock_db)
-	w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix)
+	w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix)
 	time.Sleep(time.Second)
 
 	suite.Equal(http.StatusNotFound, w.Code, "internal error")
@@ -191,13 +195,13 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestAddsCounter() {
 
 	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request next in "+expectedDBName)))
 
-	doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix)
+	doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix)
 	suite.Equal(1, statistics.GetCounter(), "ProcessRequest increases counter")
 }
 
 func (suite *ProcessRequestTestSuite) TestProcessRequestWrongGroupID() {
 	logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("wrong groupid")))
-	w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + wrongGroupID + "/next" + correctTokenSuffix)
+	w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + wrongGroupID + "/next" + correctTokenSuffix)
 	suite.Equal(http.StatusBadRequest, w.Code, "wrong group id")
 }
 
@@ -208,5 +212,11 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestAddsDataset() {
 
 	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing request next in "+expectedDBName)))
 
-	doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix + "&dataset=true")
+	doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix + "&dataset=true")
+}
+
+
+func (suite *ProcessRequestTestSuite) TestProcessRequestErrorOnWrongProtocol() {
+	w := doRequest("/beamtime/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + correctTokenSuffix,"GET","","/v0.2")
+	suite.Equal(http.StatusUnsupportedMediaType, w.Code, "wrong protocol")
 }
diff --git a/broker/src/asapo_broker/server/server.go b/broker/src/asapo_broker/server/server.go
index c69d58e578ba85eeee96e31836cb5db26b533aab..1537fa08642c36454b679b54e218d5ad5b6f4007 100644
--- a/broker/src/asapo_broker/server/server.go
+++ b/broker/src/asapo_broker/server/server.go
@@ -18,6 +18,7 @@ type serverSettings struct {
 	DatabaseServer              string
 	PerformanceDbServer         string
 	PerformanceDbName           string
+	MonitorPerformance 			bool
 	AuthorizationServer         string
 	Port                        int
 	LogLevel                    string
diff --git a/broker/src/asapo_broker/server/server_nottested.go b/broker/src/asapo_broker/server/server_nottested.go
index 3f7cb0a746949205697741387c8e28e1d1402b61..ae96af4d5a957f7bc5529ad0f78510a648cdabd0 100644
--- a/broker/src/asapo_broker/server/server_nottested.go
+++ b/broker/src/asapo_broker/server/server_nottested.go
@@ -18,7 +18,9 @@ func StartStatistics() {
 }
 
 func Start() {
-	StartStatistics()
+	if settings.MonitorPerformance {
+		StartStatistics()
+	}
 	mux := utils.NewRouter(listRoutes)
 	log.Info("Listening on port: " + strconv.Itoa(settings.Port))
 	log.Fatal(http.ListenAndServe(":"+strconv.Itoa(settings.Port), http.HandlerFunc(mux.ServeHTTP)))
diff --git a/broker/src/asapo_broker/server/statistics_nottested.go b/broker/src/asapo_broker/server/statistics_nottested.go
index c2728623d93b161305d5f9285cea9af751350466..3b6d3ee4b65a2c55957ed253cc473a36b91648e8 100644
--- a/broker/src/asapo_broker/server/statistics_nottested.go
+++ b/broker/src/asapo_broker/server/statistics_nottested.go
@@ -9,7 +9,7 @@ import (
 
 func (st *serverStatistics) Monitor() {
 	for {
-		time.Sleep(1000 * time.Millisecond)
+		time.Sleep(10000 * time.Millisecond)
 		if err := st.WriteStatistic(); err != nil {
 		    logstr := "sending statistics to " + settings.PerformanceDbServer + ", dbname: " + settings.PerformanceDbName
 			log.Error(logstr + " - " + err.Error())
diff --git a/common/cpp/CMakeLists.txt b/common/cpp/CMakeLists.txt
index f59ad1bcf8f18acae4dc8da02ccd73eb654cb55d..8f90ff257a0db963ffc133518e2768c020975fc7 100644
--- a/common/cpp/CMakeLists.txt
+++ b/common/cpp/CMakeLists.txt
@@ -6,6 +6,9 @@ add_subdirectory(src/json_parser)
 
 add_subdirectory(src/data_structs)
 
+add_subdirectory(src/version)
+
+
 add_subdirectory(src/http_client)
 
 add_subdirectory(src/logger)
@@ -20,7 +23,8 @@ endif()
 
 install(DIRECTORY ${ASAPO_CXX_COMMON_INCLUDE_DIR}/asapo/common
         DESTINATION include/asapo
-        PATTERN "*.h.in" EXCLUDE)
+        PATTERN "*.h.in" EXCLUDE
+        PATTERN "*/internal" EXCLUDE)
 
 install(DIRECTORY ${ASAPO_CXX_COMMON_INCLUDE_DIR}/asapo/logger
         DESTINATION include/asapo )
diff --git a/common/cpp/include/asapo/common/data_structs.h b/common/cpp/include/asapo/common/data_structs.h
index f95aea6a769c64948132d88855735573f79e9ba8..96cdaf8c81ef046c05d7699d6e90004a947d149c 100644
--- a/common/cpp/include/asapo/common/data_structs.h
+++ b/common/cpp/include/asapo/common/data_structs.h
@@ -14,51 +14,49 @@ namespace asapo {
 const std::string kFinishStreamKeyword = "asapo_finish_stream";
 const std::string kNoNextStreamKeyword = "asapo_no_next";
 
-
 class JsonStringParser;
 
 uint64_t NanosecsEpochFromTimePoint(std::chrono::system_clock::time_point);
-uint64_t  EpochNanosecsFromNow();
+uint64_t EpochNanosecsFromNow();
 std::chrono::system_clock::time_point TimePointfromNanosec(uint64_t nanoseconds_from_epoch);
 std::string IsoDateFromEpochNanosecs(uint64_t time_from_epoch_nanosec);
 uint64_t NanosecsEpochFromISODate(std::string date_time);
 
-bool TimeFromJson(const JsonStringParser& parser, const std::string& name, std::chrono::system_clock::time_point* val);
+bool TimeFromJson(const JsonStringParser &parser, const std::string &name, std::chrono::system_clock::time_point* val);
 
 class MessageMeta {
-  public:
-    std::string name;
-    std::chrono::system_clock::time_point timestamp;
-    uint64_t size{0};
-    uint64_t id{0};
-    std::string source;
-    std::string metadata;
-    uint64_t buf_id{0};
-    uint64_t dataset_substream{0};
-    std::string Json() const;
-    bool SetFromJson(const std::string& json_string);
-    std::string FullName(const std::string& base_path) const;
+ public:
+  std::string name;
+  std::chrono::system_clock::time_point timestamp;
+  uint64_t size{0};
+  uint64_t id{0};
+  std::string source;
+  std::string metadata;
+  uint64_t buf_id{0};
+  uint64_t dataset_substream{0};
+  std::string Json() const;
+  bool SetFromJson(const std::string &json_string);
+  std::string FullName(const std::string &base_path) const;
 };
 
-
 struct StreamInfo {
-    uint64_t last_id{0};
-    std::string name;
-    bool finished{false};
-    std::string next_stream;
-    std::chrono::system_clock::time_point timestamp_created;
-    std::chrono::system_clock::time_point timestamp_lastentry;
-    std::string Json() const;
-    bool SetFromJson(const std::string &json_string);
+  uint64_t last_id{0};
+  std::string name;
+  bool finished{false};
+  std::string next_stream;
+  std::chrono::system_clock::time_point timestamp_created;
+  std::chrono::system_clock::time_point timestamp_lastentry;
+  std::string Json() const;
+  bool SetFromJson(const std::string &json_string);
 };
 
 using StreamInfos = std::vector<StreamInfo>;
 
-inline bool operator==(const MessageMeta& lhs, const MessageMeta& rhs) {
-    return  (lhs.name == rhs.name &&
-             lhs.id == rhs.id &&
-             lhs.timestamp == rhs.timestamp &&
-             lhs.size == rhs.size);
+inline bool operator==(const MessageMeta &lhs, const MessageMeta &rhs) {
+    return (lhs.name == rhs.name &&
+        lhs.id == rhs.id &&
+        lhs.timestamp == rhs.timestamp &&
+        lhs.size == rhs.size);
 }
 
 using MessageData = std::unique_ptr<uint8_t[]>;
@@ -69,10 +67,10 @@ using MessageMetas = std::vector<MessageMeta>;
 using IdList = std::vector<uint64_t>;
 
 struct DataSet {
-    uint64_t id;
-    uint64_t expected_size;
-    MessageMetas content;
-    bool SetFromJson(const std::string& json_string);
+  uint64_t id;
+  uint64_t expected_size;
+  MessageMetas content;
+  bool SetFromJson(const std::string &json_string);
 };
 
 using SubDirList = std::vector<std::string>;
@@ -82,38 +80,122 @@ enum class SourceType {
   kRaw
 };
 
-Error GetSourceTypeFromString(std::string stype,SourceType *type);
+Error GetSourceTypeFromString(std::string stype, SourceType* type);
 std::string GetStringFromSourceType(SourceType type);
 
 struct SourceCredentials {
-    SourceCredentials(SourceType type, std::string beamtime, std::string beamline, std::string data_source, std::string token):
-        beamtime_id{std::move(beamtime)},
-        beamline{std::move(beamline)},
-        data_source{std::move(data_source)},
-        user_token{std::move(token)},
-        type{type}{};
-    SourceCredentials() {};
-    static const std::string kDefaultStream;
-    static const std::string kDefaultBeamline;
-    static const std::string kDefaultBeamtimeId;
-    std::string beamtime_id;
-    std::string beamline;
-    std::string data_source;
-    std::string user_token;
-    SourceType type = SourceType::kProcessed;
-    std::string GetString() {
-        return (type==SourceType::kRaw?std::string("raw"):std::string("processed")) + "%"+ beamtime_id + "%" + beamline + "%" + data_source + "%" + user_token;
-    };
+  SourceCredentials(SourceType type,
+                    std::string beamtime,
+                    std::string beamline,
+                    std::string data_source,
+                    std::string token) :
+      beamtime_id{std::move(beamtime)},
+      beamline{std::move(beamline)},
+      data_source{std::move(data_source)},
+      user_token{std::move(token)},
+      type{type} {};
+  SourceCredentials() {};
+  static const std::string kDefaultStream;
+  static const std::string kDefaultBeamline;
+  static const std::string kDefaultBeamtimeId;
+  std::string beamtime_id;
+  std::string beamline;
+  std::string data_source;
+  std::string user_token;
+  SourceType type = SourceType::kProcessed;
+  std::string GetString() {
+      return (type == SourceType::kRaw ? std::string("raw") : std::string("processed")) + "%" + beamtime_id + "%"
+          + beamline + "%" + data_source + "%" + user_token;
+  };
 };
 
 enum IngestModeFlags : uint64_t {
-    kTransferData = 1 << 0,
-    kTransferMetaDataOnly = 1 << 1,
-    kStoreInFilesystem = 1 << 2,
-    kStoreInDatabase = 1 << 3,
+  kTransferData = 1 << 0,
+  kTransferMetaDataOnly = 1 << 1,
+  kStoreInFilesystem = 1 << 2,
+  kStoreInDatabase = 1 << 3,
 };
 
 const uint64_t kDefaultIngestMode = kTransferData | kStoreInFilesystem | kStoreInDatabase;
 
+class ClientProtocol {
+ private:
+  std::string version_;
+  std::string discovery_version_;
+  std::string name_;
+ public:
+  ClientProtocol(std::string version, std::string name,std::string discovery_version) : version_{version}, name_{name} {
+      discovery_version_ = discovery_version;
+  };
+  ClientProtocol() = delete;
+  virtual std::string GetString() = 0;
+  const std::string &GetVersion() const {
+      return version_;
+  }
+  const std::string &GetDiscoveryVersion() const {
+      return discovery_version_;
+  }
+  const std::string &GetName() const {
+      return name_;
+  }
+};
+
+class ConsumerProtocol final : public ClientProtocol {
+ private:
+  std::string authorizer_version_;
+  std::string file_transfer_service_version_;
+  std::string broker_version_;
+  std::string rds_version_;
+ public:
+  ConsumerProtocol(std::string version,
+                   std::string discovery_version,
+                   std::string authorizer_version,
+                   std::string file_transfer_service_version,
+                   std::string broker_version,
+                   std::string rds_version)
+      : ClientProtocol(version, "consumer protocol",discovery_version) {
+      authorizer_version_ = authorizer_version;
+      file_transfer_service_version_ = file_transfer_service_version;
+      broker_version_ = broker_version;
+      rds_version_ = rds_version;
+  }
+  const std::string &GetAuthorizerVersion() const {
+      return authorizer_version_;
+  }
+  const std::string &GetFileTransferServiceVersion() const {
+      return file_transfer_service_version_;
+  }
+  const std::string &GetRdsVersion() const {
+      return rds_version_;
+  }
+  const std::string &GetBrokerVersion() const {
+      return broker_version_;
+  };
+  ConsumerProtocol() = delete;
+  std::string GetString() override {
+      return std::string();
+  }
+};
+
+class ProducerProtocol final : public ClientProtocol {
+ private:
+  std::string receiver_version_;
+ public:
+  ProducerProtocol(std::string version,
+                   std::string discovery_version,
+                   std::string receiver_version)
+      : ClientProtocol(version, "producer protocol",discovery_version) {
+      receiver_version_ = receiver_version;
+  };
+  const std::string &GetReceiverVersion() const {
+      return receiver_version_;
+  }
+  ProducerProtocol() = delete;
+  std::string GetString() override {
+      return std::string();
+  }
+};
+
 }
+
 #endif //ASAPO_message_meta_H
diff --git a/common/cpp/include/asapo/common/internal/version.h.in b/common/cpp/include/asapo/common/internal/version.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..79fcea4136e61555e17ee7fc03f5d14d7f66a54a
--- /dev/null
+++ b/common/cpp/include/asapo/common/internal/version.h.in
@@ -0,0 +1,45 @@
+#ifndef ASAPO_VERSION_H
+#define ASAPO_VERSION_H
+
+#include <iostream>
+#include "string.h"
+
+#include "asapo/common/data_structs.h"
+#include "asapo/common/error.h"
+#include "asapo/http_client/http_client.h"
+
+namespace asapo {
+
+
+const char kVersion[] = "@ASAPO_VERSION@@ASAPO_VERSION_COMMIT@";
+
+inline void ExitAfterPrintVersionIfNeeded(std::string prefix,int argc, char* argv[]) {
+    if (argc == 2 && strcmp(argv[1], "-v") == 0) {
+        std::cout << prefix << ", version " << kVersion << std::endl;
+        exit(0);
+    }
+}
+
+const ConsumerProtocol kConsumerProtocol{"@ASAPO_CONSUMER_PROTOCOL@","@ASAPO_DISCOVERY_API_VER@",
+                                         "@ASAPO_AUTHORIZER_API_VER@","@ASAPO_FILE_TRANSFER_SERVICE_API_VER@","@ASAPO_BROKER_API_VER@","@ASAPO_RDS_API_VER@"};
+const ProducerProtocol kProducerProtocol{"@ASAPO_PRODUCER_PROTOCOL@","@ASAPO_DISCOVERY_API_VER@", "@ASAPO_RECEIVER_API_VER@"};
+
+inline std::string GetReceiverApiVersion() {
+    return "@ASAPO_RECEIVER_API_VER@";
+}
+
+inline std::string GetRdsApiVersion() {
+    return "@ASAPO_RDS_API_VER@";
+}
+
+inline int VersionToNumber(const std::string& version) {
+    return int(atof(version.c_str()+2)*1000);
+}
+
+Error ExtractVersionFromResponse(const std::string &response,
+                                 const std::string &client,
+                                 std::string* server_info,
+                                 bool* supported);
+}
+
+#endif //ASAPO_VERSION_H
diff --git a/common/cpp/include/asapo/common/networking.h b/common/cpp/include/asapo/common/networking.h
index bd7f5379f302f0fbd05e423b270495e699958bb0..79f29abb4cefe2095cb06859f11611d0b229d142 100644
--- a/common/cpp/include/asapo/common/networking.h
+++ b/common/cpp/include/asapo/common/networking.h
@@ -36,6 +36,7 @@ enum NetworkErrorCode : uint16_t {
     kNetErrorReauthorize,
     kNetErrorWarning,
     kNetErrorWrongRequest,
+    kNetErrorNotSupported,
     kNetErrorNoData,
     kNetAuthorizationError,
     kNetErrorInternalServerError = 65535,
@@ -44,6 +45,7 @@ enum NetworkErrorCode : uint16_t {
 //TODO need to use an serialization framework to ensure struct consistency on different computers
 
 const std::size_t kMaxMessageSize = 1024;
+const std::size_t kMaxVersionSize = 10;
 const std::size_t kNCustomParams = 3;
 using CustomRequestData = uint64_t[kNCustomParams];
 const std::size_t kPosIngestMode = 0;
@@ -56,6 +58,7 @@ struct GenericRequestHeader {
         memcpy(custom_data, header.custom_data, kNCustomParams * sizeof(uint64_t)),
         memcpy(message, header.message, kMaxMessageSize);
         strncpy(stream, header.stream, kMaxMessageSize);
+        strncpy(api_version, header.api_version, kMaxVersionSize);
     }
 
     /* Keep in mind that the message here is just strncpy'ed, you can change the message later */
@@ -65,6 +68,7 @@ struct GenericRequestHeader {
         op_code{i_op_code}, data_id{i_data_id}, data_size{i_data_size}, meta_size{i_meta_size} {
         strncpy(message, i_message.c_str(), kMaxMessageSize);
         strncpy(stream, i_stream.c_str(), kMaxMessageSize);
+        strncpy(api_version,"v0.0", kMaxVersionSize);
     }
 
     Opcode      op_code;
@@ -74,6 +78,7 @@ struct GenericRequestHeader {
     CustomRequestData    custom_data;
     char        message[kMaxMessageSize]; /* Can also be a binary message (e.g. MemoryRegionDetails) */
     char        stream[kMaxMessageSize]; /* Must be a string (strcpy is used) */
+    char        api_version[kMaxVersionSize]; /* Must be a string (strcpy is used) */
     std::string Json() {
         std::string s = "{\"id\":" + std::to_string(data_id) + ","
                         "\"buffer\":\"" + std::string(message) + "\"" + ","
@@ -81,7 +86,6 @@ struct GenericRequestHeader {
                         + "}";
         return s;
     };
-
 };
 
 
diff --git a/common/cpp/include/asapo/common/version.h.in b/common/cpp/include/asapo/common/version.h.in
deleted file mode 100644
index cfb735d837ece16c9a92c11dc09900390a1b4e3e..0000000000000000000000000000000000000000
--- a/common/cpp/include/asapo/common/version.h.in
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef ASAPO_VERSION_H
-#define ASAPO_VERSION_H
-
-#include <iostream>
-#include "string.h"
-
-namespace asapo {
-
-const char kVersion[] = "@ASAPO_VERSION@@ASAPO_VERSION_COMMIT@";
-
-inline void ExitAfterPrintVersionIfNeeded(std::string prefix,int argc, char* argv[]) {
-    if (argc == 2 && strcmp(argv[1], "-v") == 0) {
-        std::cout << prefix << ", version " << kVersion << std::endl;
-        exit(0);
-    }
-}
-
-}
-
-
-#endif //ASAPO_VERSION_H
diff --git a/common/cpp/src/version/CMakeLists.txt b/common/cpp/src/version/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..71abb5416d246fb255410e132556e4f43f5c5b7b
--- /dev/null
+++ b/common/cpp/src/version/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(TARGET_NAME version)
+set(SOURCE_FILES
+        version.cpp
+)
+
+################################
+# Library
+################################
+
+add_library(${TARGET_NAME} OBJECT ${SOURCE_FILES})
+target_include_directories(${TARGET_NAME} PUBLIC ${ASAPO_CXX_COMMON_INCLUDE_DIR}
+        ${CMAKE_SOURCE_DIR}/3d_party/rapidjson/include)
diff --git a/common/cpp/src/version/version.cpp b/common/cpp/src/version/version.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..57600be0ceb58b7e3515959b643194018d573310
--- /dev/null
+++ b/common/cpp/src/version/version.cpp
@@ -0,0 +1,28 @@
+#include "asapo/common/internal/version.h"
+#include "asapo/json_parser/json_parser.h"
+
+namespace asapo {
+
+Error ExtractVersionFromResponse(const std::string &response,
+                                 const std::string &client,
+                                 std::string* server_info,
+                                 bool* supported) {
+    JsonStringParser parser(response);
+    std::string server_version, current_client_protocol, client_supported;
+    Error err;
+    if ((err = parser.GetString("softwareVersion", &server_version))
+        || (err = parser.GetString("clientSupported", &client_supported))
+        || (err = parser.Embedded("clientProtocol").GetString("versionInfo", &current_client_protocol))) {
+        return err;
+    }
+    if (server_info) {
+        *server_info =
+            "Server version: " + server_version + ", " + client + " protocol on server: " + current_client_protocol;
+    }
+    if (supported) {
+        *supported = client_supported == "yes";
+    }
+    return nullptr;
+}
+
+}
\ No newline at end of file
diff --git a/common/go/src/asapo_common/utils/http.go b/common/go/src/asapo_common/utils/http.go
index 4e6f9736e6ff015ba66a5b56a6b32b9e3a1e4982..4a6ce7daef8084c202bebc439676e4fee071665b 100644
--- a/common/go/src/asapo_common/utils/http.go
+++ b/common/go/src/asapo_common/utils/http.go
@@ -10,7 +10,8 @@ func ExtractRequest(r *http.Request, request interface{}) error {
 	return decoder.Decode(request)
 }
 
-func WriteServerError(w http.ResponseWriter, err error,code int) {
+func WriteServerError(w http.ResponseWriter, err error, code int) {
 	w.WriteHeader(code)
 	w.Write([]byte(err.Error()))
-}
\ No newline at end of file
+}
+
diff --git a/common/go/src/asapo_common/utils/version.go b/common/go/src/asapo_common/utils/version.go
new file mode 100644
index 0000000000000000000000000000000000000000..5e8e03a9dff6ade41f5df8bf421d03bc2ff91987
--- /dev/null
+++ b/common/go/src/asapo_common/utils/version.go
@@ -0,0 +1,46 @@
+package utils
+
+import (
+	"errors"
+	"github.com/gorilla/mux"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+
+func VersionToNumber(ver string) int {
+	ver = strings.TrimPrefix(ver,"v")
+	floatNum, err := strconv.ParseFloat(ver, 64)
+	if err!=nil {
+		return 0
+	}
+	return int(floatNum*1000)
+}
+
+
+func ExtractVersion(r *http.Request) (int, error) {
+	vars := mux.Vars(r)
+	ver_str, ok := vars["apiver"]
+	if !ok {
+		return 0, errors.New("cannot extract version")
+	}
+	ver := VersionToNumber(ver_str)
+	if ver == 0 {
+		return 0, errors.New("cannot extract version")
+	}
+	return ver, nil
+}
+
+func PrecheckApiVersion(w http.ResponseWriter, r *http.Request, currentVersion string) (apiVer int, ok bool) {
+	apiVer, err := ExtractVersion(r)
+	if err != nil {
+		WriteServerError(w, err, http.StatusBadRequest)
+		return 0, false
+	}
+	if apiVer > VersionToNumber(currentVersion) {
+		WriteServerError(w, errors.New("version not supported"), http.StatusUnsupportedMediaType)
+		return 0, false
+	}
+	return apiVer, true
+}
diff --git a/common/go/src/asapo_common/version/version.go b/common/go/src/asapo_common/version/version.go
index d4674f37bddf4e84eaaec6cde2686ed6e68f306a..769bb508f97920842e834725840f056ff6342263 100644
--- a/common/go/src/asapo_common/version/version.go
+++ b/common/go/src/asapo_common/version/version.go
@@ -8,6 +8,35 @@ import (
 
 var version string
 
+var consumerProtocolVersion string
+var producerProtocolVersion string
+var discoveryApiVersion string
+var authorizerApiVersion string
+var ftsApiVersion string
+var brokerApiVersion string
+
+func GetDiscoveryApiVersion() string {
+	return discoveryApiVersion
+}
+func GetAuthorizerApiVersion() string {
+	return authorizerApiVersion
+}
+func GetFtsApiVersion() string {
+	return ftsApiVersion
+}
+func GetBrokerApiVersion() string {
+	return brokerApiVersion
+}
+
+func GetProducerProtocolVersion() string {
+	return producerProtocolVersion
+}
+
+func GetConsumerProtocolVersion() string {
+	return consumerProtocolVersion
+}
+
+
 func GetVersion() string {
     return version
 }
diff --git a/common/go/src/asapo_common/version/version_lib.go.in b/common/go/src/asapo_common/version/version_lib.go.in
index 5fc343fe161f109a008ddad671ee7ba3eabd14d1..a276d7babb1542811c6444c7c49c54de33e14474 100644
--- a/common/go/src/asapo_common/version/version_lib.go.in
+++ b/common/go/src/asapo_common/version/version_lib.go.in
@@ -4,4 +4,10 @@ package version
 // This file is overridden on build with build-time informations.
 func init(){
 	version   = "@ASAPO_VERSION@@ASAPO_VERSION_COMMIT@"
+	consumerProtocolVersion = "@ASAPO_CONSUMER_PROTOCOL@"
+    producerProtocolVersion = "@ASAPO_PRODUCER_PROTOCOL@"
+    discoveryApiVersion = "@ASAPO_DISCOVERY_API_VER@"
+    authorizerApiVersion = "@ASAPO_AUTHORIZER_API_VER@"
+    ftsApiVersion = "@ASAPO_FILE_TRANSFER_SERVICE_API_VER@"
+    brokerApiVersion = "@ASAPO_BROKER_API_VER@"
 }
diff --git a/config/nomad/discovery.nmd.in b/config/nomad/discovery.nmd.in
index 760aed3c700405ec289b47de69c0dd37c4ba4730..e3c36befc01f51fcbd7478342fe6fb6006d7b916 100644
--- a/config/nomad/discovery.nmd.in
+++ b/config/nomad/discovery.nmd.in
@@ -30,7 +30,7 @@ job "discovery" {
         check {
           name     = "alive"
           type     = "http"
-          path     = "/asapo-receiver"
+          path     = "/health"
           interval = "10s"
           timeout  = "2s"
           initial_status =   "passing"
diff --git a/consumer/api/cpp/CMakeLists.txt b/consumer/api/cpp/CMakeLists.txt
index 24661f0da20047c86732a811b657cf9f8d5e24ee..47d30a20f9a39dd6f83f070f39d6ac67e838fa68 100644
--- a/consumer/api/cpp/CMakeLists.txt
+++ b/consumer/api/cpp/CMakeLists.txt
@@ -12,7 +12,7 @@ set(SOURCE_FILES
 # Library
 ################################
 add_library(${TARGET_NAME} STATIC ${SOURCE_FILES} $<TARGET_OBJECTS:system_io>
-            $<TARGET_OBJECTS:json_parser> $<TARGET_OBJECTS:data_structs> $<TARGET_OBJECTS:curl_http_client> )
+            $<TARGET_OBJECTS:json_parser> $<TARGET_OBJECTS:data_structs> $<TARGET_OBJECTS:version>  $<TARGET_OBJECTS:curl_http_client> )
 
 target_include_directories(${TARGET_NAME} PUBLIC include ${ASAPO_CXX_COMMON_INCLUDE_DIR}  ${LIBFABRIC_INCLUDE_DIR} ${CURL_INCLUDE_DIRS})
 
diff --git a/consumer/api/cpp/include/asapo/asapo_consumer.h b/consumer/api/cpp/include/asapo/asapo_consumer.h
index e9dee4e9b5ebe0b003680e268eae48b32e91a32b..176d1d56269f35053b1fe8285a84352f6b72d487 100644
--- a/consumer/api/cpp/include/asapo/asapo_consumer.h
+++ b/consumer/api/cpp/include/asapo/asapo_consumer.h
@@ -3,7 +3,6 @@
 
 #include "asapo/consumer/consumer.h"
 #include "asapo/consumer/consumer_error.h"
-#include "asapo/common/version.h"
 #include <ostream>
 
 #endif //ASAPO_ASAPO_CONSUMER_H
diff --git a/consumer/api/cpp/include/asapo/consumer/consumer.h b/consumer/api/cpp/include/asapo/consumer/consumer.h
index 2cd1d71b678dcb22554489f9f9bf4428f970f64e..dba769567f4fec4dbd39de384f50f79205a024bc 100644
--- a/consumer/api/cpp/include/asapo/consumer/consumer.h
+++ b/consumer/api/cpp/include/asapo/consumer/consumer.h
@@ -27,6 +27,14 @@ class Consumer {
       \return nullptr of command was successful, otherwise error.
     */
     virtual Error ResetLastReadMarker(std::string group_id, std::string stream) = 0;
+  //! Return version
+  /*!
+    \param client_info - for client version
+    \param server_info - for server
+    \param supported - set to true if client is supported by server
+    \return nullptr of command was successful, otherwise error.
+  */
+    virtual Error GetVersionInfo(std::string* client_info,std::string* server_info, bool* supported) = 0;
 
     virtual Error SetLastReadMarker(std::string group_id, uint64_t value, std::string stream) = 0;
 
diff --git a/consumer/api/cpp/include/asapo/consumer/consumer_error.h b/consumer/api/cpp/include/asapo/consumer/consumer_error.h
index 7f3990d226fbcc3f663e367992496cc07e0fa3f7..38e5329d8f4aad6fdd98e25a85aae6d609c8cb04 100644
--- a/consumer/api/cpp/include/asapo/consumer/consumer_error.h
+++ b/consumer/api/cpp/include/asapo/consumer/consumer_error.h
@@ -14,7 +14,8 @@ enum class ConsumerErrorType {
     kInterruptedTransaction,
     kLocalIOError,
     kWrongInput,
-    kPartialData
+    kPartialData,
+    kUnsupportedClient
 };
 
 using ConsumerErrorTemplate = ServiceErrorTemplate<ConsumerErrorType, ErrorType::kConsumerError>;
@@ -63,6 +64,11 @@ auto const kWrongInput = ConsumerErrorTemplate {
     "wrong input", ConsumerErrorType::kWrongInput
 };
 
+auto const kUnsupportedClient = ConsumerErrorTemplate {
+    "unsupported client version", ConsumerErrorType::kUnsupportedClient
+};
+
+
 auto const kInterruptedTransaction = ConsumerErrorTemplate {
     "server error", ConsumerErrorType::kInterruptedTransaction
 };
diff --git a/consumer/api/cpp/src/consumer_impl.cpp b/consumer/api/cpp/src/consumer_impl.cpp
index 84a8fe6c9627970a204629e683ffdabbe2790e0a..7d3d565e5db6a80a6382e31b6c39adaf7d9f504c 100644
--- a/consumer/api/cpp/src/consumer_impl.cpp
+++ b/consumer/api/cpp/src/consumer_impl.cpp
@@ -12,6 +12,8 @@
 #include "fabric_consumer_client.h"
 #include "rds_response_error.h"
 
+#include "asapo/common/internal/version.h"
+
 using std::chrono::system_clock;
 
 namespace asapo {
@@ -32,7 +34,7 @@ Error GetNoDataResponseFromJson(const std::string &json_string, ConsumerErrorDat
 Error GetPartialDataResponseFromJson(const std::string &json_string, PartialErrorData* data) {
     Error err;
     auto parser = JsonStringParser(json_string);
-    uint64_t  id,size;
+    uint64_t id, size;
     if ((err = parser.GetUInt64("size", &size)) ||
         (err = parser.GetUInt64("_id", &id))) {
         return err;
@@ -84,6 +86,7 @@ Error ConsumerErrorFromHttpCode(const RequestOutput* response, const HttpCode &c
         case HttpCode::InternalServerError:return ConsumerErrorTemplates::kInterruptedTransaction.Generate(response->to_string());
         case HttpCode::NotFound:return ConsumerErrorTemplates::kUnavailableService.Generate(response->to_string());
         case HttpCode::Conflict:return ConsumerErrorFromNoDataResponse(response->to_string());
+        case HttpCode::UnsupportedMediaType:return ConsumerErrorTemplates::kUnsupportedClient.Generate(response->to_string());
         default:return ConsumerErrorTemplates::kInterruptedTransaction.Generate(response->to_string());
     }
 }
@@ -178,19 +181,20 @@ Error ConsumerImpl::ProcessRequest(RequestOutput* response, const RequestInfo &r
     return ProcessRequestResponce(err, response, code);
 }
 
-Error ConsumerImpl::DiscoverService(const std::string &service_name, std::string* uri_to_set) {
-    if (!uri_to_set->empty()) {
-        return nullptr;
-    }
+RequestInfo ConsumerImpl::GetDiscoveryRequest(const std::string &service_name) const {
     RequestInfo ri;
     ri.host = endpoint_;
-    ri.api = "/asapo-discovery/" + service_name;
-    RequestOutput output;
-    Error err;
-    err = ProcessRequest(&output, ri, nullptr);
-    *uri_to_set = std::move(output.string_output);
+    ri.api = "/asapo-discovery/" + kConsumerProtocol.GetDiscoveryVersion() + "/" + service_name;
+    ri.extra_params = "&protocol=" + kConsumerProtocol.GetVersion();
+    return ri;
+}
+
+Error ConsumerImpl::ProcessDiscoverServiceResult(Error err, std::string* uri_to_set) {
     if (err != nullptr || uri_to_set->empty()) {
         uri_to_set->clear();
+        if (err == ConsumerErrorTemplates::kUnsupportedClient) {
+            return err;
+        }
         return ConsumerErrorTemplates::kUnavailableService.Generate(" on " + endpoint_
                                                                         + (err != nullptr ? ": " + err->Explain()
                                                                                           : ""));
@@ -198,6 +202,17 @@ Error ConsumerImpl::DiscoverService(const std::string &service_name, std::string
     return nullptr;
 }
 
+Error ConsumerImpl::DiscoverService(const std::string &service_name, std::string* uri_to_set) {
+    if (!uri_to_set->empty()) {
+        return nullptr;
+    }
+    auto ri = GetDiscoveryRequest(service_name);
+    RequestOutput output;
+    auto err = ProcessRequest(&output, ri, nullptr);
+    *uri_to_set = std::move(output.string_output);
+    return ProcessDiscoverServiceResult(std::move(err), uri_to_set);
+}
+
 bool ConsumerImpl::SwitchToGetByIdIfPartialData(Error* err,
                                                 const std::string &response,
                                                 std::string* group_id,
@@ -215,7 +230,10 @@ bool ConsumerImpl::SwitchToGetByIdIfPartialData(Error* err,
     return false;
 }
 
-bool ConsumerImpl::SwitchToGetByIdIfNoData(Error* err, const std::string &response, std::string* group_id, std::string* redirect_uri) {
+bool ConsumerImpl::SwitchToGetByIdIfNoData(Error* err,
+                                           const std::string &response,
+                                           std::string* group_id,
+                                           std::string* redirect_uri) {
     if (*err == ConsumerErrorTemplates::kNoData) {
         auto error_data = static_cast<const ConsumerErrorData*>((*err)->GetCustomData());
         if (error_data == nullptr) {
@@ -235,7 +253,7 @@ RequestInfo ConsumerImpl::PrepareRequestInfo(std::string api_url, bool dataset,
     ri.api = std::move(api_url);
     if (dataset) {
         ri.extra_params = "&dataset=true";
-        ri.extra_params += "&minsize="+std::to_string(min_size);
+        ri.extra_params += "&minsize=" + std::to_string(min_size);
     }
     return ri;
 }
@@ -248,10 +266,12 @@ Error ConsumerImpl::GetRecordFromServer(std::string* response, std::string group
         return ConsumerErrorTemplates::kWrongInput.Generate("empty stream");
     }
 
-    interrupt_flag_= false;
+    interrupt_flag_ = false;
     std::string request_suffix = OpToUriCmd(op);
     std::string request_group = OpToUriCmd(op);
-    std::string request_api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source
+    std::string
+        request_api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/"
+        + source_credentials_.data_source
         + "/" + std::move(stream);
     uint64_t elapsed_ms = 0;
     Error no_data_error;
@@ -301,20 +321,20 @@ Error ConsumerImpl::GetRecordFromServer(std::string* response, std::string group
 
 Error ConsumerImpl::GetNext(std::string group_id, MessageMeta* info, MessageData* data, std::string stream) {
     return GetMessageFromServer(GetMessageServerOperation::GetNext,
-                              0,
-                              std::move(group_id),
-                              std::move(stream),
-                              info,
-                              data);
+                                0,
+                                std::move(group_id),
+                                std::move(stream),
+                                info,
+                                data);
 }
 
 Error ConsumerImpl::GetLast(MessageMeta* info, MessageData* data, std::string stream) {
     return GetMessageFromServer(GetMessageServerOperation::GetLast,
-                              0,
-                              "0",
-                              std::move(stream),
-                              info,
-                              data);
+                                0,
+                                "0",
+                                std::move(stream),
+                                info,
+                                data);
 }
 
 std::string ConsumerImpl::OpToUriCmd(GetMessageServerOperation op) {
@@ -326,9 +346,9 @@ std::string ConsumerImpl::OpToUriCmd(GetMessageServerOperation op) {
 }
 
 Error ConsumerImpl::GetMessageFromServer(GetMessageServerOperation op, uint64_t id, std::string group_id,
-                                       std::string stream,
-                                       MessageMeta* info,
-                                       MessageData* data) {
+                                         std::string stream,
+                                         MessageMeta* info,
+                                         MessageData* data) {
     if (info == nullptr) {
         return ConsumerErrorTemplates::kWrongInput.Generate();
     }
@@ -437,7 +457,7 @@ Error ConsumerImpl::TryGetDataFromBuffer(const MessageMeta* info, MessageData* d
 
 std::string ConsumerImpl::GenerateNewGroupId(Error* err) {
     RequestInfo ri;
-    ri.api = "/creategroup";
+    ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/creategroup";
     ri.post = true;
     return BrokerRequestWithTimeout(ri, err);
 }
@@ -446,7 +466,7 @@ Error ConsumerImpl::ServiceRequestWithTimeout(const std::string &service_name,
                                               std::string* service_uri,
                                               RequestInfo request,
                                               RequestOutput* response) {
-    interrupt_flag_= false;
+    interrupt_flag_ = false;
     uint64_t elapsed_ms = 0;
     Error err;
     while (elapsed_ms <= timeout_ms_) {
@@ -498,7 +518,7 @@ Error ConsumerImpl::FtsRequestWithTimeout(MessageMeta* info, MessageData* data)
 
 RequestInfo ConsumerImpl::CreateFileTransferRequest(const MessageMeta* info) const {
     RequestInfo ri;
-    ri.api = "/transfer";
+    ri.api = "/" + kConsumerProtocol.GetFileTransferServiceVersion() + "/transfer";
     ri.post = true;
     ri.body = "{\"Folder\":\"" + source_path_ + "\",\"FileName\":\"" + info->name + "\"}";
     ri.cookie = "Authorization=Bearer " + folder_token_;
@@ -518,7 +538,8 @@ Error ConsumerImpl::ResetLastReadMarker(std::string group_id, std::string stream
 
 Error ConsumerImpl::SetLastReadMarker(std::string group_id, uint64_t value, std::string stream) {
     RequestInfo ri;
-    ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + "/"
+    ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/"
+        + source_credentials_.data_source + "/"
         + std::move(stream) + "/" + std::move(group_id) + "/resetcounter";
     ri.extra_params = "&value=" + std::to_string(value);
     ri.post = true;
@@ -530,7 +551,7 @@ Error ConsumerImpl::SetLastReadMarker(std::string group_id, uint64_t value, std:
 
 uint64_t ConsumerImpl::GetCurrentSize(std::string stream, Error* err) {
     auto ri = GetSizeRequestForSingleMessagesStream(stream);
-    return GetCurrentCount(stream,ri,err);
+    return GetCurrentCount(stream, ri, err);
 }
 
 Error ConsumerImpl::GetById(uint64_t id, MessageMeta* info, MessageData* data, std::string stream) {
@@ -548,13 +569,14 @@ Error ConsumerImpl::GetRecordFromServerById(uint64_t id, std::string* response,
     }
 
     RequestInfo ri;
-    ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source +
+    ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/"
+        + source_credentials_.data_source +
         +"/" + std::move(stream) +
         "/" + std::move(
         group_id) + "/" + std::to_string(id);
     if (dataset) {
         ri.extra_params += "&dataset=true";
-        ri.extra_params += "&minsize="+std::to_string(min_size);
+        ri.extra_params += "&minsize=" + std::to_string(min_size);
     }
 
     Error err;
@@ -564,7 +586,9 @@ Error ConsumerImpl::GetRecordFromServerById(uint64_t id, std::string* response,
 
 std::string ConsumerImpl::GetBeamtimeMeta(Error* err) {
     RequestInfo ri;
-    ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + "/default/0/meta/0";
+    ri.api =
+        "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/"
+            + source_credentials_.data_source + "/default/0/meta/0";
 
     return BrokerRequestWithTimeout(ri, err);
 }
@@ -573,7 +597,7 @@ DataSet DecodeDatasetFromResponse(std::string response, Error* err) {
     DataSet res;
     if (!res.SetFromJson(std::move(response))) {
         *err = ConsumerErrorTemplates::kInterruptedTransaction.Generate("malformed response:" + response);
-        return {0,0,MessageMetas{}};
+        return {0, 0, MessageMetas{}};
     } else {
         return res;
     }
@@ -586,7 +610,8 @@ MessageMetas ConsumerImpl::QueryMessages(std::string query, std::string stream,
     }
 
     RequestInfo ri;
-    ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source +
+    ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/"
+        + source_credentials_.data_source +
         "/" + std::move(stream) + "/0/querymessages";
     ri.post = true;
     ri.body = std::move(query);
@@ -601,11 +626,16 @@ MessageMetas ConsumerImpl::QueryMessages(std::string query, std::string stream,
 }
 
 DataSet ConsumerImpl::GetNextDataset(std::string group_id, uint64_t min_size, std::string stream, Error* err) {
-    return GetDatasetFromServer(GetMessageServerOperation::GetNext, 0, std::move(group_id), std::move(stream),min_size, err);
+    return GetDatasetFromServer(GetMessageServerOperation::GetNext,
+                                0,
+                                std::move(group_id),
+                                std::move(stream),
+                                min_size,
+                                err);
 }
 
 DataSet ConsumerImpl::GetLastDataset(uint64_t min_size, std::string stream, Error* err) {
-    return GetDatasetFromServer(GetMessageServerOperation::GetLast, 0, "0", std::move(stream),min_size, err);
+    return GetDatasetFromServer(GetMessageServerOperation::GetLast, 0, "0", std::move(stream), min_size, err);
 }
 
 DataSet ConsumerImpl::GetDatasetFromServer(GetMessageServerOperation op,
@@ -620,15 +650,15 @@ DataSet ConsumerImpl::GetDatasetFromServer(GetMessageServerOperation op,
     } else {
         *err = GetRecordFromServer(&response, std::move(group_id), std::move(stream), op, true, min_size);
     }
-    if (*err != nullptr && *err!=ConsumerErrorTemplates::kPartialData) {
-        return {0, 0,MessageMetas{}};
+    if (*err != nullptr && *err != ConsumerErrorTemplates::kPartialData) {
+        return {0, 0, MessageMetas{}};
     }
     return DecodeDatasetFromResponse(response, err);
 }
 
 DataSet ConsumerImpl::GetDatasetById(uint64_t id, uint64_t min_size, std::string stream, Error* err) {
     if (id == 0) {
-        *err =  ConsumerErrorTemplates::kWrongInput.Generate("id should be positive");
+        *err = ConsumerErrorTemplates::kWrongInput.Generate("id should be positive");
         return {};
     }
     return GetDatasetFromServer(GetMessageServerOperation::GetID, id, "0", std::move(stream), min_size, err);
@@ -656,18 +686,14 @@ StreamInfos ParseStreamsFromResponse(std::string response, Error* err) {
 }
 
 std::string filterToString(StreamFilter filter) {
-    switch(filter) {
-        case StreamFilter::kAllStreams:
-            return "all";
-        case StreamFilter::kFinishedStreams:
-            return "finished";
-        case StreamFilter::kUnfinishedStreams:
-            return "unfinished";
+    switch (filter) {
+        case StreamFilter::kAllStreams:return "all";
+        case StreamFilter::kFinishedStreams:return "finished";
+        case StreamFilter::kUnfinishedStreams:return "unfinished";
     }
 }
 
-
-StreamInfos ConsumerImpl::GetStreamList(std::string from,StreamFilter filter, Error* err) {
+StreamInfos ConsumerImpl::GetStreamList(std::string from, StreamFilter filter, Error* err) {
     RequestInfo ri = GetStreamListRequest(from, filter);
 
     auto response = BrokerRequestWithTimeout(ri, err);
@@ -679,12 +705,13 @@ StreamInfos ConsumerImpl::GetStreamList(std::string from,StreamFilter filter, Er
 
 RequestInfo ConsumerImpl::GetStreamListRequest(const std::string &from, const StreamFilter &filter) const {
     RequestInfo ri;
-    ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source + "/0/streams";
+    ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/"
+        + source_credentials_.data_source + "/0/streams";
     ri.post = false;
     if (!from.empty()) {
         ri.extra_params = "&from=" + from;
     }
-    ri.extra_params +="&filter="+filterToString(filter);
+    ri.extra_params += "&filter=" + filterToString(filter);
     return ri;
 }
 
@@ -707,7 +734,7 @@ Error ConsumerImpl::UpdateFolderTokenIfNeeded(bool ignore_existing) {
 RequestInfo ConsumerImpl::CreateFolderTokenRequest() const {
     RequestInfo ri;
     ri.host = endpoint_;
-    ri.api = "/asapo-authorizer/folder";
+    ri.api = "/asapo-authorizer/" + kConsumerProtocol.GetAuthorizerVersion() + "/folder";
     ri.post = true;
     ri.body =
         "{\"Folder\":\"" + source_path_ + "\",\"BeamtimeId\":\"" + source_credentials_.beamtime_id + "\",\"Token\":\""
@@ -747,7 +774,8 @@ Error ConsumerImpl::Acknowledge(std::string group_id, uint64_t id, std::string s
         return ConsumerErrorTemplates::kWrongInput.Generate("empty stream");
     }
     RequestInfo ri;
-    ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source +
+    ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/"
+        + source_credentials_.data_source +
         +"/" + std::move(stream) +
         "/" + std::move(group_id) + "/" + std::to_string(id);
     ri.post = true;
@@ -768,7 +796,8 @@ IdList ConsumerImpl::GetUnacknowledgedMessages(std::string group_id,
         return {};
     }
     RequestInfo ri;
-    ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source +
+    ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/"
+        + source_credentials_.data_source +
         +"/" + std::move(stream) +
         "/" + std::move(group_id) + "/nacks";
     ri.extra_params = "&from=" + std::to_string(from_id) + "&to=" + std::to_string(to_id);
@@ -793,7 +822,8 @@ uint64_t ConsumerImpl::GetLastAcknowledgedMessage(std::string group_id, std::str
         return 0;
     }
     RequestInfo ri;
-    ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source +
+    ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/"
+        + source_credentials_.data_source +
         +"/" + std::move(stream) +
         "/" + std::move(group_id) + "/lastack";
 
@@ -828,7 +858,8 @@ Error ConsumerImpl::NegativeAcknowledge(std::string group_id,
         return ConsumerErrorTemplates::kWrongInput.Generate("empty stream");
     }
     RequestInfo ri;
-    ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source +
+    ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/"
+        + source_credentials_.data_source +
         +"/" + std::move(stream) +
         "/" + std::move(group_id) + "/" + std::to_string(id);
     ri.post = true;
@@ -839,21 +870,21 @@ Error ConsumerImpl::NegativeAcknowledge(std::string group_id,
     return err;
 }
 void ConsumerImpl::InterruptCurrentOperation() {
-    interrupt_flag_= true;
+    interrupt_flag_ = true;
 }
 
 uint64_t ConsumerImpl::GetCurrentDatasetCount(std::string stream, bool include_incomplete, Error* err) {
     RequestInfo ri = GetSizeRequestForDatasetStream(stream, include_incomplete);
-    return GetCurrentCount(stream,ri,err);
+    return GetCurrentCount(stream, ri, err);
 }
 
 RequestInfo ConsumerImpl::GetSizeRequestForDatasetStream(std::string &stream, bool include_incomplete) const {
     RequestInfo ri = GetSizeRequestForSingleMessagesStream(stream);
-    ri.extra_params = std::string("&incomplete=")+(include_incomplete?"true":"false");
+    ri.extra_params = std::string("&incomplete=") + (include_incomplete ? "true" : "false");
     return ri;
 }
 
-uint64_t ConsumerImpl::GetCurrentCount(std::string stream, const RequestInfo& ri, Error* err) {
+uint64_t ConsumerImpl::GetCurrentCount(std::string stream, const RequestInfo &ri, Error* err) {
     auto responce = BrokerRequestWithTimeout(ri, err);
     if (*err) {
         return 0;
@@ -872,9 +903,44 @@ uint64_t ConsumerImpl::ParseGetCurrentCountResponce(Error* err, const std::strin
 
 RequestInfo ConsumerImpl::GetSizeRequestForSingleMessagesStream(std::string &stream) const {
     RequestInfo ri;
-    ri.api = "/database/" + source_credentials_.beamtime_id + "/" + source_credentials_.data_source +
+    ri.api = "/" + kConsumerProtocol.GetBrokerVersion() + "/beamtime/" + source_credentials_.beamtime_id + "/"
+        + source_credentials_.data_source +
         +"/" + std::move(stream) + "/size";
     return ri;
 }
 
+RequestInfo ConsumerImpl::GetVersionRequest() const {
+    RequestInfo ri;
+    ri.host = endpoint_;
+    ri.api = "/asapo-discovery/" + kConsumerProtocol.GetDiscoveryVersion() + "/version";
+    ri.extra_params = "&client=consumer&protocol=" + kConsumerProtocol.GetVersion();
+    return ri;
 }
+
+Error ConsumerImpl::GetServerVersionInfo(std::string* server_info, bool* supported) {
+    auto ri = GetVersionRequest();
+    RequestOutput output;
+    auto err = ProcessRequest(&output, ri, nullptr);
+    if (err) {
+        return err;
+    }
+    return ExtractVersionFromResponse(output.string_output,"consumer",server_info,supported);
+}
+
+Error ConsumerImpl::GetVersionInfo(std::string* client_info, std::string* server_info, bool* supported) {
+    if (client_info == nullptr && server_info == nullptr && supported == nullptr) {
+        return ConsumerErrorTemplates::kWrongInput.Generate("missing parameters");
+    }
+    if (client_info != nullptr) {
+        *client_info =
+            "software version: " + std::string(kVersion) + ", consumer protocol: " + kConsumerProtocol.GetVersion();
+    }
+
+    if (server_info != nullptr || supported != nullptr) {
+        return GetServerVersionInfo(server_info,supported);
+    }
+
+    return nullptr;
+}
+
+}
\ No newline at end of file
diff --git a/consumer/api/cpp/src/consumer_impl.h b/consumer/api/cpp/src/consumer_impl.h
index 9628c810760c03a364677519473756bed77f3e8f..ef0ee3ac8679b32d415dee65442565e28da66558 100644
--- a/consumer/api/cpp/src/consumer_impl.h
+++ b/consumer/api/cpp/src/consumer_impl.h
@@ -84,6 +84,7 @@ class ConsumerImpl final : public asapo::Consumer {
 
     Error GetById(uint64_t id, MessageMeta* info, MessageData* data, std::string stream) override;
 
+    Error GetVersionInfo(std::string* client_info,std::string* server_info, bool* supported) override;
 
     void SetTimeout(uint64_t timeout_ms) override;
     void ForceNoRdma() override;
@@ -111,6 +112,7 @@ class ConsumerImpl final : public asapo::Consumer {
     std::unique_ptr<NetClient> net_client__;
     std::mutex net_client_mutex__; // Required for the lazy initialization of net_client
   private:
+    Error ProcessDiscoverServiceResult(Error err, std::string* uri_to_set);
     Error GetDataFromFileTransferService(MessageMeta* info, MessageData* data, bool retry_with_new_token);
     Error GetDataFromFile(MessageMeta* info, MessageData* data);
     static const std::string kBrokerServiceName;
@@ -145,6 +147,7 @@ class ConsumerImpl final : public asapo::Consumer {
 
     uint64_t GetCurrentCount(std::string stream, const RequestInfo& ri, Error* err);
     RequestInfo GetStreamListRequest(const std::string &from, const StreamFilter &filter) const;
+    Error GetServerVersionInfo(std::string* server_info, bool* supported) ;
 
     std::string endpoint_;
     std::string current_broker_uri_;
@@ -167,6 +170,9 @@ class ConsumerImpl final : public asapo::Consumer {
   RequestInfo GetSizeRequestForSingleMessagesStream(std::string &stream) const;
   RequestInfo GetSizeRequestForDatasetStream(std::string &stream, bool include_incomplete) const;
   uint64_t ParseGetCurrentCountResponce(Error* err, const std::string &responce) const;
+  RequestInfo GetDiscoveryRequest(const std::string &service_name) const;
+  RequestInfo GetVersionRequest() const;
+
 };
 
 }
diff --git a/consumer/api/cpp/src/fabric_consumer_client.cpp b/consumer/api/cpp/src/fabric_consumer_client.cpp
index 8c80895cb4a1048fb10cab4128677e58f7dbe6b8..774513e1f4d7dab3abce541dfa3e4b1261d46d5b 100644
--- a/consumer/api/cpp/src/fabric_consumer_client.cpp
+++ b/consumer/api/cpp/src/fabric_consumer_client.cpp
@@ -3,6 +3,7 @@
 #include <iostream>
 #include "fabric_consumer_client.h"
 #include "rds_response_error.h"
+#include "asapo/common/internal/version.h"
 
 using namespace asapo;
 
@@ -33,6 +34,7 @@ Error FabricConsumerClient::GetData(const MessageMeta* info, MessageData* data)
     }
 
     GenericRequestHeader request_header{kOpcodeGetBufferData, info->buf_id, info->size};
+    strncpy(request_header.api_version, kConsumerProtocol.GetRdsVersion().c_str(), kMaxVersionSize);
     memcpy(request_header.message, mr->GetDetails(), sizeof(fabric::MemoryRegionDetails));
     GenericNetworkResponse response{};
 
diff --git a/consumer/api/cpp/src/rds_response_error.h b/consumer/api/cpp/src/rds_response_error.h
index dfd5859a66ca8e10c2fcaac54e8d87e74bdc1639..8bc8d64c53d24138e10b17458e8af4311df08391 100644
--- a/consumer/api/cpp/src/rds_response_error.h
+++ b/consumer/api/cpp/src/rds_response_error.h
@@ -12,6 +12,11 @@ namespace RdsResponseErrorTemplates {
 auto const kNetErrorReauthorize = RdsResponseErrorTemplate {
     "RDS response Reauthorize", NetworkErrorCode::kNetErrorReauthorize
 };
+
+auto const kNetErrorNotSupported = RdsResponseErrorTemplate {
+    "RDS unsupported client", NetworkErrorCode::kNetErrorNotSupported
+};
+
 auto const kNetErrorWarning = RdsResponseErrorTemplate {
     "RDS response Warning", NetworkErrorCode::kNetErrorWarning
 };
@@ -33,6 +38,8 @@ inline Error ConvertRdsResponseToError(NetworkErrorCode error_code) {
     switch (error_code) {
     case kNetErrorNoError:
         return nullptr;
+    case kNetErrorNotSupported:
+        return RdsResponseErrorTemplates::kNetErrorNotSupported.Generate();
     case kNetErrorReauthorize:
         return RdsResponseErrorTemplates::kNetErrorReauthorize.Generate();
     case kNetErrorWarning:
diff --git a/consumer/api/cpp/src/tcp_consumer_client.cpp b/consumer/api/cpp/src/tcp_consumer_client.cpp
index a2bcc349cb90152409dfc3a68f808cfeed68a5dd..d58f05d6bb3213beeb39ec7e0a539ed181a68345 100644
--- a/consumer/api/cpp/src/tcp_consumer_client.cpp
+++ b/consumer/api/cpp/src/tcp_consumer_client.cpp
@@ -2,6 +2,7 @@
 #include "asapo/io/io_factory.h"
 #include "asapo/common/networking.h"
 #include "rds_response_error.h"
+#include "asapo/common/internal/version.h"
 
 namespace asapo {
 
@@ -13,6 +14,7 @@ TcpConsumerClient::TcpConsumerClient() : io__{GenerateDefaultIO()}, connection_p
 Error TcpConsumerClient::SendGetDataRequest(SocketDescriptor sd, const MessageMeta* info) const noexcept {
     Error err;
     GenericRequestHeader request_header{kOpcodeGetBufferData, info->buf_id, info->size};
+    strncpy(request_header.api_version, kConsumerProtocol.GetRdsVersion().c_str(), kMaxVersionSize);
     io__->Send(sd, &request_header, sizeof(request_header), &err);
     if (err) {
         connection_pool__->ReleaseConnection(sd);
@@ -43,6 +45,10 @@ Error TcpConsumerClient::ReceiveResponce(SocketDescriptor sd) const noexcept {
     }
     if (response.error_code) {
         switch (response.error_code) {
+        case kNetErrorNotSupported:
+                io__->CloseSocket(sd, nullptr);
+                connection_pool__->ReleaseConnection(sd);
+                break;
         case kNetErrorWrongRequest:
             io__->CloseSocket(sd, nullptr);
             break;
diff --git a/consumer/api/cpp/unittests/test_consumer_impl.cpp b/consumer/api/cpp/unittests/test_consumer_impl.cpp
index 813a2d65f4144c5c2dfdcf6e7cf04284f35bc916..6ad5448e5d336702803094aa454d40e4292e9555 100644
--- a/consumer/api/cpp/unittests/test_consumer_impl.cpp
+++ b/consumer/api/cpp/unittests/test_consumer_impl.cpp
@@ -14,6 +14,7 @@
 #include "asapo/http_client/http_error.h"
 #include "mocking.h"
 #include "../src/tcp_consumer_client.h"
+#include "asapo/common/internal/version.h"
 
 using asapo::ConsumerFactory;
 using asapo::Consumer;
@@ -66,6 +67,8 @@ class ConsumerImplTests : public Test {
   MessageMeta info;
   std::string expected_server_uri = "test:8400";
   std::string expected_broker_uri = "asapo-broker:5005";
+  std::string expected_consumer_protocol = "v0.1";
+  std::string expected_broker_api = expected_broker_uri + "/" + expected_consumer_protocol;
   std::string expected_fts_uri = "asapo-file-transfer:5008";
   std::string expected_token = "token";
   std::string expected_path = "/tmp/beamline/beamtime";
@@ -120,7 +123,7 @@ class ConsumerImplTests : public Test {
 
   }
   void MockGet(const std::string &response, asapo::HttpCode return_code = HttpCode::OK) {
-      EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_broker_uri), _, _)).WillOnce(DoAll(
+      EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_broker_api), _, _)).WillOnce(DoAll(
           SetArgPointee<1>(return_code),
           SetArgPointee<2>(nullptr),
           Return(response)
@@ -128,14 +131,15 @@ class ConsumerImplTests : public Test {
   }
 
   void MockGetError() {
-      EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_broker_uri), _, _)).WillOnce(DoAll(
+      EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_broker_api), _, _)).WillOnce(DoAll(
           SetArgPointee<1>(HttpCode::NotFound),
           SetArgPointee<2>(asapo::IOErrorTemplates::kUnknownIOError.Generate().release()),
           Return("")
       ));
   }
   void MockGetServiceUri(std::string service, std::string result) {
-      EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/" + service), _,
+      EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/" + service+"?token="
+          + expected_token+"&protocol=v0.1"), _,
                                           _)).WillOnce(DoAll(
           SetArgPointee<1>(HttpCode::OK),
           SetArgPointee<2>(nullptr),
@@ -200,7 +204,7 @@ TEST_F(ConsumerImplTests, DefaultStreamIsDetector) {
     MockGetBrokerUri();
 
     EXPECT_CALL(mock_http_client,
-                Get_t(expected_broker_uri + "/database/beamtime_id/detector/stream/" + expected_group_id
+                Get_t(expected_broker_api + "/beamtime/beamtime_id/detector/stream/" + expected_group_id
                           +
                               "/next?token="
                           + expected_token, _,
@@ -215,7 +219,7 @@ TEST_F(ConsumerImplTests, DefaultStreamIsDetector) {
 TEST_F(ConsumerImplTests, GetNextUsesCorrectUriWithStream) {
     MockGetBrokerUri();
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" +
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" +
                                             expected_stream + "/" + expected_group_id + "/next?token="
                                             + expected_token, _,
                                         _)).WillOnce(DoAll(
@@ -229,7 +233,7 @@ TEST_F(ConsumerImplTests, GetLastUsesCorrectUri) {
     MockGetBrokerUri();
 
     EXPECT_CALL(mock_http_client,
-                Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/"+ expected_stream+"/0/last?token="
+                Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/"+ expected_stream+"/0/last?token="
                           + expected_token, _,
                       _)).WillOnce(DoAll(
         SetArgPointee<1>(HttpCode::OK),
@@ -322,7 +326,7 @@ TEST_F(ConsumerImplTests, GetMessageReturnsWrongResponseFromHttpClient) {
 }
 
 TEST_F(ConsumerImplTests, GetMessageReturnsIfBrokerAddressNotFound) {
-    EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/asapo-broker"), _,
+    EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/asapo-broker"), _,
                                         _)).Times(AtLeast(2)).WillRepeatedly(DoAll(
         SetArgPointee<1>(HttpCode::NotFound),
         SetArgPointee<2>(nullptr),
@@ -334,8 +338,22 @@ TEST_F(ConsumerImplTests, GetMessageReturnsIfBrokerAddressNotFound) {
     ASSERT_THAT(err->Explain(), AllOf(HasSubstr(expected_server_uri), HasSubstr("unavailable")));
 }
 
+TEST_F(ConsumerImplTests, GetMessageReturnsUnsupportedClient) {
+    EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/asapo-broker"), _,
+                                        _)).Times(AtLeast(2)).WillRepeatedly(DoAll(
+        SetArgPointee<1>(HttpCode::UnsupportedMediaType),
+        SetArgPointee<2>(nullptr),
+        Return("")));
+
+    consumer->SetTimeout(100);
+    auto err = consumer->GetNext(expected_group_id, &info, nullptr, expected_stream);
+
+    ASSERT_THAT(err, Eq(asapo::ConsumerErrorTemplates::kUnsupportedClient));
+}
+
+
 TEST_F(ConsumerImplTests, GetMessageReturnsIfBrokerUriEmpty) {
-    EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/asapo-broker"), _,
+    EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/asapo-broker"), _,
                                         _)).Times(AtLeast(2)).WillRepeatedly(DoAll(
         SetArgPointee<1>(HttpCode::OK),
         SetArgPointee<2>(nullptr),
@@ -356,7 +374,7 @@ TEST_F(ConsumerImplTests, GetDoNotCallBrokerUriIfAlreadyFound) {
     Mock::VerifyAndClearExpectations(&mock_http_client);
 
     EXPECT_CALL(mock_http_client,
-                Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/asap-broker"), _, _)).Times(0);
+                Get_t(_, _, _)).Times(0);
     MockGet("error_response");
     consumer->GetNext(expected_group_id, &info, nullptr, expected_stream);
 }
@@ -398,7 +416,7 @@ TEST_F(ConsumerImplTests, GetMessageReturnsNoDataAfterTimeoutEvenIfOtherErrorOcc
         Return("{\"op\":\"get_record_by_id\",\"id\":" + std::to_string(expected_dataset_id) +
             ",\"id_max\":2,\"next_stream\":\"""\"}")));
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0/"
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0/"
                                             + std::to_string(expected_dataset_id) + "?token="
                                             + expected_token, _, _)).Times(AtLeast(1)).WillRepeatedly(DoAll(
         SetArgPointee<1>(HttpCode::NotFound),
@@ -431,7 +449,7 @@ ACTION(AssignArg2) {
 }
 
 TEST_F(ConsumerImplTests, GetNextRetriesIfConnectionHttpClientErrorUntilTimeout) {
-    EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/asapo-broker"), _,
+    EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/asapo-broker"), _,
                                         _)).Times(AtLeast(2)).WillRepeatedly(DoAll(
         SetArgPointee<1>(HttpCode::OK),
         SetArgPointee<2>(nullptr),
@@ -564,7 +582,7 @@ TEST_F(ConsumerImplTests, GenerateNewGroupIdReturnsErrorCreateGroup) {
 TEST_F(ConsumerImplTests, GenerateNewGroupIdReturnsGroupID) {
     MockGetBrokerUri();
 
-    EXPECT_CALL(mock_http_client, Post_t(expected_broker_uri + "/creategroup?token=" + expected_token, _, "", _,
+    EXPECT_CALL(mock_http_client, Post_t(expected_broker_api + "/creategroup?token=" + expected_token, _, "", _,
                                          _)).WillOnce(DoAll(
         SetArgPointee<3>(HttpCode::OK),
         SetArgPointee<4>(nullptr),
@@ -582,7 +600,7 @@ TEST_F(ConsumerImplTests, ResetCounterByDefaultUsesCorrectUri) {
     consumer->SetTimeout(100);
 
     EXPECT_CALL(mock_http_client,
-                Post_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/" +
+                Post_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/" +
                     expected_group_id +
                     "/resetcounter?token=" + expected_token + "&value=0", _, _, _, _)).WillOnce(DoAll(
         SetArgPointee<3>(HttpCode::OK),
@@ -596,7 +614,7 @@ TEST_F(ConsumerImplTests, ResetCounterUsesCorrectUri) {
     MockGetBrokerUri();
     consumer->SetTimeout(100);
 
-    EXPECT_CALL(mock_http_client, Post_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" +
+    EXPECT_CALL(mock_http_client, Post_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" +
         expected_stream + "/" +
         expected_group_id +
         "/resetcounter?token=" + expected_token + "&value=10", _, _, _, _)).WillOnce(DoAll(
@@ -611,7 +629,7 @@ TEST_F(ConsumerImplTests, GetCurrentSizeUsesCorrectUri) {
     MockGetBrokerUri();
     consumer->SetTimeout(100);
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" +
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" +
         expected_stream + "/size?token="
                                             + expected_token, _, _)).WillOnce(DoAll(
         SetArgPointee<1>(HttpCode::OK),
@@ -627,7 +645,7 @@ TEST_F(ConsumerImplTests, GetCurrentSizeErrorOnWrongResponce) {
     MockGetBrokerUri();
     consumer->SetTimeout(100);
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source +
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source +
         "/"+expected_stream+"/size?token="
                                             + expected_token, _, _)).WillRepeatedly(DoAll(
         SetArgPointee<1>(HttpCode::Unauthorized),
@@ -643,7 +661,7 @@ TEST_F(ConsumerImplTests, GetNDataErrorOnWrongParse) {
     MockGetBrokerUri();
     consumer->SetTimeout(100);
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source +
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source +
         "/stream/size?token="
                                             + expected_token, _, _)).WillOnce(DoAll(
         SetArgPointee<1>(HttpCode::OK),
@@ -661,7 +679,7 @@ TEST_F(ConsumerImplTests, GetByIdUsesCorrectUri) {
     auto to_send = CreateFI();
     auto json = to_send.Json();
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0/"
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0/"
                                             + std::to_string(
                                                 expected_dataset_id) + "?token="
                                             + expected_token, _,
@@ -680,7 +698,7 @@ TEST_F(ConsumerImplTests, GetByIdTimeouts) {
     MockGetBrokerUri();
     consumer->SetTimeout(10);
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0/"
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0/"
                                             + std::to_string(expected_dataset_id) + "?token="
                                             + expected_token, _, _)).WillOnce(DoAll(
         SetArgPointee<1>(HttpCode::Conflict),
@@ -696,7 +714,7 @@ TEST_F(ConsumerImplTests, GetByIdReturnsEndOfStream) {
     MockGetBrokerUri();
     consumer->SetTimeout(10);
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0/"
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0/"
                                             + std::to_string(expected_dataset_id) + "?token="
                                             + expected_token, _, _)).WillOnce(DoAll(
         SetArgPointee<1>(HttpCode::Conflict),
@@ -712,7 +730,7 @@ TEST_F(ConsumerImplTests, GetByIdReturnsEndOfStreamWhenIdTooLarge) {
     MockGetBrokerUri();
     consumer->SetTimeout(10);
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0/"
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0/"
                                             + std::to_string(expected_dataset_id) + "?token="
                                             + expected_token, _, _)).WillOnce(DoAll(
         SetArgPointee<1>(HttpCode::Conflict),
@@ -728,7 +746,7 @@ TEST_F(ConsumerImplTests, GetMetaDataOK) {
     MockGetBrokerUri();
     consumer->SetTimeout(100);
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source +
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source +
                                             "/default/0/meta/0?token="
                                             + expected_token, _,
                                         _)).WillOnce(DoAll(
@@ -834,7 +852,7 @@ TEST_F(ConsumerImplTests, QueryMessagesReturnRecords) {
     auto responce_string = "[" + json1 + "," + json2 + "]";
 
     EXPECT_CALL(mock_http_client,
-                Post_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0" +
+                Post_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0" +
                     "/querymessages?token=" + expected_token, _, expected_query_string, _, _)).WillOnce(DoAll(
         SetArgPointee<3>(HttpCode::OK),
         SetArgPointee<4>(nullptr),
@@ -854,7 +872,7 @@ TEST_F(ConsumerImplTests, QueryMessagesReturnRecords) {
 TEST_F(ConsumerImplTests, GetNextDatasetUsesCorrectUri) {
     MockGetBrokerUri();
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/" +
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/" +
                                             expected_group_id + "/next?token="
                                             + expected_token + "&dataset=true&minsize=0", _,
                                         _)).WillOnce(DoAll(
@@ -989,7 +1007,7 @@ TEST_F(ConsumerImplTests, GetDataSetReturnsParseError) {
 TEST_F(ConsumerImplTests, GetLastDatasetUsesCorrectUri) {
     MockGetBrokerUri();
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" +
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" +
                                             expected_stream + "/0/last?token="
                                             + expected_token + "&dataset=true&minsize=1", _,
                                         _)).WillOnce(DoAll(
@@ -1003,7 +1021,7 @@ TEST_F(ConsumerImplTests, GetLastDatasetUsesCorrectUri) {
 TEST_F(ConsumerImplTests, GetDatasetByIdUsesCorrectUri) {
     MockGetBrokerUri();
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/0/"
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/0/"
                                             + std::to_string(expected_dataset_id) + "?token="
                                             + expected_token + "&dataset=true" + "&minsize=0", _,
                                         _)).WillOnce(DoAll(
@@ -1020,7 +1038,7 @@ TEST_F(ConsumerImplTests, GetStreamListUsesCorrectUri) {
         std::string(R"({"streams":[{"lastId":123,"name":"test","timestampCreated":1000000,"timestampLast":1000,"finished":false,"nextStream":""},)")+
         R"({"lastId":124,"name":"test1","timestampCreated":2000000,"timestampLast":2000,"finished":true,"nextStream":"next"}]})";
     EXPECT_CALL(mock_http_client,
-                Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/0/streams"
+                Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/0/streams"
                           + "?token=" + expected_token + "&from=stream_from&filter=all", _,
                       _)).WillOnce(DoAll(
         SetArgPointee<1>(HttpCode::OK),
@@ -1039,7 +1057,7 @@ TEST_F(ConsumerImplTests, GetStreamListUsesCorrectUri) {
 TEST_F(ConsumerImplTests, GetStreamListUsesCorrectUriWithoutFrom) {
     MockGetBrokerUri();
     EXPECT_CALL(mock_http_client,
-                Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/0/streams"
+                Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/0/streams"
                           + "?token=" + expected_token+"&filter=finished", _,
                       _)).WillOnce(DoAll(
         SetArgPointee<1>(HttpCode::OK),
@@ -1064,7 +1082,7 @@ void ConsumerImplTests::ExpectFolderToken() {
         expected_beamtime_id
         + "\",\"Token\":\"" + expected_token + "\"}";
 
-    EXPECT_CALL(mock_http_client, Post_t(HasSubstr(expected_server_uri + "/asapo-authorizer/folder"), _,
+    EXPECT_CALL(mock_http_client, Post_t(HasSubstr(expected_server_uri + "/asapo-authorizer/v0.1/folder"), _,
                                          expected_folder_query_string, _, _)).WillOnce(DoAll(
         SetArgPointee<3>(HttpCode::OK),
         SetArgPointee<4>(nullptr),
@@ -1082,7 +1100,7 @@ ACTION_P(AssignArg3, assign) {
 }
 
 void ConsumerImplTests::ExpectFileTransfer(const asapo::ConsumerErrorTemplate* p_err_template) {
-    EXPECT_CALL(mock_http_client, PostReturnArray_t(HasSubstr(expected_fts_uri + "/transfer"),
+    EXPECT_CALL(mock_http_client, PostReturnArray_t(HasSubstr(expected_fts_uri + "/v0.1/transfer"),
                                                     expected_cookie,
                                                     expected_fts_query_string,
                                                     _,
@@ -1095,7 +1113,7 @@ void ConsumerImplTests::ExpectFileTransfer(const asapo::ConsumerErrorTemplate* p
 }
 
 void ConsumerImplTests::ExpectRepeatedFileTransfer() {
-    EXPECT_CALL(mock_http_client, PostReturnArray_t(HasSubstr(expected_fts_uri + "/transfer"),
+    EXPECT_CALL(mock_http_client, PostReturnArray_t(HasSubstr(expected_fts_uri + "/v0.1/transfer"),
                                                     expected_cookie,
                                                     expected_fts_query_string,
                                                     _,
@@ -1140,7 +1158,7 @@ TEST_F(ConsumerImplTests, FileTransferReadsFileSize) {
         Return("{\"file_size\":5}")
     ));
 
-    EXPECT_CALL(mock_http_client, PostReturnArray_t(HasSubstr(expected_fts_uri + "/transfer"),
+    EXPECT_CALL(mock_http_client, PostReturnArray_t(HasSubstr(expected_fts_uri + "/v0.1/transfer"),
                                                     expected_cookie,
                                                     expected_fts_query_string,
                                                     _,
@@ -1181,7 +1199,7 @@ TEST_F(ConsumerImplTests, GetMessageTriesToGetTokenAgainIfTransferFailed) {
 TEST_F(ConsumerImplTests, AcknowledgeUsesCorrectUri) {
     MockGetBrokerUri();
     auto expected_acknowledge_command = "{\"Op\":\"ackmessage\"}";
-    EXPECT_CALL(mock_http_client, Post_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" +
+    EXPECT_CALL(mock_http_client, Post_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" +
         expected_stream + "/" +
         expected_group_id
                                              + "/" + std::to_string(expected_dataset_id) + "?token="
@@ -1197,7 +1215,7 @@ TEST_F(ConsumerImplTests, AcknowledgeUsesCorrectUri) {
 
 void ConsumerImplTests::ExpectIdList(bool error) {
     MockGetBrokerUri();
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" +
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" +
         expected_stream + "/" +
         expected_group_id + "/nacks?token=" + expected_token + "&from=1&to=0", _, _)).WillOnce(DoAll(
         SetArgPointee<1>(HttpCode::OK),
@@ -1215,7 +1233,7 @@ TEST_F(ConsumerImplTests, GetUnAcknowledgedListReturnsIds) {
 }
 
 void ConsumerImplTests::ExpectLastAckId(bool empty_response) {
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" +
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" +
         expected_stream + "/" +
         expected_group_id + "/lastack?token=" + expected_token, _, _)).WillOnce(DoAll(
         SetArgPointee<1>(HttpCode::OK),
@@ -1253,7 +1271,7 @@ TEST_F(ConsumerImplTests, GetByIdErrorsForId0) {
 TEST_F(ConsumerImplTests, ResendNacks) {
     MockGetBrokerUri();
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/stream/"
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/stream/"
                                             + expected_group_id + "/next?token="
                                             + expected_token + "&resend_nacks=true&delay_ms=10000&resend_attempts=3", _,
                                         _)).WillOnce(DoAll(
@@ -1268,7 +1286,7 @@ TEST_F(ConsumerImplTests, ResendNacks) {
 TEST_F(ConsumerImplTests, NegativeAcknowledgeUsesCorrectUri) {
     MockGetBrokerUri();
     auto expected_neg_acknowledge_command = R"({"Op":"negackmessage","Params":{"DelayMs":10000}})";
-    EXPECT_CALL(mock_http_client, Post_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" +
+    EXPECT_CALL(mock_http_client, Post_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" +
         expected_stream + "/" +
         expected_group_id
                                              + "/" + std::to_string(expected_dataset_id) + "?token="
@@ -1313,7 +1331,7 @@ TEST_F(ConsumerImplTests, GetCurrentDataSetCounteUsesCorrectUri) {
     MockGetBrokerUri();
     consumer->SetTimeout(100);
 
-    EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/" + expected_data_source + "/" +
+    EXPECT_CALL(mock_http_client, Get_t(expected_broker_api + "/beamtime/beamtime_id/" + expected_data_source + "/" +
         expected_stream + "/size?token="
                                             + expected_token+"&incomplete=true", _, _)).WillOnce(DoAll(
         SetArgPointee<1>(HttpCode::OK),
@@ -1325,4 +1343,30 @@ TEST_F(ConsumerImplTests, GetCurrentDataSetCounteUsesCorrectUri) {
     ASSERT_THAT(size, Eq(10));
 }
 
+
+TEST_F(ConsumerImplTests, GetVersionInfoClientOnly) {
+    std::string client_info;
+    auto err = consumer->GetVersionInfo(&client_info,nullptr,nullptr);
+    ASSERT_THAT(err, Eq(nullptr));
+    ASSERT_THAT(client_info, HasSubstr(std::string(asapo::kVersion)));
+    ASSERT_THAT(client_info, HasSubstr(asapo::kConsumerProtocol.GetVersion()));
+}
+
+TEST_F(ConsumerImplTests, GetVersionInfoWithServer) {
+
+    std::string result = R"({"softwareVersion":"20.03.1, build 7a9294ad","clientSupported":"no", "clientProtocol":{"versionInfo":"v0.2"}})";
+
+    EXPECT_CALL(mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/version?token=token&client=consumer&protocol=v0.1"), _,_)).WillOnce(DoAll(
+        SetArgPointee<1>(HttpCode::OK),
+        SetArgPointee<2>(nullptr),
+        Return(result)));
+
+    std::string client_info,server_info;
+    auto err = consumer->GetVersionInfo(&client_info,&server_info,nullptr);
+    ASSERT_THAT(err, Eq(nullptr));
+    ASSERT_THAT(server_info, HasSubstr("20.03.1"));
+    ASSERT_THAT(server_info, HasSubstr("v0.2"));
+}
+
+
 }
diff --git a/consumer/api/cpp/unittests/test_fabric_consumer_client.cpp b/consumer/api/cpp/unittests/test_fabric_consumer_client.cpp
index 9e32cd3842cc11d96003b342ade885a0d8d7e8a7..dcbd311e16fef382fa1f1d710eab1041912ddf78 100644
--- a/consumer/api/cpp/unittests/test_fabric_consumer_client.cpp
+++ b/consumer/api/cpp/unittests/test_fabric_consumer_client.cpp
@@ -33,6 +33,7 @@ MATCHER_P6(M_CheckSendRequest, op_code, buf_id, data_size, mr_addr, mr_length, m
            && data->data_id == uint64_t(buf_id)
            && data->data_size == uint64_t(data_size)
            && mr->addr == uint64_t(mr_addr)
+           && strcmp(data->api_version, "v0.1") == 0
            && mr->length == uint64_t(mr_length)
            && mr->key == uint64_t(mr_key);
 }
diff --git a/consumer/api/cpp/unittests/test_rds_error_mapper.cpp b/consumer/api/cpp/unittests/test_rds_error_mapper.cpp
index f19dc56022525914a17fe0b04fee1340571c4216..c5161d0ee8fc35c46d549a968059e7c7ee64aba1 100644
--- a/consumer/api/cpp/unittests/test_rds_error_mapper.cpp
+++ b/consumer/api/cpp/unittests/test_rds_error_mapper.cpp
@@ -19,4 +19,6 @@ TEST(ConvertRdsResponseToError, TestAllCases) {
                 Eq(RdsResponseErrorTemplates::kNetAuthorizationError));
     ASSERT_THAT(ConvertRdsResponseToError(NetworkErrorCode::kNetErrorInternalServerError),
                 Eq(RdsResponseErrorTemplates::kNetErrorInternalServerError));
+    ASSERT_THAT(ConvertRdsResponseToError(NetworkErrorCode::kNetErrorNotSupported),
+                Eq(RdsResponseErrorTemplates::kNetErrorNotSupported));
 }
diff --git a/consumer/api/cpp/unittests/test_tcp_consumer_client.cpp b/consumer/api/cpp/unittests/test_tcp_consumer_client.cpp
index b1df9c9db1e6bd84ae1c21aba9968e0bc7c82a36..ebf4102b3aa4931b9efd884a83acf134e3168b8e 100644
--- a/consumer/api/cpp/unittests/test_tcp_consumer_client.cpp
+++ b/consumer/api/cpp/unittests/test_tcp_consumer_client.cpp
@@ -44,6 +44,7 @@ MATCHER_P4(M_CheckSendRequest, op_code, buf_id, data_size, message,
     return ((asapo::GenericRequestHeader*) arg)->op_code == op_code
            && ((asapo::GenericRequestHeader*) arg)->data_id == uint64_t(buf_id)
            && ((asapo::GenericRequestHeader*) arg)->data_size == uint64_t(data_size)
+           && strcmp(((asapo::GenericRequestHeader*) arg)->api_version, "v0.1") == 0
            && strcmp(((asapo::GenericRequestHeader*) arg)->message, message) == 0;
 }
 
@@ -212,6 +213,19 @@ TEST_F(TcpClientTests, GetResponceReturnsWrongRequest) {
     ASSERT_THAT(err, Ne(nullptr));
 }
 
+TEST_F(TcpClientTests, GetResponceReturnsUnsupported) {
+    ExpectNewConnection(false, true);
+    ExpectSendRequest(expected_sd, true);
+    ExpectGetResponce(expected_sd, true, asapo::kNetErrorNotSupported);
+    EXPECT_CALL(mock_io, CloseSocket_t(expected_sd, _));
+    EXPECT_CALL(mock_connection_pool, ReleaseConnection(expected_sd));
+
+    auto err = client->GetData(&info, &data);
+
+    ASSERT_THAT(err, Ne(nullptr));
+}
+
+
 TEST_F(TcpClientTests, ErrorGettingData) {
     ExpectNewConnection(false, true);
     ExpectSendRequest(expected_sd, true);
diff --git a/consumer/api/python/asapo_consumer.pxd b/consumer/api/python/asapo_consumer.pxd
index f0c9fa99c9dc5885b8bee77d9227d89db15d4724..fa755a375a83d05f4469cb4fad4030ea0130caf2 100644
--- a/consumer/api/python/asapo_consumer.pxd
+++ b/consumer/api/python/asapo_consumer.pxd
@@ -87,6 +87,7 @@ cdef extern from "asapo/asapo_consumer.h" namespace "asapo" nogil:
         vector[StreamInfo] GetStreamList(string from_stream, StreamFilter filter, Error* err)
         void SetResendNacs(bool resend, uint64_t delay_ms, uint64_t resend_attempts)
         void InterruptCurrentOperation()
+        Error GetVersionInfo(string* client_info,string* server_info, bool* supported)
 
 cdef extern from "asapo/asapo_consumer.h" namespace "asapo" nogil:
     cdef cppclass ConsumerFactory:
@@ -103,6 +104,8 @@ cdef extern from "asapo/asapo_consumer.h" namespace "asapo":
   ErrorTemplateInterface kLocalIOError "asapo::ConsumerErrorTemplates::kLocalIOError"
   ErrorTemplateInterface kWrongInput "asapo::ConsumerErrorTemplates::kWrongInput"
   ErrorTemplateInterface kPartialData "asapo::ConsumerErrorTemplates::kPartialData"
+  ErrorTemplateInterface kUnsupportedClient "asapo::ConsumerErrorTemplates::kUnsupportedClient"
+
 
   cdef cppclass ConsumerErrorData:
     uint64_t id
diff --git a/consumer/api/python/asapo_consumer.pyx.in b/consumer/api/python/asapo_consumer.pyx.in
index 88d5be838750d5e531875823885e41a3da7369c9..1db15ed4a72531c1bb9403c632a4ea9231f4da58 100644
--- a/consumer/api/python/asapo_consumer.pyx.in
+++ b/consumer/api/python/asapo_consumer.pyx.in
@@ -46,6 +46,9 @@ class AsapoUnavailableServiceError(AsapoConsumerError):
 class AsapoLocalIOError(AsapoConsumerError):
   pass
 
+class AsapoUnsupportedClientError(AsapoConsumerError):
+  pass
+
 class AsapoStreamFinishedError(AsapoConsumerError):
   def __init__(self,message,id_max=None,next_stream=None):
     AsapoConsumerError.__init__(self,message)
@@ -99,6 +102,8 @@ cdef throw_exception(Error& err, res = None):
             raise AsapoUnavailableServiceError(error_string)
     elif err == kInterruptedTransaction:
             raise AsapoInterruptedTransactionError(error_string)
+    elif err == kUnsupportedClient:
+            raise AsapoUnsupportedClientError(error_string)
     else:
         raise AsapoConsumerError(error_string)
 
@@ -211,6 +216,21 @@ cdef class PyConsumer:
         if err:
             throw_exception(err)
         return
+    def get_version_info(self, from_server = "true"):
+        cdef string client_info,server_info
+        cdef bool supported
+        cdef string* p_server_info =  &server_info if from_server else <string*>NULL
+        cdef bool* p_supported =  &supported if from_server else <bool*>NULL
+        cdef Error err
+        with nogil:
+                err =  self.c_consumer.get().GetVersionInfo(&client_info,p_server_info,p_supported)
+        if err:
+            throw_exception(err)
+        version = {}
+        if from_server:
+            return {'client': _str(client_info), 'server': _str(server_info), 'supported': supported}
+        else:
+            return {'client': _str(client_info)}
     def reset_lastread_marker(self,group_id, stream = "default"):
         cdef string b_group_id = _bytes(group_id)
         cdef string b_stream = _bytes(stream)
diff --git a/deploy/asapo_helm_chart/asapo/configs/asapo-broker.json b/deploy/asapo_helm_chart/asapo/configs/asapo-broker.json
index 00325d3e1b8a514c42ad8a72acc816ea52a6e909..196b79c99019f1fdb86eafdd6573ac7a6ae894bf 100644
--- a/deploy/asapo_helm_chart/asapo/configs/asapo-broker.json
+++ b/deploy/asapo_helm_chart/asapo/configs/asapo-broker.json
@@ -3,6 +3,7 @@
   "DiscoveryServer": "asapo-discovery:{{ .Values.ownServices.discovery.port }}",
   "AuthorizationServer": "asapo-authorizer:{{ .Values.ownServices.authorization.port }}",
   "PerformanceDbServer":"{{ .Chart.Name }}-influxdb:{{ .Values.influxdb.influxdb.service.port }}",
+  "MonitorPerformance": true,
   "PerformanceDbName": "asapo_brokers",
   "Port": {{ .Values.ownServices.broker.port }},
   "CheckResendInterval":10,
diff --git a/deploy/asapo_helm_chart/asapo/configs/asapo-receiver.json b/deploy/asapo_helm_chart/asapo/configs/asapo-receiver.json
index c034223fc2a8c0082d924ab5ba5db797f2dfc037..6dde5c8adc0a08182691d7158e067bff336f8815 100644
--- a/deploy/asapo_helm_chart/asapo/configs/asapo-receiver.json
+++ b/deploy/asapo_helm_chart/asapo/configs/asapo-receiver.json
@@ -1,5 +1,6 @@
 {
   "PerformanceDbServer": "{{ .Chart.Name }}-influxdb:{{ .Values.influxdb.influxdb.service.port }}",
+  "MonitorPerformance": true,
   "PerformanceDbName": "asapo_receivers",
   "DatabaseServer": "asapo-mongodb:{{ .Values.ownServices.mongodb.port }}",
   "DiscoveryServer": "asapo-discovery:{{ .Values.ownServices.discovery.port }}",
diff --git a/deploy/asapo_services/scripts/asapo-brokers.nmd.tpl b/deploy/asapo_services/scripts/asapo-brokers.nmd.tpl
index e96dc1a954aacfdc6ecef2a325926544e171b151..14f5eaf5baf9587059c4b644d3dbfea8a29eb137 100644
--- a/deploy/asapo_services/scripts/asapo-brokers.nmd.tpl
+++ b/deploy/asapo_services/scripts/asapo-brokers.nmd.tpl
@@ -30,7 +30,7 @@ job "asapo-brokers" {
 	    security_opt = ["no-new-privileges"]
 	    userns_mode = "host"
         image = "yakser/asapo-broker${image_suffix}"
-	    force_pull = true
+	    force_pull = ${force_pull_images}
         volumes = ["local/config.json:/var/lib/broker/config.json"]
         %{ if ! nomad_logs  }
           logging {
@@ -67,6 +67,10 @@ job "asapo-brokers" {
         }
       }
 
+      meta {
+        perf_monitor = "${perf_monitor}"
+      }
+
       template {
          source        = "${scripts_dir}/broker.json.tpl"
          destination   = "local/config.json"
diff --git a/deploy/asapo_services/scripts/asapo-fts.nmd.tpl b/deploy/asapo_services/scripts/asapo-fts.nmd.tpl
index 055d567c0da050d0898ca58f72164b7b30065048..5f4d98278ccb419e54ce9465895e47ea22c92bbb 100644
--- a/deploy/asapo_services/scripts/asapo-fts.nmd.tpl
+++ b/deploy/asapo_services/scripts/asapo-fts.nmd.tpl
@@ -30,7 +30,7 @@ job "asapo-file-transfer" {
 	    security_opt = ["no-new-privileges"]
 	    userns_mode = "host"
         image = "yakser/asapo-file-transfer${image_suffix}"
-	    force_pull = true
+	    force_pull = ${force_pull_images}
         volumes = ["local/config.json:/var/lib/file_transfer/config.json",
                            "${offline_dir}:${offline_dir}",
                            "${online_dir}:${online_dir}"
diff --git a/deploy/asapo_services/scripts/asapo-perfmetrics.nmd.tpl b/deploy/asapo_services/scripts/asapo-perfmetrics.nmd.tpl
index 6033581d872d53ae108a892f0754c5bff98b901a..cd717baff86ea82bd6bf5b54719d827caa3aacfa 100644
--- a/deploy/asapo_services/scripts/asapo-perfmetrics.nmd.tpl
+++ b/deploy/asapo_services/scripts/asapo-perfmetrics.nmd.tpl
@@ -14,7 +14,7 @@ job "asapo-perfmetrics" {
 #  }
 
   group "perfmetrics" {
-    count = 1
+    count = "%{ if perf_monitor }1%{ else }0%{ endif }"
     restart {
       attempts = 2
       interval = "3m"
@@ -30,11 +30,13 @@ job "asapo-perfmetrics" {
 	    security_opt = ["no-new-privileges"]
 	    userns_mode = "host"
         image = "influxdb:${influxdb_version}"
-        volumes = ["/${service_dir}/influxdb:/var/lib/influxdb"]
+        volumes = ["/${service_dir}/influxdb2:/var/lib/influxdb2"]
       }
 
       env {
         PRE_CREATE_DB="asapo_receivers;asapo_brokers"
+        INFLUXDB_BIND_ADDRESS="127.0.0.1:$${NOMAD_PORT_influxdb_rpc}"
+        INFLUXDB_HTTP_BIND_ADDRESS=":$${NOMAD_PORT_influxdb}"
       }
 
       resources {
@@ -43,6 +45,9 @@ job "asapo-perfmetrics" {
           port "influxdb" {
           static = "${influxdb_port}"
           }
+          port "influxdb_rpc" {
+          static = "${influxdb_rpc_port}"
+          }
         }
       }
 
@@ -72,6 +77,7 @@ job "asapo-perfmetrics" {
       env {
         GF_SERVER_DOMAIN = "$${attr.unique.hostname}"
         GF_SERVER_ROOT_URL = "%(protocol)s://%(domain)s/performance/"
+        GF_SERVER_HTTP_PORT = "${grafana_port}"
       }
 
       config {
diff --git a/deploy/asapo_services/scripts/asapo-receivers.nmd.tpl b/deploy/asapo_services/scripts/asapo-receivers.nmd.tpl
index 075100884089b185c4695d7f7c063763fda1776c..2096021f5cc99da4edcfbecafaf5c4a2343855d3 100644
--- a/deploy/asapo_services/scripts/asapo-receivers.nmd.tpl
+++ b/deploy/asapo_services/scripts/asapo-receivers.nmd.tpl
@@ -35,7 +35,7 @@ job "asapo-receivers" {
 	    userns_mode = "host"
 	    privileged = true
         image = "yakser/asapo-receiver${image_suffix}"
-	    force_pull = true
+	    force_pull = ${force_pull_images}
         volumes = ["local/config.json:/var/lib/receiver/config.json",
                    "${offline_dir}:${offline_dir}",
                    "${online_dir}:${online_dir}"]
@@ -84,6 +84,7 @@ job "asapo-receivers" {
         receiver_dataserver_nthreads = "${receiver_dataserver_nthreads}"
         receiver_receive_to_disk_threshold = "${receiver_receive_to_disk_threshold}"
         receiver_network_modes = "${receiver_network_modes}"
+        perf_monitor = "${perf_monitor}"
       }
 
       template {
diff --git a/deploy/asapo_services/scripts/asapo-services.nmd.tpl b/deploy/asapo_services/scripts/asapo-services.nmd.tpl
index 6220ae11d82341f7b997f0b11aa872908f5bbfe1..9cb6298aa08ab6edf9b2f3897c21ead5a7dd9514 100644
--- a/deploy/asapo_services/scripts/asapo-services.nmd.tpl
+++ b/deploy/asapo_services/scripts/asapo-services.nmd.tpl
@@ -19,7 +19,7 @@ job "asapo-services" {
 	    security_opt = ["no-new-privileges"]
 	    userns_mode = "host"
         image = "yakser/asapo-authorizer${image_suffix}"
-	force_pull = true
+	    force_pull = ${force_pull_images}
         volumes = ["local/config.json:/var/lib/authorizer/config.json",
                            "${offline_dir}:${offline_dir}",
                            "${online_dir}:${online_dir}"]
@@ -96,7 +96,7 @@ job "asapo-services" {
 	    security_opt = ["no-new-privileges"]
 	    userns_mode = "host"
         image = "yakser/asapo-discovery${image_suffix}"
-	    force_pull = true
+	    force_pull = ${force_pull_images}
         volumes = ["local/config.json:/var/lib/discovery/config.json"]
         %{ if ! nomad_logs  }
         logging {
@@ -125,7 +125,7 @@ job "asapo-services" {
         check {
           name     = "alive"
           type     = "http"
-          path     = "/asapo-receiver"
+          path     = "/health"
           interval = "10s"
           timeout  = "2s"
           initial_status =   "passing"
diff --git a/deploy/asapo_services/scripts/asapo.auto.tfvars.in b/deploy/asapo_services/scripts/asapo.auto.tfvars.in
index 2212ce1f349579fc874591fbf5884a5db746269b..764b672753af79dcad8aebf46aa1205e6672a9f9 100644
--- a/deploy/asapo_services/scripts/asapo.auto.tfvars.in
+++ b/deploy/asapo_services/scripts/asapo.auto.tfvars.in
@@ -6,10 +6,12 @@ nginx_version = "1.14"
 elasticsearch_version = "7.3.2"
 kibana_version = "7.3.2"
 mongo_version = "4.0.0"
-grafana_version="latest"
-influxdb_version = "latest"
-elk_logs = true
+grafana_version="7.5.0"
+influxdb_version = "2.0.4"
+elk_logs = false
+perf_monitor = false
 nomad_logs = false
+force_pull_images = false
 
 job_scripts_dir = "/var/run/asapo"
 
@@ -32,8 +34,9 @@ authorizer_total_memory_size = 256
 discovery_total_memory_size = 256
 
 
-grafana_port = 3000
+grafana_port = 3301
 influxdb_port = 8086
+influxdb_rpc_port = 8088
 mongo_port = 27017
 fluentd_port = 9880
 fluentd_port_stream = 24224
diff --git a/deploy/asapo_services/scripts/broker.json.tpl b/deploy/asapo_services/scripts/broker.json.tpl
index bbd97f4218f30116f62aaab2ee94088f65b6a8e8..493c986e427c76ff9c226d931055ad6f5e398563 100644
--- a/deploy/asapo_services/scripts/broker.json.tpl
+++ b/deploy/asapo_services/scripts/broker.json.tpl
@@ -3,6 +3,7 @@
   "DiscoveryServer": "localhost:8400/asapo-discovery",
   "AuthorizationServer": "localhost:8400/asapo-authorizer",
   "PerformanceDbServer":"localhost:8400/influxdb",
+  "MonitorPerformance": {{ env "NOMAD_META_perf_monitor" }},
   "CheckResendInterval":10,
   "PerformanceDbName": "asapo_brokers",
   "Port":{{ env "NOMAD_PORT_broker" }},
diff --git a/deploy/asapo_services/scripts/receiver.json.tpl b/deploy/asapo_services/scripts/receiver.json.tpl
index c4f0d33b20cf255c005650b9d849e9ebd2562f3f..e5214deed638118fac712fe6dced5bf56ebaf790 100644
--- a/deploy/asapo_services/scripts/receiver.json.tpl
+++ b/deploy/asapo_services/scripts/receiver.json.tpl
@@ -1,5 +1,6 @@
 {
   "PerformanceDbServer":"localhost:8400/influxdb",
+  "MonitorPerformance": {{ env "NOMAD_META_perf_monitor" }},
   "PerformanceDbName": "asapo_receivers",
   "DatabaseServer":"auto",
   "DiscoveryServer": "localhost:8400/asapo-discovery",
diff --git a/deploy/asapo_services/scripts/resources.tf b/deploy/asapo_services/scripts/resources.tf
index 1539150f6436c3920ebe58520fb05637882b205a..869b4664f4cde62fbd8495ea5aa42c00ed8b3378 100644
--- a/deploy/asapo_services/scripts/resources.tf
+++ b/deploy/asapo_services/scripts/resources.tf
@@ -1,37 +1,37 @@
 resource "nomad_job" "asapo-nginx" {
-  jobspec = "${data.template_file.nginx.rendered}"
+  jobspec = data.template_file.nginx.rendered
 }
 
 resource "nomad_job" "asapo-mongo" {
-  jobspec = "${data.template_file.asapo_mongo.rendered}"
+  jobspec = data.template_file.asapo_mongo.rendered
 }
 
 resource "nomad_job" "asapo-perfmetrics" {
-  jobspec = "${data.template_file.asapo_perfmetrics.rendered}"
+  jobspec = data.template_file.asapo_perfmetrics.rendered
 }
 
 resource "nomad_job" "asapo-logging" {
-  jobspec = "${data.template_file.asapo_logging.rendered}"
+  jobspec = data.template_file.asapo_logging.rendered
   depends_on = [null_resource.nginx]
 }
 
 resource "nomad_job" "asapo-services" {
-  jobspec = "${data.template_file.asapo_services.rendered}"
+  jobspec = data.template_file.asapo_services.rendered
   depends_on = [null_resource.nginx,null_resource.mongo,null_resource.influxdb,null_resource.fluentd,null_resource.elasticsearch]
 }
 
 resource "nomad_job" "asapo-receivers" {
-  jobspec = "${data.template_file.asapo_receivers.rendered}"
+  jobspec = data.template_file.asapo_receivers.rendered
   depends_on = [nomad_job.asapo-services,null_resource.asapo-authorizer,null_resource.asapo-discovery]
 }
 
 resource "nomad_job" "asapo-brokers" {
-  jobspec = "${data.template_file.asapo_brokers.rendered}"
+  jobspec = data.template_file.asapo_brokers.rendered
   depends_on = [nomad_job.asapo-services,null_resource.asapo-authorizer,null_resource.asapo-discovery]
 }
 
 resource "nomad_job" "asapo-fts" {
-  jobspec = "${data.template_file.asapo_fts.rendered}"
+  jobspec = data.template_file.asapo_fts.rendered
   depends_on = [nomad_job.asapo-services,null_resource.asapo-authorizer,null_resource.asapo-discovery]
 }
 
diff --git a/deploy/asapo_services/scripts/resources_services.tf b/deploy/asapo_services/scripts/resources_services.tf
index fa84a79b18e64e5a4a1431b9c8589f08330d2e02..e3cff85810efb48af3bc90347c5e20010204df6b 100644
--- a/deploy/asapo_services/scripts/resources_services.tf
+++ b/deploy/asapo_services/scripts/resources_services.tf
@@ -8,7 +8,7 @@ resource "null_resource" "nginx" {
 
 resource "null_resource" "influxdb" {
   provisioner "local-exec" {
-    command = "asapo-wait-service influxdb"
+    command = "asapo-wait-service influxdb ${var.perf_monitor}"
   }
   depends_on = [nomad_job.asapo-perfmetrics]
 }
diff --git a/deploy/asapo_services/scripts/templates.tf b/deploy/asapo_services/scripts/templates.tf
index 90f6b71ec4bc3f5cb5c6e66e376e57783aaa50a3..e5dae73a5b2e39f2550df7de744e1142ed60d962 100644
--- a/deploy/asapo_services/scripts/templates.tf
+++ b/deploy/asapo_services/scripts/templates.tf
@@ -29,6 +29,7 @@ data "template_file" "asapo_services" {
     authorizer_port = "${var.authorizer_port}"
     discovery_port = "${var.discovery_port}"
     asapo_user = "${var.asapo_user}"
+    force_pull_images = "${var.force_pull_images}"
   }
 }
 
@@ -47,6 +48,8 @@ data "template_file" "asapo_receivers" {
     receiver_network_modes = "${var.receiver_network_modes}"
     asapo_user = "${var.asapo_user}"
     n_receivers = "${var.n_receivers}"
+    force_pull_images = "${var.force_pull_images}"
+    perf_monitor = "${var.perf_monitor}"
   }
 }
 
@@ -58,6 +61,8 @@ data "template_file" "asapo_brokers" {
     nomad_logs = "${var.nomad_logs}"
     asapo_user = "${var.asapo_user}"
     n_brokers = "${var.n_brokers}"
+    force_pull_images = "${var.force_pull_images}"
+    perf_monitor = "${var.perf_monitor}"
   }
 }
 
@@ -72,6 +77,7 @@ data "template_file" "asapo_fts" {
     nomad_logs = "${var.nomad_logs}"
     asapo_user = "${var.asapo_user}"
     n_fts = "${var.n_fts}"
+    force_pull_images = "${var.force_pull_images}"
   }
 }
 
@@ -86,6 +92,8 @@ data "template_file" "asapo_perfmetrics" {
     influxdb_total_memory_size = "${var.influxdb_total_memory_size}"
     influxdb_port = "${var.influxdb_port}"
     asapo_user = "${var.asapo_user}"
+    influxdb_rpc_port = "${var.influxdb_rpc_port}"
+    perf_monitor = "${var.perf_monitor}"
     }
 }
 
diff --git a/deploy/asapo_services/scripts/vars.tf b/deploy/asapo_services/scripts/vars.tf
index 5d69d474089cd565a3bb5650c78a18e6a21eaef7..2e95cf15a863cff1d0565cf5f36d9e4cb0c5bcd3 100644
--- a/deploy/asapo_services/scripts/vars.tf
+++ b/deploy/asapo_services/scripts/vars.tf
@@ -1,4 +1,7 @@
 variable "elk_logs" {}
+variable "perf_monitor" {}
+
+variable "force_pull_images" {}
 
 variable "asapo_user" {}
 
@@ -60,6 +63,8 @@ variable "grafana_port" {}
 
 variable "influxdb_port" {}
 
+variable "influxdb_rpc_port" {}
+
 variable "mongo_port" {}
 
 variable "fluentd_port" {}
diff --git a/deploy/nomad_consul_docker/nomad.hcl.tpl b/deploy/nomad_consul_docker/nomad.hcl.tpl
index 1d67eb3f695986732be629468f657b7c75b58d39..2a5716ee38a99f7c301b25544705a0f8f14cc7d4 100644
--- a/deploy/nomad_consul_docker/nomad.hcl.tpl
+++ b/deploy/nomad_consul_docker/nomad.hcl.tpl
@@ -27,7 +27,9 @@ client {
 plugin "docker" {
   config {
     endpoint = "$docker_endpoint"
-
+    gc {
+        image = false
+    }
     tls {
       cert = "/etc/nomad/cert.pem"
       key  = "/etc/nomad/key.pem"
diff --git a/deploy/nomad_consul_docker/orchestr_config.py b/deploy/nomad_consul_docker/orchestr_config.py
index 5e91651d3bd413a2359790284df9da1b6023b904..52f5da0e6d6fc01be04c96a3d73320170919e1ba 100644
--- a/deploy/nomad_consul_docker/orchestr_config.py
+++ b/deploy/nomad_consul_docker/orchestr_config.py
@@ -59,8 +59,6 @@ def process_file(file_in,file_out):
     filein = open(file_in)
     src = Template(filein.read())
     d = set_parameters()
-    print d
-
     with open(file_out, "w") as out:
         out.write(src.substitute(d))
 
diff --git a/deploy/nomad_consul_docker/scripts/provider.tf b/deploy/nomad_consul_docker/scripts/provider.tf
index 0df2412ca44f14d2a2f03f3c3b0d41d33a9e6cb3..922c3af25a15d5f0668ef0aef8bb1e64ef9238dd 100644
--- a/deploy/nomad_consul_docker/scripts/provider.tf
+++ b/deploy/nomad_consul_docker/scripts/provider.tf
@@ -1,5 +1,5 @@
 provider "nomad" {
   address = "http://localhost:4646"
-  secret_id = "${chomp(file("/var/nomad/token"))}"
+  secret_id = chomp(file("/var/nomad/token"))
 }
 
diff --git a/discovery/src/asapo_discovery/common/consts.go b/discovery/src/asapo_discovery/common/consts.go
index 9789e656f1b7cadca21b370582f815a6e23453bc..e43ea3b1e52bae972c34cb40e658b3d1cc99a98b 100644
--- a/discovery/src/asapo_discovery/common/consts.go
+++ b/discovery/src/asapo_discovery/common/consts.go
@@ -6,3 +6,4 @@ const  (
 	NameBrokerService = "asapo-broker"
 	NameReceiverService = "asapo-receiver"
 )
+
diff --git a/discovery/src/asapo_discovery/go.mod b/discovery/src/asapo_discovery/go.mod
index 84dadee21b1e443654a1c9aaab81842c20e29eb6..d1fbc93e8aa6557c91054b95b2925088f5a36359 100644
--- a/discovery/src/asapo_discovery/go.mod
+++ b/discovery/src/asapo_discovery/go.mod
@@ -6,6 +6,7 @@ replace asapo_common v0.0.0 => ../../../common/go/src/asapo_common
 
 require (
 	asapo_common v0.0.0
+	github.com/gorilla/mux v1.8.0
 	github.com/hashicorp/consul/api v1.4.0
 	github.com/stretchr/testify v1.7.0
 	k8s.io/apimachinery v0.17.0
diff --git a/discovery/src/asapo_discovery/protocols/hard_coded_consumer.go b/discovery/src/asapo_discovery/protocols/hard_coded_consumer.go
new file mode 100644
index 0000000000000000000000000000000000000000..15a8f7b5c89c2f31b4c029279254523aa2d0c3db
--- /dev/null
+++ b/discovery/src/asapo_discovery/protocols/hard_coded_consumer.go
@@ -0,0 +1,14 @@
+package protocols
+
+func GetSupportedConsumerProtocols() []Protocol {
+	return []Protocol{
+		Protocol{"v0.1",
+			map[string]string{
+				"Discovery": "v0.1",
+				"Authorizer": "v0.1",
+				"Broker": "v0.1",
+				"File Transfer": "v0.1",
+				"Data cache service": "v0.1",
+			}, &protocolValidatorCurrent{}},
+	}
+}
diff --git a/discovery/src/asapo_discovery/protocols/hard_coded_producer.go b/discovery/src/asapo_discovery/protocols/hard_coded_producer.go
new file mode 100644
index 0000000000000000000000000000000000000000..515e242930e9c55231cb35dbc830cf25eb2180ec
--- /dev/null
+++ b/discovery/src/asapo_discovery/protocols/hard_coded_producer.go
@@ -0,0 +1,14 @@
+package protocols
+
+func GetSupportedProducerProtocols() []Protocol {
+	return []Protocol{
+		Protocol{"v0.1",
+			map[string]string{
+				"Discovery": "v0.1",
+				"Receiver": "v0.1",
+			}, &protocolValidatorCurrent{}},
+	}
+}
+
+
+
diff --git a/discovery/src/asapo_discovery/protocols/protocol_test.go b/discovery/src/asapo_discovery/protocols/protocol_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..458ff5589920fdbbe4111689fe7fd29cec50a5fa
--- /dev/null
+++ b/discovery/src/asapo_discovery/protocols/protocol_test.go
@@ -0,0 +1,33 @@
+package protocols
+
+import (
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+type protocolTest struct {
+	client   string
+	protocol string
+	result   bool
+	hint     string
+	message  string
+}
+
+var protocolTests = []protocolTest{
+// consumer
+	{"consumer", "v0.1", true, "", "current protocol"},
+	{"consumer", "v0.2", false, "unknown", "unknown protocol"},
+
+
+// producer
+	{"producer", "v0.1", true, "", "current protocol"},
+	{"producer", "v0.2", false, "unknown", "unknown protocol"},
+}
+
+func TestProtocolTests(t *testing.T) {
+	for _, ct := range protocolTests {
+		hint, ok := ValidateProtocol(ct.client, ct.protocol)
+		assert.Equal(t, ct.result, ok, ct.message)
+		assert.Contains(t, hint, ct.hint, ct.message)
+	}
+}
diff --git a/discovery/src/asapo_discovery/protocols/protocols.go b/discovery/src/asapo_discovery/protocols/protocols.go
new file mode 100644
index 0000000000000000000000000000000000000000..ada29e7f0e67348e233e8eb21f40903c0c12080a
--- /dev/null
+++ b/discovery/src/asapo_discovery/protocols/protocols.go
@@ -0,0 +1,84 @@
+package protocols
+
+import "errors"
+
+type protocolValidator interface {
+	IsValid() (hint string, ok bool)
+}
+
+type protocolValidatorCurrent struct {
+}
+
+func (p *protocolValidatorCurrent) IsValid() (hint string, ok bool) {
+	return "current", true
+}
+
+type Protocol struct {
+	Version   string
+	MicroserviceAPis map[string]string
+	validator protocolValidator
+}
+
+type ProtocolInfo  struct {
+	VersionInfo      string            `json:"versionInfo"`
+	MicroservicesApi map[string]string `json:"microservicesApi"`
+}
+
+func (p *Protocol) IsValid() (hint string, ok bool) {
+	return p.validator.IsValid()
+}
+
+func (p *Protocol) GetString() string {
+	hint, _ := p.validator.IsValid()
+	if hint != "" {
+		return p.Version + " (" + hint + ")"
+	} else {
+		return p.Version
+	}
+}
+
+func getSupportedProtocols(client string) ([]Protocol, error) {
+	switch client {
+	case "consumer":
+		return GetSupportedConsumerProtocols(), nil
+	case "producer":
+		return GetSupportedProducerProtocols(), nil
+	}
+	return nil, errors.New("unknown client")
+}
+
+func FindProtocol(client string, version string) (Protocol, error) {
+	protocols, err := getSupportedProtocols(client)
+	if err != nil {
+		return Protocol{},err
+	}
+	for _, protocol := range protocols {
+		if protocol.Version == version {
+			return protocol,nil
+		}
+	}
+	return Protocol{},errors.New("unknown protocol")
+}
+
+func ValidateProtocol(client string, version string) (hint string, ok bool) {
+	protocol, err := FindProtocol(client,version)
+	if err != nil {
+		return err.Error(), false
+	}
+	return protocol.IsValid()
+}
+
+func GetSupportedProtocolsArray(client string) ([]ProtocolInfo, error) {
+	protocols,err := getSupportedProtocols(client)
+	if err!=nil  {
+		return nil,err
+	}
+	res:=make([]ProtocolInfo,0)
+	for _,protocol := range protocols {
+		var info ProtocolInfo
+		info.VersionInfo = protocol.GetString()
+		info.MicroservicesApi = protocol.MicroserviceAPis
+		res = append(res, info)
+	}
+	return res,nil
+}
\ No newline at end of file
diff --git a/discovery/src/asapo_discovery/server/get_health.go b/discovery/src/asapo_discovery/server/get_health.go
new file mode 100644
index 0000000000000000000000000000000000000000..fdc697baf435f6bd7077bad2bdd7aa25284789fb
--- /dev/null
+++ b/discovery/src/asapo_discovery/server/get_health.go
@@ -0,0 +1,9 @@
+package server
+
+import (
+	"net/http"
+)
+
+func routeGetHealth(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(http.StatusNoContent)
+}
diff --git a/discovery/src/asapo_discovery/server/get_health_test.go b/discovery/src/asapo_discovery/server/get_health_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..4d455e086fb8e9aede4d1fb6a4c1738ac244f442
--- /dev/null
+++ b/discovery/src/asapo_discovery/server/get_health_test.go
@@ -0,0 +1,12 @@
+package server
+
+import (
+	"github.com/stretchr/testify/assert"
+	"net/http"
+	"testing"
+)
+
+func TestHealth(t *testing.T) {
+	w := doRequest("/health")
+	assert.Equal(t, http.StatusNoContent, w.Code, "ok")
+}
diff --git a/discovery/src/asapo_discovery/server/get_receivers.go b/discovery/src/asapo_discovery/server/get_receivers.go
deleted file mode 100644
index 5fed8a36aa8be5856be7bad3f700b37933ea2760..0000000000000000000000000000000000000000
--- a/discovery/src/asapo_discovery/server/get_receivers.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package server
-
-import (
-	"net/http"
-	"asapo_common/logger"
-	"asapo_discovery/common"
-)
-
-func getService(service string) (answer []byte, code int) {
-	var err error
-	if (service == "asapo-receiver") {
-		answer, err = requestHandler.GetReceivers(settings.Receiver.UseIBAddress)
-	} else {
-		answer, err = requestHandler.GetSingleService(service)
-
-	}
-	log_str := "processing get "+service
-	if err != nil {
-		logger.Error(log_str + " - " + err.Error())
-		return []byte(err.Error()),http.StatusInternalServerError
-	}
-	logger.Debug(log_str + " -  got " + string(answer))
-	return answer, http.StatusOK
-}
-
-
-func routeGetReceivers(w http.ResponseWriter, r *http.Request) {
-	r.Header.Set("Content-type", "application/json")
-	answer,code := getService(common.NameReceiverService)
-	w.WriteHeader(code)
-	w.Write(answer)
-}
-
-func routeGetBroker(w http.ResponseWriter, r *http.Request) {
-	r.Header.Set("Content-type", "application/json")
-	answer,code := getService(common.NameBrokerService)
-	w.WriteHeader(code)
-	w.Write(answer)
-}
-
-func routeGetMongo(w http.ResponseWriter, r *http.Request) {
-	r.Header.Set("Content-type", "application/json")
-	answer,code := getService(common.NameMongoService)
-	w.WriteHeader(code)
-	w.Write(answer)
-}
-
-func routeGetFileTransferService(w http.ResponseWriter, r *http.Request) {
-	r.Header.Set("Content-type", "application/json")
-	answer,code := getService(common.NameFtsService)
-	w.WriteHeader(code)
-	w.Write(answer)
-}
\ No newline at end of file
diff --git a/discovery/src/asapo_discovery/server/get_version.go b/discovery/src/asapo_discovery/server/get_version.go
new file mode 100644
index 0000000000000000000000000000000000000000..3e2abebd5afd815adb2bda77982424acff6c5992
--- /dev/null
+++ b/discovery/src/asapo_discovery/server/get_version.go
@@ -0,0 +1,115 @@
+package server
+
+import (
+	"asapo_common/logger"
+	"asapo_common/utils"
+	"asapo_common/version"
+	"asapo_discovery/protocols"
+	"encoding/json"
+	"errors"
+	"net/http"
+)
+
+type versionInfo struct {
+	SoftwareVersion            string `json:"softwareVersion"`
+	ClientProtocol     protocols.ProtocolInfo `json:"clientProtocol"`
+	ClientSupported            string `json:"clientSupported"`
+	SupportedProtocols []protocols.ProtocolInfo `json:"supportedProtocols"`
+}
+
+func extractProtocol(r *http.Request) (string, error) {
+	keys := r.URL.Query()
+	protocol := keys.Get("protocol")
+	if protocol == "" {
+		return "", errors.New("cannot extract protocol from request")
+	}
+	return protocol, nil
+}
+
+func routeGetVersion(w http.ResponseWriter, r *http.Request) {
+	log_str := "processing get version"
+	logger.Debug(log_str)
+
+	if ok := checkDiscoveryApiVersion(w, r); !ok {
+		return
+	}
+	keys := r.URL.Query()
+	client := keys.Get("client")
+	protocol := keys.Get("protocol")
+	info, err := getVersionInfo(client, protocol)
+	if err != nil {
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Write([]byte(err.Error()))
+		logger.Error(log_str + " - " + err.Error())
+		return
+	}
+	resp, _ := json.Marshal(&info)
+	w.Write(resp)
+}
+
+func checkDiscoveryApiVersion(w http.ResponseWriter, r *http.Request) bool {
+	_, ok := utils.PrecheckApiVersion(w, r, version.GetDiscoveryApiVersion())
+	return ok
+}
+
+func getVersionInfo(client string, ver string) (versionInfo, error) {
+	info, err := getCoreInfo(client)
+	if err != nil {
+		return versionInfo{}, err
+	}
+	if ver=="" {
+		return info, nil
+	}
+	updateClientInfo(client, ver, &info)
+	return info, nil
+}
+
+func getCoreInfo(client string) (versionInfo, error) {
+	var info versionInfo
+	info.SoftwareVersion = version.GetVersion()
+	if client=="" {
+		return info, nil
+	}
+	var err error
+	info.SupportedProtocols, err = protocols.GetSupportedProtocolsArray(client)
+	if err != nil {
+		return versionInfo{}, err
+	}
+	return info, nil
+}
+
+func updateClientInfo(client string, ver string, info *versionInfo) {
+	if client == "" {
+		return
+	}
+	pInfo,valid := getProtocolInfo(client, ver, info)
+	setSupported(valid, info)
+	if client == "consumer" {
+		info.ClientProtocol = pInfo
+	} else
+	if client == "producer" {
+		info.ClientProtocol = pInfo
+	}
+}
+
+func setSupported(valid bool, info *versionInfo) {
+	if valid {
+		info.ClientSupported = "yes"
+	} else {
+		info.ClientSupported = "no"
+	}
+}
+
+func getProtocolInfo(client string, ver string, info *versionInfo) (pInfo protocols.ProtocolInfo, valid bool) {
+	protocol, err := protocols.FindProtocol(client, ver)
+	if err != nil {
+		pInfo.VersionInfo = ver + " (" + err.Error() + ")"
+		valid = false
+	} else {
+		var hint string
+		hint, valid = protocol.IsValid()
+		pInfo.VersionInfo = ver + " (" + hint + ")"
+		pInfo.MicroservicesApi = protocol.MicroserviceAPis
+	}
+	return
+}
diff --git a/discovery/src/asapo_discovery/server/get_version_test.go b/discovery/src/asapo_discovery/server/get_version_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..5a1e99c8a159a36b9c884b51b83a8d97d11c851e
--- /dev/null
+++ b/discovery/src/asapo_discovery/server/get_version_test.go
@@ -0,0 +1,69 @@
+package server
+
+import (
+	"asapo_common/version"
+	"asapo_discovery/protocols"
+	"encoding/json"
+	"fmt"
+	"github.com/stretchr/testify/assert"
+	"net/http"
+	"testing"
+)
+
+var coreVer = version.GetVersion()
+
+var versionTests = []struct {
+	request string
+	result  versionInfo
+	code    int
+	message string
+}{
+	{"", versionInfo{
+		SoftwareVersion:        coreVer,
+		ClientProtocol: protocols.ProtocolInfo{},
+		ClientSupported:        "",
+	}, http.StatusOK, "no client"},
+	{"?client=consumer", versionInfo{
+		SoftwareVersion: coreVer,
+		ClientProtocol:     protocols.ProtocolInfo{"", nil},
+		ClientSupported:            "no",
+	}, http.StatusOK, "consumer client, no protocol"},
+
+	{"?client=consumer&protocol=v0.1", versionInfo{
+		SoftwareVersion: coreVer,
+		ClientProtocol:     protocols.ProtocolInfo{"v0.1 (current)",
+			map[string]string{"Authorizer":"v0.1", "Broker":"v0.1", "Data cache service":"v0.1", "Discovery":"v0.1", "File Transfer":"v0.1"}},
+		ClientSupported:            "yes",
+	}, http.StatusOK, "consumer client"},
+	{"?client=producer&protocol=v0.1", versionInfo{
+		SoftwareVersion:        coreVer,
+		ClientProtocol: protocols.ProtocolInfo{"v0.1 (current)",map[string]string{"Discovery":"v0.1", "Receiver":"v0.1"}},
+		ClientSupported:        "yes",
+	}, http.StatusOK, "producer client"},
+	{"?client=producer&protocol=v0.2", versionInfo{
+		SoftwareVersion:        coreVer,
+		ClientProtocol: protocols.ProtocolInfo{"v0.2 (unknown protocol)",nil},
+		ClientSupported:        "no",
+	}, http.StatusOK, "producer client unknown"},
+}
+
+func TestVersionTests(t *testing.T) {
+	for _, test := range versionTests {
+		w := doRequest("/" + version.GetDiscoveryApiVersion() + "/version" + test.request)
+		assert.Equal(t, test.code, w.Code, test.message)
+		if test.code == http.StatusOK {
+			var info versionInfo
+			json.Unmarshal(w.Body.Bytes(), &info)
+			fmt.Println(w.Body.String())
+			assert.Equal(t, test.result.ClientProtocol,info.ClientProtocol, test.message)
+			if test.message!="no client" {
+				assert.Equal(t, true,len(info.SupportedProtocols)>0, test.message)
+			}
+		}
+	}
+}
+
+func TestVersionTestsWrongApi(t *testing.T) {
+	w := doRequest("/v2.0/version")
+	assert.Equal(t, http.StatusUnsupportedMediaType, w.Code, "wrong api")
+}
diff --git a/discovery/src/asapo_discovery/server/listroutes.go b/discovery/src/asapo_discovery/server/listroutes.go
index ec6ae17371a6f688925c8a05614855a9d7f248a1..88c566d79e480a08e97a6470cb554ef6a0aa3fdc 100644
--- a/discovery/src/asapo_discovery/server/listroutes.go
+++ b/discovery/src/asapo_discovery/server/listroutes.go
@@ -9,13 +9,13 @@ var listRoutes = utils.Routes{
 	utils.Route{
 		"GetReceivers",
 		"Get",
-		"/" + common.NameReceiverService,
+		"/{apiver}/" + common.NameReceiverService,
 		routeGetReceivers,
 	},
 	utils.Route{
 		"GetBroker",
 		"Get",
-		"/asapo-broker",
+		"/{apiver}/"+common.NameBrokerService,
 		routeGetBroker,
 	},
 	utils.Route{
@@ -24,10 +24,23 @@ var listRoutes = utils.Routes{
 		"/" + common.NameMongoService,
 		routeGetMongo,
 	},
+	utils.Route{
+		"GetVersion",
+		"Get",
+		"/{apiver}/version",
+		routeGetVersion,
+	},
 	utils.Route{
 		"GetFTS",
 		"Get",
-		"/" + common.NameFtsService,
+		"/{apiver}/" + common.NameFtsService,
 		routeGetFileTransferService,
 	},
+	utils.Route{
+		"Health",
+		"Get",
+		"/health",
+		routeGetHealth,
+	},
+
 }
diff --git a/discovery/src/asapo_discovery/server/routes.go b/discovery/src/asapo_discovery/server/routes.go
new file mode 100644
index 0000000000000000000000000000000000000000..d918a8adb6db7208fe001f2bb4df96e94ea7bd06
--- /dev/null
+++ b/discovery/src/asapo_discovery/server/routes.go
@@ -0,0 +1,90 @@
+package server
+
+import (
+	"asapo_discovery/protocols"
+	"net/http"
+	"asapo_common/logger"
+	"asapo_discovery/common"
+)
+
+func getService(service string) (answer []byte, code int) {
+	var err error
+	if service == "asapo-receiver" {
+		answer, err = requestHandler.GetReceivers(settings.Receiver.UseIBAddress)
+	} else {
+		answer, err = requestHandler.GetSingleService(service)
+
+	}
+	log_str := "processing get " + service
+	if err != nil {
+		logger.Error(log_str + " - " + err.Error())
+		return []byte(err.Error()), http.StatusInternalServerError
+	}
+	logger.Debug(log_str + " -  got " + string(answer))
+	return answer, http.StatusOK
+}
+
+func validateProtocol(w http.ResponseWriter, r *http.Request, client string) bool {
+	protocol, err := extractProtocol(r)
+	log_str := "validating " + client + " protocol"
+	if err != nil {
+		w.WriteHeader(http.StatusBadRequest)
+		w.Write([]byte(err.Error()))
+		logger.Error(log_str + " - " + err.Error())
+		return false
+	}
+	if hint, ok := protocols.ValidateProtocol(client, protocol); !ok {
+		w.WriteHeader(http.StatusUnsupportedMediaType)
+		w.Write([]byte(hint))
+		logger.Error(log_str + " - " + hint)
+		return false
+	}
+	logger.Debug(log_str + " - ok")
+	return true
+}
+
+func routeGetReceivers(w http.ResponseWriter, r *http.Request) {
+	if ok := checkDiscoveryApiVersion(w, r); !ok {
+		return
+	}
+
+	if !validateProtocol(w, r, "producer") {
+		return
+	}
+	answer, code := getService(common.NameReceiverService)
+	w.WriteHeader(code)
+	w.Write(answer)
+}
+
+func routeGetBroker(w http.ResponseWriter, r *http.Request) {
+	if ok := checkDiscoveryApiVersion(w, r); !ok {
+		return
+	}
+
+	if !validateProtocol(w, r, "consumer") {
+		return
+	}
+
+	answer, code := getService(common.NameBrokerService)
+	w.WriteHeader(code)
+	w.Write(answer)
+}
+
+func routeGetMongo(w http.ResponseWriter, r *http.Request) {
+	answer, code := getService(common.NameMongoService)
+	w.WriteHeader(code)
+	w.Write(answer)
+}
+
+func routeGetFileTransferService(w http.ResponseWriter, r *http.Request) {
+	if ok := checkDiscoveryApiVersion(w, r); !ok {
+		return
+	}
+	if !validateProtocol(w, r, "consumer") {
+		return
+	}
+
+	answer, code := getService(common.NameFtsService)
+	w.WriteHeader(code)
+	w.Write(answer)
+}
diff --git a/discovery/src/asapo_discovery/server/routes_test.go b/discovery/src/asapo_discovery/server/routes_test.go
index f15fb60704580489017776c1ef40916eb669c892..e72d0c55abfba927659cf6e56f651046b504e2a0 100644
--- a/discovery/src/asapo_discovery/server/routes_test.go
+++ b/discovery/src/asapo_discovery/server/routes_test.go
@@ -1,6 +1,7 @@
 package server
 
 import (
+	"asapo_common/version"
 	"github.com/stretchr/testify/mock"
 	"github.com/stretchr/testify/suite"
 	"asapo_common/logger"
@@ -31,9 +32,9 @@ type GetServicesTestSuite struct {
 
 func (suite *GetServicesTestSuite) SetupTest() {
 	requestHandler = new(request_handler.StaticRequestHandler)
-	var s common.Settings= common.Settings{Receiver:common.ReceiverInfo{MaxConnections:10,StaticEndpoints:[]string{"ip1","ip2"}},
-	Broker:common.BrokerInfo{StaticEndpoint:"ip_broker"},Mongo:common.MongoInfo{StaticEndpoint:"ip_mongo"},
-		FileTransferService:common.FtsInfo{StaticEndpoint:"ip_fts"}}
+	var s common.Settings = common.Settings{Receiver: common.ReceiverInfo{MaxConnections: 10, StaticEndpoints: []string{"ip1", "ip2"}},
+		Broker: common.BrokerInfo{StaticEndpoint: "ip_broker"}, Mongo: common.MongoInfo{StaticEndpoint: "ip_mongo"},
+		FileTransferService: common.FtsInfo{StaticEndpoint: "ip_fts"}}
 
 	requestHandler.Init(s)
 	logger.SetMockLog()
@@ -58,27 +59,63 @@ func (suite *GetServicesTestSuite) TestWrongPath() {
 	suite.Equal(http.StatusNotFound, w.Code, "wrong path")
 }
 
-func (suite *GetServicesTestSuite) TestGetReceivers() {
-	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get "+common.NameReceiverService)))
-
-	w := doRequest("/asapo-receiver")
-
-	suite.Equal(http.StatusOK, w.Code, "code ok")
-	suite.Equal(w.Body.String(), "{\"MaxConnections\":10,\"Uris\":[\"ip1\",\"ip2\"]}", "result")
-	assertExpectations(suite.T())
+type requestTest struct {
+request string
+code int
+message string
 }
 
+var receiverTests = []requestTest {
+	{"/" + version.GetDiscoveryApiVersion()+"/asapo-receiver",http.StatusBadRequest,"protocol missing"},
+	{"/" + version.GetDiscoveryApiVersion()+"/asapo-receiver?protocol=v0.2",http.StatusUnsupportedMediaType,"wrong protocol"},
+	{"/" + version.GetDiscoveryApiVersion()+"/asapo-receiver?protocol=v0.1",http.StatusOK,"ok"},
+}
 
-func (suite *GetServicesTestSuite) TestGetBroker() {
-	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get "+common.NameBrokerService)))
+func (suite *GetServicesTestSuite) TestGetReceivers() {
+	for _,test:= range receiverTests {
+		if test.code == http.StatusOK {
+			logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("validating producer")))
+			logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get "+common.NameReceiverService)))
+		} else {
+			logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("validating producer")))
+		}
+
+		w := doRequest(test.request)
+
+		suite.Equal(test.code, w.Code, test.message)
+		if test.code == http.StatusOK {
+			suite.Equal(w.Body.String(), "{\"MaxConnections\":10,\"Uris\":[\"ip1\",\"ip2\"]}", "result")
+		}
+		assertExpectations(suite.T())
+	}
 
-	w := doRequest("/asapo-broker")
+}
 
-	suite.Equal(http.StatusOK, w.Code, "code ok")
-	suite.Equal(w.Body.String(), "ip_broker", "result")
-	assertExpectations(suite.T())
+var brokerTests = []requestTest {
+	{"/" + version.GetDiscoveryApiVersion()+"/asapo-broker",http.StatusBadRequest,"protocol missing"},
+	{"/" + version.GetDiscoveryApiVersion()+"/asapo-broker?protocol=v0.2",http.StatusUnsupportedMediaType,"wrong protocol"},
+	{"/" + version.GetDiscoveryApiVersion()+"/asapo-broker?protocol=v0.1",http.StatusOK,"ok"},
+}
+func (suite *GetServicesTestSuite) TestGetBroker() {
+	for _,test:= range brokerTests {
+		if test.code == http.StatusOK {
+			logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("validating consumer")))
+			logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get "+common.NameBrokerService)))
+		} else {
+			logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("validating consumer")))
+		}
+
+		w := doRequest(test.request)
+
+		suite.Equal(test.code, w.Code, test.message)
+		if test.code == http.StatusOK {
+			suite.Equal(w.Body.String(), "ip_broker", "result")
+		}
+		assertExpectations(suite.T())
+	}
 }
 
+
 func (suite *GetServicesTestSuite) TestGetMongo() {
 	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get "+common.NameMongoService)))
 
@@ -91,10 +128,23 @@ func (suite *GetServicesTestSuite) TestGetMongo() {
 
 func (suite *GetServicesTestSuite) TestGetFts() {
 	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get "+common.NameFtsService)))
+	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("validating")))
 
-	w := doRequest("/asapo-file-transfer")
+	w := doRequest("/" + version.GetDiscoveryApiVersion()+"/asapo-file-transfer?protocol=v0.1")
 
 	suite.Equal(http.StatusOK, w.Code, "code ok")
 	suite.Equal(w.Body.String(), "ip_fts", "result")
 	assertExpectations(suite.T())
 }
+
+func (suite *GetServicesTestSuite) TestGetVersions() {
+	logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("processing get version")))
+
+	w := doRequest("/" + version.GetDiscoveryApiVersion() + "/version")
+
+	suite.Equal(http.StatusOK, w.Code, "code ok")
+	// we dont really check what it returns, just that route is ok
+	suite.Contains(w.Body.String(), version.GetVersion(), "core version")
+	suite.Contains(w.Body.String(), "supportedProtocols", "protocols")
+	assertExpectations(suite.T())
+}
diff --git a/examples/consumer/getnext/check_linux.sh b/examples/consumer/getnext/check_linux.sh
index a8c0ec75089eeff7ab9ca5049ea4dbbc530abd27..2c853792cf60bc9a171c6664a2a695ca71c0791f 100644
--- a/examples/consumer/getnext/check_linux.sh
+++ b/examples/consumer/getnext/check_linux.sh
@@ -17,7 +17,7 @@ Cleanup() {
     nomad stop discovery
     nomad stop authorizer
     nomad stop broker
-	echo "db.dropDatabase()" | mongo ${database_name}
+  	echo "db.dropDatabase()" | mongo ${database_name}
 }
 
 nomad run nginx.nmd
diff --git a/examples/consumer/getnext/getnext.cpp b/examples/consumer/getnext/getnext.cpp
index 5e90a3885be448262e12bbd099278deb62eb6f8b..d30e87e578210fb3776e34c18c1fd4d332ad321b 100644
--- a/examples/consumer/getnext/getnext.cpp
+++ b/examples/consumer/getnext/getnext.cpp
@@ -19,6 +19,7 @@ std::mutex lock;
 
 uint64_t file_size = 0;
 
+
 inline std::string ConnectionTypeToString(asapo::NetworkConnectionType type) {
     switch (type) {
     case asapo::NetworkConnectionType::kUndefined:
@@ -119,6 +120,7 @@ StartThreads(const Args& params, std::vector<int>* nfiles, std::vector<int>* err
             if (err) {
                 (*errors)[i] += ProcessError(err);
                 lock.unlock();
+                exit(EXIT_FAILURE);
                 return;
             }
         }
@@ -263,7 +265,6 @@ void TryGetStream(Args* args) {
 }
 
 int main(int argc, char* argv[]) {
-    asapo::ExitAfterPrintVersionIfNeeded("GetNext consumer Example", argc, argv);
     Args params;
     params.datasets = false;
     if (argc != 8 && argc != 9) {
diff --git a/examples/pipeline/in_to_out/in_to_out.cpp b/examples/pipeline/in_to_out/in_to_out.cpp
index 801d9f32a0653776f4a2093a2a3d545bcad19dc3..e96985a02266e9a7e5fa3bde748e0ba6361e3478 100644
--- a/examples/pipeline/in_to_out/in_to_out.cpp
+++ b/examples/pipeline/in_to_out/in_to_out.cpp
@@ -206,7 +206,6 @@ std::unique_ptr<asapo::Producer> CreateProducer(const Args &args) {
 }
 
 int main(int argc, char* argv[]) {
-    asapo::ExitAfterPrintVersionIfNeeded("GetNext consumer Example", argc, argv);
     Args args;
     if (argc != 11) {
         std::cout << "Usage: " + std::string{argv[0]}
diff --git a/examples/producer/dummy-data-producer/dummy_data_producer.cpp b/examples/producer/dummy-data-producer/dummy_data_producer.cpp
index d983f01e2d419a5b5ca0356e746d4a64d16b54be..560cd20ba6b9f89aa52d40deae4cab08319f2666 100644
--- a/examples/producer/dummy-data-producer/dummy_data_producer.cpp
+++ b/examples/producer/dummy-data-producer/dummy_data_producer.cpp
@@ -69,7 +69,6 @@ void TryGetDataSourceAndToken(Args* args) {
 
 
 void ProcessCommandArguments(int argc, char* argv[], Args* args) {
-    asapo::ExitAfterPrintVersionIfNeeded("Dummy Data Producer", argc, argv);
     if (argc != 8 && argc != 9) {
         std::cout <<
                   "Usage: " << argv[0] <<
diff --git a/file_transfer/src/asapo_file_transfer/server/listroutes.go b/file_transfer/src/asapo_file_transfer/server/listroutes.go
index 03fba92d86e41b3418eba91878c4253cb5ffb2f0..54188582ae387e1c61118539ad835eebba1ed36d 100644
--- a/file_transfer/src/asapo_file_transfer/server/listroutes.go
+++ b/file_transfer/src/asapo_file_transfer/server/listroutes.go
@@ -8,7 +8,7 @@ var listRoutes = utils.Routes{
 	utils.Route{
 		"Transfer File",
 		"POST",
-		"/transfer",
+		"/{apiver}/transfer",
 		routeFileTransfer,
 	},
 	utils.Route{
diff --git a/file_transfer/src/asapo_file_transfer/server/transfer.go b/file_transfer/src/asapo_file_transfer/server/transfer.go
index 18b172a8e232472bfb55495f0d88886b2e43d733..8e6817007b75dc25ab7b589814c13a0788ea42f6 100644
--- a/file_transfer/src/asapo_file_transfer/server/transfer.go
+++ b/file_transfer/src/asapo_file_transfer/server/transfer.go
@@ -4,6 +4,7 @@ import (
 	log "asapo_common/logger"
 	"asapo_common/structs"
 	"asapo_common/utils"
+	"asapo_common/version"
 	"encoding/json"
 	"errors"
 	"net/http"
@@ -88,7 +89,17 @@ func serveFileSize(w http.ResponseWriter, r *http.Request, fullName string) {
 	w.Write(b)
 }
 
+
+func checkFtsApiVersion(w http.ResponseWriter, r *http.Request) bool {
+	_, ok := utils.PrecheckApiVersion(w, r, version.GetFtsApiVersion())
+	return ok
+}
+
 func routeFileTransfer(w http.ResponseWriter, r *http.Request) {
+	if ok := checkFtsApiVersion(w, r); !ok {
+		return
+	}
+
 	fullName, status,err := checkRequest(r);
 	if err != nil {
 		utils.WriteServerError(w,err,status)
diff --git a/file_transfer/src/asapo_file_transfer/server/transfer_test.go b/file_transfer/src/asapo_file_transfer/server/transfer_test.go
index 815d4b48a0b7408f43c45c39e777b835f8bd95ee..378426407d26265af17b2ee6e522d023a540b207 100644
--- a/file_transfer/src/asapo_file_transfer/server/transfer_test.go
+++ b/file_transfer/src/asapo_file_transfer/server/transfer_test.go
@@ -72,7 +72,7 @@ func TestTransferFile(t *testing.T) {
 
 	for _, test := range transferFileTests {
 		request :=  makeRequest(fileTransferRequest{test.folder,test.fname})
-		w := doPostRequest("/transfer",request,test.token)
+		w := doPostRequest("/v0.1/transfer",request,test.token)
 		if test.status==http.StatusOK {
 			body, _ := ioutil.ReadAll(w.Body)
 			body_str:=string(body)
@@ -92,7 +92,7 @@ func TestTransferFileSize(t *testing.T) {
 
 	test:=transferFileTests[0]
 		request :=  makeRequest(fileTransferRequest{test.folder,test.fname})
-		w := doPostRequest("/transfer?sizeonly=true",request,test.token)
+		w := doPostRequest("/v0.1/transfer?sizeonly=true",request,test.token)
 		if test.status==http.StatusOK {
 			body, _ := ioutil.ReadAll(w.Body)
 			body_str:=string(body)
@@ -101,3 +101,11 @@ func TestTransferFileSize(t *testing.T) {
 		}
 		assert.Equal(t, test.status, w.Code, test.message)
 }
+
+
+func TestTransferWrongApiVersion(t *testing.T) {
+	request :=  makeRequest(fileTransferRequest{"folder","fname"})
+	token := prepareToken("folder")
+	w := doPostRequest("/v0.2/transfer?sizeonly=true",request,token)
+	assert.Equal(t, http.StatusUnsupportedMediaType, w.Code, "wrong api version")
+}
diff --git a/producer/api/cpp/CMakeLists.txt b/producer/api/cpp/CMakeLists.txt
index 896c05265d55a5b9c9cea5fbfc75fc877d8716d0..24b5722350e4392b898e3d4b350055184c8b8c4b 100644
--- a/producer/api/cpp/CMakeLists.txt
+++ b/producer/api/cpp/CMakeLists.txt
@@ -14,7 +14,7 @@ set(SOURCE_FILES
 # Library
 ################################
 add_library(${TARGET_NAME} STATIC ${SOURCE_FILES} $<TARGET_OBJECTS:system_io> $<TARGET_OBJECTS:logger> $<TARGET_OBJECTS:json_parser>
-        $<TARGET_OBJECTS:curl_http_client> $<TARGET_OBJECTS:request_pool> $<TARGET_OBJECTS:data_structs>)
+        $<TARGET_OBJECTS:curl_http_client> $<TARGET_OBJECTS:request_pool> $<TARGET_OBJECTS:data_structs> $<TARGET_OBJECTS:version>)
 target_include_directories(${TARGET_NAME} PUBLIC include ${ASAPO_CXX_COMMON_INCLUDE_DIR})
 target_link_libraries(${TARGET_NAME} ${CURL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
 
diff --git a/producer/api/cpp/include/asapo/asapo_producer.h b/producer/api/cpp/include/asapo/asapo_producer.h
index 1e5ea176cd474cfb25e98e0523ea16ee0ac0418b..152abe230de7e0fe2f7604c55d0f7f3885fccb76 100644
--- a/producer/api/cpp/include/asapo/asapo_producer.h
+++ b/producer/api/cpp/include/asapo/asapo_producer.h
@@ -2,7 +2,6 @@
 #define ASAPO_ASAPO_PRODUCER_H
 
 #include "asapo/common/io_error.h"
-#include "asapo/common/version.h"
 
 #include "asapo/producer/producer.h"
 #include "asapo/producer/producer_error.h"
diff --git a/producer/api/cpp/include/asapo/producer/producer.h b/producer/api/cpp/include/asapo/producer/producer.h
index c8de7d637ff86f09f2f976e52f792e23a54cc816..a2fde18ebeeb2f3ae0a02784bf6f5ccf39382bc3 100644
--- a/producer/api/cpp/include/asapo/producer/producer.h
+++ b/producer/api/cpp/include/asapo/producer/producer.h
@@ -23,6 +23,15 @@ class Producer {
 
     virtual ~Producer() = default;
 
+  //! Return version
+  /*!
+    \param client_info - for client version
+    \param server_info - for server
+    \param supported - set to true if client is supported by server
+    \return nullptr of command was successful, otherwise error.
+  */
+  virtual Error GetVersionInfo(std::string* client_info,std::string* server_info, bool* supported) const = 0;
+
     //! Get stream information from receiver
     /*!
       \param stream - stream to send messages to
diff --git a/producer/api/cpp/include/asapo/producer/producer_error.h b/producer/api/cpp/include/asapo/producer/producer_error.h
index 1d1e0904f91f7be183e8dd55545a0cbca8281ba1..6f8e66ea926a60bbba909809893e350171c2637e 100644
--- a/producer/api/cpp/include/asapo/producer/producer_error.h
+++ b/producer/api/cpp/include/asapo/producer/producer_error.h
@@ -13,6 +13,7 @@ enum class ProducerErrorType {
     kWrongInput,
     kServerWarning,
     kReAuthorizationNeeded,
+    kUnsupportedClient,
     kTimeout
 };
 
@@ -54,6 +55,12 @@ auto const kReAuthorizationNeeded = ProducerErrorTemplate {
     "reauthorization needed", ProducerErrorType::kReAuthorizationNeeded
 };
 
+auto const kUnsupportedClient = ProducerErrorTemplate {
+    "cannot connect to asapo", ProducerErrorType::kUnsupportedClient
+};
+
+
+
 
 
 };
diff --git a/producer/api/cpp/src/producer_impl.cpp b/producer/api/cpp/src/producer_impl.cpp
index cba069bb723f350b3713166b27c00208af13671b..2a4d38a5b11699300300d77e93db4992ae84ce23 100644
--- a/producer/api/cpp/src/producer_impl.cpp
+++ b/producer/api/cpp/src/producer_impl.cpp
@@ -1,16 +1,16 @@
 #include <iostream>
-#include <iostream>
 #include <cstring>
 #include <future>
 
 #include "producer_impl.h"
 #include "producer_logger.h"
-#include "asapo/io/io_factory.h"
 #include "asapo/producer/producer_error.h"
 #include "producer_request_handler_factory.h"
 #include "producer_request.h"
 #include "asapo/common/data_structs.h"
 #include "asapo/request/request_pool_error.h"
+#include "asapo/http_client/http_client.h"
+#include "asapo/common/internal/version.h"
 
 namespace  asapo {
 
@@ -18,7 +18,7 @@ const size_t ProducerImpl::kDiscoveryServiceUpdateFrequencyMs = 10000; // 10s
 
 ProducerImpl::ProducerImpl(std::string endpoint, uint8_t n_processing_threads, uint64_t timeout_ms,
                            asapo::RequestHandlerType type):
-    log__{GetDefaultProducerLogger()}, timeout_ms_{timeout_ms} {
+    log__{GetDefaultProducerLogger()},httpclient__{DefaultHttpClient()}, timeout_ms_{timeout_ms},endpoint_{endpoint} {
     switch (type) {
     case RequestHandlerType::kTcp:
         discovery_service_.reset(new ReceiverDiscoveryService{endpoint, ProducerImpl::kDiscoveryServiceUpdateFrequencyMs});
@@ -392,5 +392,32 @@ void ProducerImpl::SetRequestsQueueLimits(uint64_t size, uint64_t volume) {
     request_pool__->SetLimits(RequestPoolLimits{size,volume});
 }
 
+Error ProducerImpl::GetVersionInfo(std::string* client_info, std::string* server_info, bool* supported) const {
+    if (client_info == nullptr && server_info == nullptr && supported == nullptr) {
+        return ProducerErrorTemplates::kWrongInput.Generate("missing parameters");
+    }
+    if (client_info != nullptr) {
+        *client_info =
+            "software version: " + std::string(kVersion) + ", producer protocol: " + kProducerProtocol.GetVersion();
+    }
+
+    if (server_info != nullptr || supported != nullptr) {
+        return GetServerVersionInfo(server_info, supported);
+    }
+    return nullptr;
+}
+
+Error ProducerImpl::GetServerVersionInfo(std::string* server_info,
+                                         bool* supported) const {
+    auto endpoint = endpoint_ +"/asapo-discovery/"+kProducerProtocol.GetDiscoveryVersion()+
+        "/version?client=producer&protocol="+kProducerProtocol.GetVersion();
+    HttpCode  code;
+    Error err;
+    auto response = httpclient__->Get(endpoint, &code, &err);
+    if (err) {
+        return err;
+    }
+    return ExtractVersionFromResponse(response,"producer",server_info,supported);
+}
 
 }
\ No newline at end of file
diff --git a/producer/api/cpp/src/producer_impl.h b/producer/api/cpp/src/producer_impl.h
index a60b59c7dfd0a49b43f2757c782917ab3262a1e2..53fda3df0a07508efce6dc7f7ef891af2601bf4a 100644
--- a/producer/api/cpp/src/producer_impl.h
+++ b/producer/api/cpp/src/producer_impl.h
@@ -30,6 +30,9 @@ class ProducerImpl : public Producer {
   ProducerImpl(const ProducerImpl &) = delete;
   ProducerImpl &operator=(const ProducerImpl &) = delete;
 
+
+  Error GetVersionInfo(std::string* client_info,std::string* server_info, bool* supported) const override;
+
   StreamInfo GetStreamInfo(std::string stream, uint64_t timeout_ms, Error* err) const override;
   StreamInfo GetLastStream(uint64_t timeout_ms, Error* err) const override;
 
@@ -56,6 +59,7 @@ class ProducerImpl : public Producer {
                                   RequestCallback callback) override;
 
   AbstractLogger* log__;
+  std::unique_ptr<HttpClient> httpclient__;
   std::unique_ptr<RequestPool> request_pool__;
 
   Error SetCredentials(SourceCredentials source_cred) override;
@@ -74,6 +78,9 @@ class ProducerImpl : public Producer {
                                                uint64_t ingest_mode);
   std::string source_cred_string_;
   uint64_t timeout_ms_;
+  std::string endpoint_;
+  Error GetServerVersionInfo(std::string* server_info,
+                             bool* supported) const;
 };
 
 struct StreamInfoResult {
diff --git a/producer/api/cpp/src/producer_request.cpp b/producer/api/cpp/src/producer_request.cpp
index 73a64c2a61052aae9d9cc68f4c717b77591e99ef..7d41d0d44c1311674214c1d72bf72e0955d5f044 100644
--- a/producer/api/cpp/src/producer_request.cpp
+++ b/producer/api/cpp/src/producer_request.cpp
@@ -1,5 +1,6 @@
 #include <asapo/asapo_producer.h>
 #include "producer_request.h"
+#include "asapo/common/internal/version.h"
 
 namespace asapo {
 
@@ -24,6 +25,13 @@ ProducerRequest::ProducerRequest(std::string source_credentials,
     original_filepath{std::move(original_filepath)},
     callback{callback},
     manage_data_memory{manage_data_memory} {
+
+    if (kProducerProtocol.GetReceiverVersion().size()<kMaxVersionSize) {
+        strcpy(header.api_version, kProducerProtocol.GetReceiverVersion().c_str());
+    } else {
+        strcpy(header.api_version, "v0.0");
+    }
+
 }
 
 bool ProducerRequest::NeedSend() const {
diff --git a/producer/api/cpp/src/receiver_discovery_service.cpp b/producer/api/cpp/src/receiver_discovery_service.cpp
index 69b6ace5338ae8ec7d07114c85feb9b99a1c060a..b1130b7ec6043a9635c2336c57de719967e48eda 100644
--- a/producer/api/cpp/src/receiver_discovery_service.cpp
+++ b/producer/api/cpp/src/receiver_discovery_service.cpp
@@ -1,15 +1,17 @@
 #include "receiver_discovery_service.h"
 
-#include "producer_logger.h"
-#include "asapo/json_parser/json_parser.h"
-
 #include <iostream>
 #include <algorithm>
 #include <numeric>
 
+#include "producer_logger.h"
+#include "asapo/json_parser/json_parser.h"
+#include "asapo/common/internal/version.h"
+
 namespace  asapo {
 
-const std::string ReceiverDiscoveryService::kServiceEndpointSuffix = "/asapo-discovery/asapo-receiver";
+const std::string ReceiverDiscoveryService::kServiceEndpointSuffix = "/asapo-discovery/"+kProducerProtocol.GetDiscoveryVersion()
+    +"/asapo-receiver?protocol="+kConsumerProtocol.GetVersion();
 
 ReceiverDiscoveryService::ReceiverDiscoveryService(std::string endpoint, uint64_t update_frequency_ms): httpclient__{DefaultHttpClient()},
     log__{GetDefaultProducerLogger()},
diff --git a/producer/api/cpp/src/request_handler_tcp.cpp b/producer/api/cpp/src/request_handler_tcp.cpp
index e6f105d0150499ad74f665b16610710c97153df0..85895cfd06c37dcd4257ad88c2c6bbf1d5be75e4 100644
--- a/producer/api/cpp/src/request_handler_tcp.cpp
+++ b/producer/api/cpp/src/request_handler_tcp.cpp
@@ -7,16 +7,19 @@
 namespace asapo {
 
 RequestHandlerTcp::RequestHandlerTcp(ReceiverDiscoveryService* discovery_service, uint64_t thread_id,
-                                     uint64_t* shared_counter):
-    io__{GenerateDefaultIO()}, log__{GetDefaultProducerLogger()}, discovery_service__{discovery_service}, thread_id_{thread_id},
+                                     uint64_t* shared_counter) :
+    io__{GenerateDefaultIO()},
+    log__{GetDefaultProducerLogger()},
+    discovery_service__{discovery_service},
+    thread_id_{thread_id},
     ncurrent_connections_{shared_counter} {
 }
 
-Error RequestHandlerTcp::Authorize(const std::string& source_credentials) {
+Error RequestHandlerTcp::Authorize(const std::string &source_credentials) {
     GenericRequestHeader header{kOpcodeAuthorize, 0, 0, source_credentials.size(), ""};
     Error err;
     io__->Send(sd_, &header, sizeof(header), &err);
-    if(err) {
+    if (err) {
         return err;
     }
 
@@ -28,12 +31,11 @@ Error RequestHandlerTcp::Authorize(const std::string& source_credentials) {
     return ReceiveResponse(header, nullptr);
 }
 
-
-Error RequestHandlerTcp::ConnectToReceiver(const std::string& source_credentials, const std::string& receiver_address) {
+Error RequestHandlerTcp::ConnectToReceiver(const std::string &source_credentials, const std::string &receiver_address) {
     Error err;
 
     sd_ = io__->CreateAndConnectIPTCPSocket(receiver_address, &err);
-    if(err != nullptr) {
+    if (err != nullptr) {
         log__->Debug("cannot connect to receiver at " + receiver_address + " - " + err->Explain());
         return err;
     }
@@ -55,11 +57,10 @@ Error RequestHandlerTcp::ConnectToReceiver(const std::string& source_credentials
 Error RequestHandlerTcp::SendRequestContent(const ProducerRequest* request) {
     Error io_error;
     io__->Send(sd_, &(request->header), sizeof(request->header), &io_error);
-    if(io_error) {
+    if (io_error) {
         return io_error;
     }
 
-
     if (request->NeedSendMetaData()) {
         io__->Send(sd_, (void*) request->metadata.c_str(), (size_t) request->header.meta_size, &io_error);
         if (io_error) {
@@ -69,9 +70,9 @@ Error RequestHandlerTcp::SendRequestContent(const ProducerRequest* request) {
 
     if (request->NeedSend()) {
         if (request->DataFromFile()) {
-            io_error = io__->SendFile(sd_,  request->original_filepath, (size_t)request->header.data_size);
+            io_error = io__->SendFile(sd_, request->original_filepath, (size_t) request->header.data_size);
         } else {
-            io__->Send(sd_, (void*) request->data.get(), (size_t)request->header.data_size, &io_error);
+            io__->Send(sd_, (void*) request->data.get(), (size_t) request->header.data_size, &io_error);
         }
         if (io_error) {
             return io_error;
@@ -81,65 +82,69 @@ Error RequestHandlerTcp::SendRequestContent(const ProducerRequest* request) {
     return nullptr;
 }
 
-Error RequestHandlerTcp::ReceiveResponse(const GenericRequestHeader& request_header, std::string* response) {
+Error RequestHandlerTcp::ReceiveResponse(const GenericRequestHeader &request_header, std::string* response) {
     Error err;
     SendResponse sendDataResponse;
     io__->Receive(sd_, &sendDataResponse, sizeof(sendDataResponse), &err);
-    if(err != nullptr) {
+    if (err != nullptr) {
         return err;
     }
 
     switch (sendDataResponse.error_code) {
-    case kNetAuthorizationError : {
-        auto res_err = ProducerErrorTemplates::kWrongInput.Generate();
-        res_err->Append(sendDataResponse.message);
-        return res_err;
-    }
-    case kNetErrorWrongRequest : {
-        auto res_err = ProducerErrorTemplates::kWrongInput.Generate();
-        res_err->Append(sendDataResponse.message);
-        return res_err;
-    }
-    case kNetErrorWarning: {
-        auto res_err = ProducerErrorTemplates::kServerWarning.Generate();
-        res_err->Append(sendDataResponse.message);
-        return res_err;
-    }
-    case kNetErrorReauthorize: {
-        auto res_err = ProducerErrorTemplates::kReAuthorizationNeeded.Generate();
-        return res_err;
-    }
-    case kNetErrorNoError :
-        if (response) {
-            *response = sendDataResponse.message;
+        case kNetAuthorizationError : {
+            auto res_err = ProducerErrorTemplates::kWrongInput.Generate();
+            res_err->Append(sendDataResponse.message);
+            return res_err;
+        }
+        case kNetErrorNotSupported : {
+            auto res_err = ProducerErrorTemplates::kUnsupportedClient.Generate();
+            res_err->Append(sendDataResponse.message);
+            return res_err;
+        }
+        case kNetErrorWrongRequest : {
+            auto res_err = ProducerErrorTemplates::kWrongInput.Generate();
+            res_err->Append(sendDataResponse.message);
+            return res_err;
         }
-        return nullptr;
-    default:
-        auto res_err = ProducerErrorTemplates::kInternalServerError.Generate();
-        res_err->Append(sendDataResponse.message);
-        return res_err;
+        case kNetErrorWarning: {
+            auto res_err = ProducerErrorTemplates::kServerWarning.Generate();
+            res_err->Append(sendDataResponse.message);
+            return res_err;
+        }
+        case kNetErrorReauthorize: {
+            auto res_err = ProducerErrorTemplates::kReAuthorizationNeeded.Generate();
+            return res_err;
+        }
+        case kNetErrorNoError :
+            if (response) {
+                *response = sendDataResponse.message;
+            }
+            return nullptr;
+        default:auto res_err = ProducerErrorTemplates::kInternalServerError.Generate();
+            res_err->Append(sendDataResponse.message);
+            return res_err;
     }
 }
 
 Error RequestHandlerTcp::TrySendToReceiver(const ProducerRequest* request, std::string* response) {
     auto err = SendRequestContent(request);
-    if (err)  {
+    if (err) {
         return err;
     }
 
     err = ReceiveResponse(request->header, response);
-    if (err == nullptr || err == ProducerErrorTemplates::kServerWarning)  {
+    if (err == nullptr || err == ProducerErrorTemplates::kServerWarning) {
         log__->Debug("successfully sent data, opcode: " + std::to_string(request->header.op_code) +
-                     ", id: " + std::to_string(request->header.data_id) + " to " + connected_receiver_uri_);
-        if (err == ProducerErrorTemplates::kServerWarning ) {
-            log__->Warning("warning from server for id " + std::to_string(request->header.data_id) + ": " + err->Explain());
+            ", id: " + std::to_string(request->header.data_id) + " to " + connected_receiver_uri_);
+        if (err == ProducerErrorTemplates::kServerWarning) {
+            log__->Warning(
+                "warning from server for id " + std::to_string(request->header.data_id) + ": " + err->Explain());
         }
     }
 
     return err;
 }
 
-
 void RequestHandlerTcp::UpdateIfNewConnection() {
     if (Connected())
         return;
@@ -158,17 +163,15 @@ bool RequestHandlerTcp::UpdateReceiversList() {
 }
 
 bool RequestHandlerTcp::TimeToUpdateReceiverList() {
-    uint64_t elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>( system_clock::now() -
-                          last_receivers_uri_update_).count();
+    uint64_t elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(system_clock::now() -
+        last_receivers_uri_update_).count();
     return elapsed_ms > discovery_service__->UpdateFrequency();
 }
 
-
 bool RequestHandlerTcp::Disconnected() {
     return !Connected();
 }
 
-
 bool RequestHandlerTcp::NeedRebalance() {
     if (Disconnected())
         return false;
@@ -192,23 +195,24 @@ void RequestHandlerTcp::Disconnect() {
     connected_receiver_uri_.clear();
 }
 
-bool RequestHandlerTcp::ServerError(const Error& err) {
+bool RequestHandlerTcp::ServerError(const Error &err) {
     return err != nullptr && (err != ProducerErrorTemplates::kWrongInput &&
-                              err != ProducerErrorTemplates::kLocalIOError &&
-                              err != ProducerErrorTemplates::kServerWarning
-                             );
+        err != ProducerErrorTemplates::kLocalIOError &&
+        err != ProducerErrorTemplates::kUnsupportedClient &&
+        err != ProducerErrorTemplates::kServerWarning
+    );
 }
 
-bool RequestHandlerTcp::ProcessErrorFromReceiver(const Error& error,
+bool RequestHandlerTcp::ProcessErrorFromReceiver(const Error &error,
                                                  const ProducerRequest* request,
-                                                 const std::string& receiver_uri) {
+                                                 const std::string &receiver_uri) {
     bool is_server_error = ServerError(error);
 
     if (error && error != ProducerErrorTemplates::kServerWarning) {
         Disconnect();
         std::string log_str = "cannot send data, opcode: " + std::to_string(request->header.op_code) +
-                              ", id: " + std::to_string(request->header.data_id) + " to " + receiver_uri + ": " +
-                              error->Explain();
+            ", id: " + std::to_string(request->header.data_id) + " to " + receiver_uri + ": " +
+            error->Explain();
         if (is_server_error) {
             log__->Warning(log_str + ", will try again");
         } else {
@@ -219,24 +223,27 @@ bool RequestHandlerTcp::ProcessErrorFromReceiver(const Error& error,
     return is_server_error;
 }
 
-
 void RequestHandlerTcp::ProcessRequestCallback(Error err, ProducerRequest* request, std::string response, bool* retry) {
     if (request->callback) {
-        request->callback(RequestCallbackPayload{request->header, std::move(request->data),std::move(response)}, std::move(err));
+        request->callback(RequestCallbackPayload{request->header, std::move(request->data), std::move(response)},
+                          std::move(err));
     }
     *retry = false;
 }
 
+bool ImmediateCallbackAfterError(const Error& err) {
+    return err == ProducerErrorTemplates::kWrongInput || err == ProducerErrorTemplates::kUnsupportedClient;
+}
 
 bool RequestHandlerTcp::SendToOneOfTheReceivers(ProducerRequest* request, bool* retry) {
     for (auto receiver_uri : receivers_list_) {
         if (Disconnected()) {
             auto err = ConnectToReceiver(request->source_credentials, receiver_uri);
-            if (err == ProducerErrorTemplates::kWrongInput) {
+            if (ImmediateCallbackAfterError(err)) {
                 ProcessRequestCallback(std::move(err), request, "", retry);
                 return false;
             } else {
-                if (err != nullptr ) {
+                if (err != nullptr) {
                     continue;
                 }
             }
@@ -245,7 +252,7 @@ bool RequestHandlerTcp::SendToOneOfTheReceivers(ProducerRequest* request, bool*
         std::string response;
         auto err = TrySendToReceiver(request, &response);
         bool server_error_can_retry = ProcessErrorFromReceiver(err, request, receiver_uri);
-        if (server_error_can_retry)  {
+        if (server_error_can_retry) {
             continue;
         }
 
@@ -253,13 +260,13 @@ bool RequestHandlerTcp::SendToOneOfTheReceivers(ProducerRequest* request, bool*
         ProcessRequestCallback(std::move(err), request, response, retry);
         return success;
     }
-    log__->Warning((receivers_list_.empty()?std::string("receiver list empty, "):"")+"put back to the queue, request opcode: " + std::to_string(request->header.op_code) +
-                   ", id: " + std::to_string(request->header.data_id));
+    log__->Warning((receivers_list_.empty() ? std::string("receiver list empty, ") : "")
+                       + "put back to the queue, request opcode: " + std::to_string(request->header.op_code) +
+        ", id: " + std::to_string(request->header.data_id));
     *retry = true;
     return false;
 }
 
-
 bool RequestHandlerTcp::ProcessRequestUnlocked(GenericRequest* request, bool* retry) {
     auto producer_request = static_cast<ProducerRequest*>(request);
 
@@ -303,13 +310,14 @@ void RequestHandlerTcp::TearDownProcessingRequestLocked(bool request_processed_s
 void RequestHandlerTcp::ProcessRequestTimeout(GenericRequest* request) {
     auto producer_request = static_cast<ProducerRequest*>(request);
     auto err_string = "request id:" + std::to_string(request->header.data_id) + ", opcode: " + std::to_string(
-                          request->header.op_code) + " for " + request->header.stream +
-                      " stream";
+        request->header.op_code) + " for " + request->header.stream +
+        " stream";
     log__->Error("timeout " + err_string);
 
     auto err = ProducerErrorTemplates::kTimeout.Generate(err_string);
     if (producer_request->callback) {
-        producer_request->callback(RequestCallbackPayload{request->header, std::move(producer_request->data),""}, std::move(err));
+        producer_request->callback(RequestCallbackPayload{request->header, std::move(producer_request->data), ""},
+                                   std::move(err));
     }
 
 }
diff --git a/producer/api/cpp/unittests/test_producer_impl.cpp b/producer/api/cpp/unittests/test_producer_impl.cpp
index bdea491aceec053a3b03579c6e38e01be7c9c3dc..5219352f164def64bf0b0d1c819af0feba464c3d 100644
--- a/producer/api/cpp/unittests/test_producer_impl.cpp
+++ b/producer/api/cpp/unittests/test_producer_impl.cpp
@@ -1,5 +1,3 @@
-#pragma clang diagnostic push
-#pragma ide diagnostic ignored "InfiniteRecursion"
 #include <gtest/gtest.h>
 #include <gmock/gmock.h>
 
@@ -11,6 +9,7 @@
 
 #include "../src/request_handler_tcp.h"
 #include "asapo/request/request_pool_error.h"
+#include "asapo/unittests/MockHttpClient.h"
 
 #include "mocking.h"
 
@@ -26,10 +25,13 @@ using ::testing::Ne;
 using ::testing::Mock;
 using ::testing::InSequence;
 using ::testing::HasSubstr;
+using testing::SetArgPointee;
 
 
 using asapo::RequestPool;
 using asapo::ProducerRequest;
+using asapo::MockHttpClient;
+
 
 MATCHER_P10(M_CheckSendRequest, op_code, source_credentials, metadata, file_id, file_size, message, stream,
             ingest_mode,
@@ -56,6 +58,8 @@ TEST(ProducerImpl, Constructor) {
     asapo::ProducerImpl producer{"", 4, 3600000, asapo::RequestHandlerType::kTcp};
     ASSERT_THAT(dynamic_cast<asapo::AbstractLogger*>(producer.log__), Ne(nullptr));
     ASSERT_THAT(dynamic_cast<asapo::RequestPool*>(producer.request_pool__.get()), Ne(nullptr));
+    ASSERT_THAT(dynamic_cast<const asapo::HttpClient*>(producer.httpclient__.get()), Ne(nullptr));
+
 }
 
 class ProducerImplTests : public testing::Test {
@@ -64,7 +68,8 @@ class ProducerImplTests : public testing::Test {
   asapo::ProducerRequestHandlerFactory factory{&service};
   testing::NiceMock<asapo::MockLogger> mock_logger;
   testing::NiceMock<MockRequestPull> mock_pull{&factory, &mock_logger};
-  asapo::ProducerImpl producer{"", 1, 3600000, asapo::RequestHandlerType::kTcp};
+  std::string expected_server_uri = "test:8400";
+  asapo::ProducerImpl producer{expected_server_uri, 1, 3600000, asapo::RequestHandlerType::kTcp};
   uint64_t expected_size = 100;
   uint64_t expected_id = 10;
   uint64_t expected_dataset_id = 100;
@@ -88,9 +93,15 @@ class ProducerImplTests : public testing::Test {
   std::string expected_fullpath = "filename";
   bool expected_managed_memory = true;
   bool expected_unmanaged_memory = false;
+
+  MockHttpClient* mock_http_client;
+
   void SetUp() override {
       producer.log__ = &mock_logger;
       producer.request_pool__ = std::unique_ptr<RequestPool>{&mock_pull};
+      mock_http_client = new MockHttpClient;
+      producer.httpclient__.reset(mock_http_client);
+
   }
   void TearDown() override {
       producer.request_pool__.release();
@@ -510,8 +521,20 @@ TEST_F(ProducerImplTests, ReturnDataIfCanotAddToQueue) {
 
 }
 
+TEST_F(ProducerImplTests, GetVersionInfoWithServer) {
+
+    std::string result = R"({"softwareVersion":"20.03.1, build 7a9294ad","clientSupported":"no", "clientProtocol":{"versionInfo":"v0.2"}})";
 
+    EXPECT_CALL(*mock_http_client, Get_t(HasSubstr(expected_server_uri + "/asapo-discovery/v0.1/version?client=producer&protocol=v0.1"), _,_)).WillOnce(DoAll(
+        SetArgPointee<1>(asapo::HttpCode::OK),
+        SetArgPointee<2>(nullptr),
+        Return(result)));
 
+    std::string client_info,server_info;
+    auto err = producer.GetVersionInfo(&client_info,&server_info,nullptr);
+    ASSERT_THAT(err, Eq(nullptr));
+    ASSERT_THAT(server_info, HasSubstr("20.03.1"));
+    ASSERT_THAT(server_info, HasSubstr("v0.2"));
 }
 
-#pragma clang diagnostic pop
\ No newline at end of file
+}
diff --git a/producer/api/cpp/unittests/test_producer_request.cpp b/producer/api/cpp/unittests/test_producer_request.cpp
index eb087cfa3b3a4dec67b92d1626c7b0bb58d47ce8..b879fb32833c7dd8bdb911adddd7db9f007a9fc5 100644
--- a/producer/api/cpp/unittests/test_producer_request.cpp
+++ b/producer/api/cpp/unittests/test_producer_request.cpp
@@ -40,6 +40,7 @@ TEST(ProducerRequest, Constructor) {
     uint64_t expected_file_size = 1337;
     uint64_t expected_meta_size = 137;
     std::string expected_meta = "meta";
+    std::string expected_api_version = "v0.1";
     asapo::Opcode expected_op_code = asapo::kOpcodeTransferData;
 
     asapo::GenericRequestHeader header{expected_op_code, expected_file_id, expected_file_size,
@@ -53,7 +54,7 @@ TEST(ProducerRequest, Constructor) {
     ASSERT_THAT(request.header.data_id, Eq(expected_file_id));
     ASSERT_THAT(request.header.op_code, Eq(expected_op_code));
     ASSERT_THAT(request.header.meta_size, Eq(expected_meta_size));
-
+    ASSERT_THAT(request.header.api_version, testing::StrEq(expected_api_version));
 }
 
 
diff --git a/producer/api/cpp/unittests/test_receiver_discovery_service.cpp b/producer/api/cpp/unittests/test_receiver_discovery_service.cpp
index 7000da7d4c01930c3906a9460405e7623140d766..014be20c89dd3d247a2e3d7134c9c43fb5131792 100644
--- a/producer/api/cpp/unittests/test_receiver_discovery_service.cpp
+++ b/producer/api/cpp/unittests/test_receiver_discovery_service.cpp
@@ -48,7 +48,7 @@ class ReceiversStatusTests : public Test {
     NiceMock<asapo::MockLogger> mock_logger;
     NiceMock<MockHttpClient>* mock_http_client;
 
-    std::string expected_endpoint{"endpoint/asapo-discovery/asapo-receiver"};
+    std::string expected_endpoint{"endpoint/asapo-discovery/v0.1/asapo-receiver?protocol=v0.1"};
     ReceiverDiscoveryService status{"endpoint", 20};
 
     void SetUp() override {
diff --git a/producer/api/cpp/unittests/test_request_handler_tcp.cpp b/producer/api/cpp/unittests/test_request_handler_tcp.cpp
index 536aee478111030daf6181ddf82d475b5b8a877e..1d7b812cd1e88df4915b65a83639774ef8ececb8 100644
--- a/producer/api/cpp/unittests/test_request_handler_tcp.cpp
+++ b/producer/api/cpp/unittests/test_request_handler_tcp.cpp
@@ -120,7 +120,7 @@ class RequestHandlerTcpTests : public testing::Test {
   bool retry;
   Sequence seq_receive[2];
   void ExpectFailConnect(bool only_once = false);
-  void ExpectFailAuthorize(bool only_once = false);
+  void ExpectFailAuthorize(asapo::NetworkErrorCode error_code);
   void ExpectOKAuthorize(bool only_once = false);
   void ExpectFailSendHeader(bool only_once = false);
   void ExpectFailSend(uint64_t expected_size, bool only_once);
@@ -191,60 +191,55 @@ void RequestHandlerTcpTests::ExpectFailConnect(bool only_once) {
 
 }
 
-void RequestHandlerTcpTests::ExpectFailAuthorize(bool only_once) {
-    int i = 0;
-    for (auto expected_sd : expected_sds) {
-        EXPECT_CALL(mock_io,
-                    Send_t(expected_sd, M_CheckSendRequest(asapo::kOpcodeAuthorize, 0, 0, "",
-                                                               ""),
-                           sizeof(asapo::GenericRequestHeader), _))
-            .WillOnce(
-                DoAll(
-                    testing::SetArgPointee<3>(nullptr),
-                    Return(sizeof(asapo::GenericRequestHeader))
-                ));
-        EXPECT_CALL(mock_io,
-                    Send_t(expected_sd, _,strlen(expected_beamtime_id), _))
-            .WillOnce(
-                DoAll(
-                    testing::SetArgPointee<3>(nullptr),
-                    Return(strlen(expected_beamtime_id))
-                ));
-
-        EXPECT_CALL(mock_io, Receive_t(expected_sd, _, sizeof(asapo::SendResponse), _))
-            .InSequence(seq_receive[i])
-            .WillOnce(
-                DoAll(
-                    testing::SetArgPointee<3>(nullptr),
-                    A_WriteSendResponse(asapo::kNetAuthorizationError, expected_auth_message),
-                    testing::ReturnArg<2>()
-                ));
-        EXPECT_CALL(mock_io, CloseSocket_t(expected_sd, _));
-        if (only_once) {
-            EXPECT_CALL(mock_logger, Debug(AllOf(
-                HasSubstr("disconnected"),
-                HasSubstr(receivers_list[i])
-                                           )
+void RequestHandlerTcpTests::ExpectFailAuthorize(asapo::NetworkErrorCode error_code) {
+    auto expected_sd = expected_sds[0];
+    EXPECT_CALL(mock_io,
+                Send_t(expected_sd, M_CheckSendRequest(asapo::kOpcodeAuthorize, 0, 0, "",
+                                                       ""),
+                       sizeof(asapo::GenericRequestHeader), _))
+        .WillOnce(
+            DoAll(
+                testing::SetArgPointee<3>(nullptr),
+                Return(sizeof(asapo::GenericRequestHeader))
+            ));
+    EXPECT_CALL(mock_io,
+                Send_t(expected_sd, _, strlen(expected_beamtime_id), _))
+        .WillOnce(
+            DoAll(
+                testing::SetArgPointee<3>(nullptr),
+                Return(strlen(expected_beamtime_id))
             ));
 
-            EXPECT_CALL(mock_logger, Error(AllOf(
-                HasSubstr("authorization"),
-                HasSubstr(expected_auth_message),
-                HasSubstr(receivers_list[i])
-                                           )
+    EXPECT_CALL(mock_io, Receive_t(expected_sd, _, sizeof(asapo::SendResponse), _))
+        .InSequence(seq_receive[0])
+        .WillOnce(
+            DoAll(
+                testing::SetArgPointee<3>(nullptr),
+                A_WriteSendResponse(error_code, expected_auth_message),
+                testing::ReturnArg<2>()
             ));
-        }
-        if (only_once) break;
-        i++;
-    }
+    EXPECT_CALL(mock_io, CloseSocket_t(expected_sd, _));
+    EXPECT_CALL(mock_logger, Debug(AllOf(
+        HasSubstr("disconnected"),
+        HasSubstr(receivers_list[0])
+                                   )
+    ));
+
+    EXPECT_CALL(mock_logger, Error(AllOf(
+        HasSubstr("authorization"),
+        HasSubstr(expected_auth_message),
+        HasSubstr(receivers_list[0])
+                                   )
+    ));
 }
 
+
 void RequestHandlerTcpTests::ExpectOKAuthorize(bool only_once) {
     int i = 0;
     for (auto expected_sd : expected_sds) {
         EXPECT_CALL(mock_io,
                     Send_t(expected_sd, M_CheckSendRequest(asapo::kOpcodeAuthorize, 0, 0, "",
-                                                               ""),
+                                                           ""),
                            sizeof(asapo::GenericRequestHeader), _))
             .WillOnce(
                 DoAll(
@@ -252,7 +247,7 @@ void RequestHandlerTcpTests::ExpectOKAuthorize(bool only_once) {
                     Return(sizeof(asapo::GenericRequestHeader))
                 ));
         EXPECT_CALL(mock_io,
-                    Send_t(expected_sd, _,strlen(expected_beamtime_id), _))
+                    Send_t(expected_sd, _, strlen(expected_beamtime_id), _))
             .WillOnce(
                 DoAll(
                     testing::SetArgPointee<3>(nullptr),
@@ -284,10 +279,10 @@ void RequestHandlerTcpTests::ExpectFailSendHeader(bool only_once) {
     int i = 0;
     for (auto expected_sd : expected_sds) {
         EXPECT_CALL(mock_io, Send_t(expected_sd, M_CheckSendRequest(expected_op_code,
-                                                                        expected_file_id,
-                                                                        expected_file_size,
-                                                                        expected_file_name,
-                                                                        expected_stream),
+                                                                    expected_file_id,
+                                                                    expected_file_size,
+                                                                    expected_file_name,
+                                                                    expected_stream),
                                     sizeof(asapo::GenericRequestHeader), _))
             .WillOnce(
                 DoAll(
@@ -456,10 +451,10 @@ void RequestHandlerTcpTests::ExpectOKSendFile(bool only_once) {
 void RequestHandlerTcpTests::ExpectOKSendHeader(bool only_once, asapo::Opcode opcode) {
     for (auto expected_sd : expected_sds) {
         EXPECT_CALL(mock_io, Send_t(expected_sd, M_CheckSendRequest(opcode,
-                                                                        expected_file_id,
-                                                                        expected_file_size,
-                                                                        expected_file_name,
-                                                                        expected_stream),
+                                                                    expected_file_id,
+                                                                    expected_file_size,
+                                                                    expected_file_name,
+                                                                    expected_stream),
                                     sizeof(asapo::GenericRequestHeader), _))
             .WillOnce(
                 DoAll(
@@ -595,7 +590,7 @@ TEST_F(RequestHandlerTcpTests, TriesConnectWhenNotConnected) {
 
 TEST_F(RequestHandlerTcpTests, FailsWhenCannotAuthorize) {
     ExpectOKConnect(true);
-    ExpectFailAuthorize(true);
+    ExpectFailAuthorize(asapo::kNetAuthorizationError);
 
     request_handler.PrepareProcessingRequestLocked();
     auto success = request_handler.ProcessRequestUnlocked(&request, &retry);
@@ -609,6 +604,21 @@ TEST_F(RequestHandlerTcpTests, FailsWhenCannotAuthorize) {
 
 }
 
+TEST_F(RequestHandlerTcpTests, FailsWhenUnsupportedClient) {
+    ExpectOKConnect(true);
+    ExpectFailAuthorize(asapo::kNetErrorNotSupported);
+
+    request_handler.PrepareProcessingRequestLocked();
+    auto success = request_handler.ProcessRequestUnlocked(&request, &retry);
+    request_handler.TearDownProcessingRequestLocked(success);
+
+    ASSERT_THAT(n_connections, Eq(0));
+    ASSERT_THAT(callback_err, Eq(asapo::ProducerErrorTemplates::kUnsupportedClient));
+    ASSERT_THAT(callback_called, Eq(true));
+    ASSERT_THAT(success, Eq(false));
+    ASSERT_THAT(retry, Eq(false));
+}
+
 TEST_F(RequestHandlerTcpTests, DoesNotTryConnectWhenConnected) {
     DoSingleSend();
 
@@ -768,6 +778,12 @@ TEST_F(RequestHandlerTcpTests, ImmediatelyCallBackErrorIfAuthorizationFailure) {
     AssertImmediatelyCallBack(asapo::kNetAuthorizationError, asapo::ProducerErrorTemplates::kWrongInput);
 }
 
+
+TEST_F(RequestHandlerTcpTests, ImmediatelyCallBackErrorIfNotSupportedfailure) {
+    AssertImmediatelyCallBack(asapo::kNetErrorNotSupported, asapo::ProducerErrorTemplates::kUnsupportedClient);
+}
+
+
 TEST_F(RequestHandlerTcpTests, ImmediatelyCallBackErrorIfWrongMetadata) {
     AssertImmediatelyCallBack(asapo::kNetErrorWrongRequest, asapo::ProducerErrorTemplates::kWrongInput);
 }
diff --git a/producer/api/python/asapo_producer.pxd b/producer/api/python/asapo_producer.pxd
index f35a341c933c0dd447ea318ef8b0bae1936c3e94..cd627b6203aa0e9322625f893d7203dfd392c6a1 100644
--- a/producer/api/python/asapo_producer.pxd
+++ b/producer/api/python/asapo_producer.pxd
@@ -22,6 +22,7 @@ cdef extern from "asapo/asapo_producer.h" namespace "asapo":
   ErrorTemplateInterface kLocalIOError "asapo::ProducerErrorTemplates::kLocalIOError"
   ErrorTemplateInterface kServerWarning "asapo::ProducerErrorTemplates::kServerWarning"
   ErrorTemplateInterface kRequestPoolIsFull "asapo::ProducerErrorTemplates::kRequestPoolIsFull"
+  ErrorTemplateInterface kUnsupportedClient "asapo::ProducerErrorTemplates::kUnsupportedClient"
 
 cdef extern from "asapo/asapo_producer.h" namespace "asapo":
   cppclass MessageData:
@@ -104,6 +105,7 @@ cdef extern from "asapo/asapo_producer.h" namespace "asapo" nogil:
         Error SendStreamFinishedFlag(string stream, uint64_t last_id, string next_stream, RequestCallback callback)
         StreamInfo GetStreamInfo(string stream, uint64_t timeout_ms, Error* err)
         StreamInfo GetLastStream(uint64_t timeout_ms, Error* err)
+        Error GetVersionInfo(string* client_info,string* server_info, bool* supported)
 
 
 cdef extern from "asapo/asapo_producer.h" namespace "asapo":
diff --git a/producer/api/python/asapo_producer.pyx.in b/producer/api/python/asapo_producer.pyx.in
index e40d7a5c9e233f7fab8e14802e2cf828ea0f2e23..5391c8ce8ea41e3eada8ad182b8e4cc755d3feb1 100644
--- a/producer/api/python/asapo_producer.pyx.in
+++ b/producer/api/python/asapo_producer.pyx.in
@@ -54,6 +54,9 @@ class AsapoServerWarning(AsapoProducerError):
 class AsapoRequestsPoolIsFull(AsapoProducerError):
   pass
 
+class AsapoUnsupportedClientError(AsapoProducerError):
+  pass
+
 cdef python_exception_from_error(Error& err):
     error_string =  _str(err.get().Explain())
     if err == kTimeout:
@@ -66,6 +69,8 @@ cdef python_exception_from_error(Error& err):
             return AsapoServerWarning(error_string)
     elif err == kRequestPoolIsFull:
             return AsapoRequestsPoolIsFull(error_string)
+    elif err == kUnsupportedClient:
+            raise AsapoUnsupportedClientError(error_string)
     else:
         return AsapoProducerError(error_string)
 
@@ -110,7 +115,21 @@ cdef class PyProducer:
             print("wrong loglevel mode: "+ level)
             return
          self.c_producer.get().SetLogLevel(log_level)
-
+    def get_version_info(self, from_server = "true"):
+        cdef string client_info,server_info
+        cdef bool supported
+        cdef string* p_server_info =  &server_info if from_server else <string*>NULL
+        cdef bool* p_supported =  &supported if from_server else <bool*>NULL
+        cdef Error err
+        with nogil:
+                err =  self.c_producer.get().GetVersionInfo(&client_info,p_server_info,p_supported)
+        if err:
+            throw_exception(err)
+        version = {}
+        if from_server:
+            return {'client': _str(client_info), 'server': _str(server_info), 'supported': supported}
+        else:
+            return {'client': _str(client_info)}
     def __send_np_array(self, id, exposed_path,data, user_meta=None,dataset=None,stream="default",ingest_mode = DEFAULT_INGEST_MODE,callback=None):
         cdef MessageHeader message_header = self.create_message_header(id,exposed_path,user_meta,dataset,ingest_mode)
         if data is None:
diff --git a/producer/event_monitor_producer/src/main_eventmon.cpp b/producer/event_monitor_producer/src/main_eventmon.cpp
index d30e479a8bf6e8af518b818ee0aa4cc8accaf040..72446fa522c48bbdd9724fedc639985874afe1ae 100644
--- a/producer/event_monitor_producer/src/main_eventmon.cpp
+++ b/producer/event_monitor_producer/src/main_eventmon.cpp
@@ -15,7 +15,7 @@
 #include "asapo/preprocessor/definitions.h"
 
 #include "asapo/io/io_factory.h"
-#include "asapo/common/version.h"
+#include "asapo/common/internal/version.h"
 
 using asapo::Producer;
 using asapo::EventMonConfigFactory;
diff --git a/receiver/src/main.cpp b/receiver/src/main.cpp
index 2f119b2005f4e68a7983b4be247874df7217e735..e00c94fbd97b8e9047bb34d52c49c18cf9b92546 100644
--- a/receiver/src/main.cpp
+++ b/receiver/src/main.cpp
@@ -6,7 +6,7 @@
 #include "receiver_config.h"
 
 #include "receiver_data_server/receiver_data_server_logger.h"
-#include "asapo/common/version.h"
+#include "asapo/common/internal/version.h"
 
 #include "receiver_data_server/receiver_data_server.h"
 #include "receiver_data_server/net_server/rds_tcp_server.h"
diff --git a/receiver/src/receiver_config.cpp b/receiver/src/receiver_config.cpp
index 82383d3d2b32461fe8c418e71c31438e87ef7495..78052168bdddcce8578809b13d266fb6f4cd9818 100644
--- a/receiver/src/receiver_config.cpp
+++ b/receiver/src/receiver_config.cpp
@@ -19,6 +19,7 @@ Error ReceiverConfigFactory::SetConfig(std::string file_name) {
     Error err;
 
     (err = parser.GetString("PerformanceDbServer", &config.performance_db_uri)) ||
+    (err = parser.GetBool("MonitorPerformance", &config.monitor_performance)) ||
     (err = parser.GetUInt64("ListenPort", &config.listen_port)) ||
     (err = parser.GetUInt64("ReceiveToDiskThresholdMB", &config.receive_to_disk_threshold_mb)) ||
     (err = parser.Embedded("DataServer").GetUInt64("ListenPort", &config.dataserver.listen_port)) ||
diff --git a/receiver/src/receiver_config.h b/receiver/src/receiver_config.h
index 74316f7e6449af6fc9dface08d59876329065774..c8128362a7e1d51075f54d327aab620dc35f6fb5 100644
--- a/receiver/src/receiver_config.h
+++ b/receiver/src/receiver_config.h
@@ -11,6 +11,7 @@ namespace asapo {
 struct ReceiverConfig {
     std::string performance_db_uri;
     std::string performance_db_name;
+    bool monitor_performance = false;
     std::string database_uri;
     uint64_t listen_port = 0;
     std::string authorization_server;
diff --git a/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.cpp b/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.cpp
index 82165357d48d7fdb3985b28eed9cdb9ca00d7d1e..0f8f387faf1d2bd20490a4e6b409612b1c81e81d 100644
--- a/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.cpp
+++ b/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.cpp
@@ -1,7 +1,7 @@
 #include "receiver_data_server_request_handler.h"
 
 #include "../receiver_data_server_error.h"
-
+#include "asapo/common/internal/version.h"
 namespace asapo {
 
 ReceiverDataServerRequestHandler::ReceiverDataServerRequestHandler(RdsNetServer* server,
@@ -11,8 +11,19 @@ ReceiverDataServerRequestHandler::ReceiverDataServerRequestHandler(RdsNetServer*
 }
 
 
-bool ReceiverDataServerRequestHandler::CheckRequest(const ReceiverDataServerRequest* request) {
-    return  request->header.op_code == kOpcodeGetBufferData;
+bool ReceiverDataServerRequestHandler::CheckRequest(const ReceiverDataServerRequest* request,NetworkErrorCode* code) {
+    if (request->header.op_code != kOpcodeGetBufferData) {
+        *code = kNetErrorWrongRequest;
+        return false;
+    }
+    int verClient = VersionToNumber(request->header.api_version);
+    int verService = VersionToNumber(GetRdsApiVersion());
+    if (verClient > verService) {
+        *code = kNetErrorNotSupported;
+        return false;
+    }
+
+    return true;
 }
 
 Error ReceiverDataServerRequestHandler::SendResponse(const ReceiverDataServerRequest* request, NetworkErrorCode code) {
@@ -45,8 +56,9 @@ CacheMeta* ReceiverDataServerRequestHandler::GetSlotAndLock(const ReceiverDataSe
 bool ReceiverDataServerRequestHandler::ProcessRequestUnlocked(GenericRequest* request, bool* retry) {
     *retry = false;
     auto receiver_request = dynamic_cast<ReceiverDataServerRequest*>(request);
-    if (!CheckRequest(receiver_request)) {
-        HandleInvalidRequest(receiver_request);
+    NetworkErrorCode code;
+    if (!CheckRequest(receiver_request,&code)) {
+        HandleInvalidRequest(receiver_request,code);
         return true;
     }
 
@@ -78,10 +90,18 @@ void ReceiverDataServerRequestHandler::ProcessRequestTimeout(GenericRequest* /*r
 // do nothing
 }
 
-void ReceiverDataServerRequestHandler::HandleInvalidRequest(const ReceiverDataServerRequest* receiver_request) {
-    SendResponse(receiver_request, kNetErrorWrongRequest);
+void ReceiverDataServerRequestHandler::HandleInvalidRequest(const ReceiverDataServerRequest* receiver_request,NetworkErrorCode code) {
+    SendResponse(receiver_request, code);
     server_->HandleAfterError(receiver_request->source_id);
-    log__->Error("wrong request, code:" + std::to_string(receiver_request->header.op_code));
+    switch (code) {
+        case NetworkErrorCode::kNetErrorWrongRequest:
+            log__->Error("wrong request, code:" + std::to_string(receiver_request->header.op_code));
+            break;
+        case NetworkErrorCode::kNetErrorNotSupported:
+            log__->Error("unsupported client, version: " + std::string(receiver_request->header.api_version));
+            break;
+    };
+
 }
 
 void ReceiverDataServerRequestHandler::HandleValidRequest(const ReceiverDataServerRequest* receiver_request,
diff --git a/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.h b/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.h
index 10c6633bd6963a18413bba8698a240bf89dcd7d0..18fc5937a793c9358376d24ec0480496ce93e88a 100644
--- a/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.h
+++ b/receiver/src/receiver_data_server/request_handler/receiver_data_server_request_handler.h
@@ -24,12 +24,12 @@ class ReceiverDataServerRequestHandler: public RequestHandler {
   private:
     RdsNetServer* server_;
     DataCache* data_cache_;
-    bool CheckRequest(const ReceiverDataServerRequest* request);
+    bool CheckRequest(const ReceiverDataServerRequest* request,NetworkErrorCode* code);
     Error SendResponse(const ReceiverDataServerRequest* request, NetworkErrorCode code);
     Error SendResponseAndSlotData(const ReceiverDataServerRequest* request, const CacheMeta* meta);
     CacheMeta* GetSlotAndLock(const ReceiverDataServerRequest* request);
 
-    void HandleInvalidRequest(const ReceiverDataServerRequest* receiver_request);
+    void HandleInvalidRequest(const ReceiverDataServerRequest* receiver_request,NetworkErrorCode code);
 
     void HandleValidRequest(const ReceiverDataServerRequest* receiver_request, const CacheMeta* meta);
 };
diff --git a/receiver/src/receiver_error.h b/receiver/src/receiver_error.h
index 3e30c4fd28a08c7a4fd8768cfae7ee89c20c3dd0..210c116cadfa8d9b1f64f2894cc014ec7355bbd2 100644
--- a/receiver/src/receiver_error.h
+++ b/receiver/src/receiver_error.h
@@ -11,7 +11,8 @@ enum class ReceiverErrorType {
     kAuthorizationFailure,
     kInternalServerError,
     kReAuthorizationFailure,
-    kWarningDuplicatedRequest
+    kWarningDuplicatedRequest,
+    kUnsupportedClient
 };
 
 using ReceiverErrorTemplate = ServiceErrorTemplate<ReceiverErrorType, ErrorType::kReceiverError>;
@@ -41,6 +42,13 @@ auto const kAuthorizationFailure = ReceiverErrorTemplate {
     "authorization failure", ReceiverErrorType::kAuthorizationFailure
 };
 
+auto const kUnsupportedClient = ReceiverErrorTemplate {
+    "client version not supported", ReceiverErrorType::kUnsupportedClient
+};
+
+
+
+
 auto const kReAuthorizationFailure = ReceiverErrorTemplate {
     "reauthorization for auto beamtime failed", ReceiverErrorType::kReAuthorizationFailure
 };
diff --git a/receiver/src/request.cpp b/receiver/src/request.cpp
index 5bf9c1ab2cbdd38f9c0dd8339e0a86912bc163b6..7db51dfd02f8aa91f097ecab8bfdb8747f9e3add 100644
--- a/receiver/src/request.cpp
+++ b/receiver/src/request.cpp
@@ -89,6 +89,11 @@ std::string Request::GetStream() const {
     return request_header_.stream;
 }
 
+std::string Request::GetApiVersion() const {
+    return request_header_.api_version;
+}
+
+
 const std::string& Request::GetOriginUri() const {
     return origin_uri_;
 }
diff --git a/receiver/src/request.h b/receiver/src/request.h
index f24ad10fcc1927e69e80a2edf91a64efbc73cc26..141430e7748b09ee46c1c596d3efa2c992e59759 100644
--- a/receiver/src/request.h
+++ b/receiver/src/request.h
@@ -44,6 +44,7 @@ class Request {
     VIRTUAL uint64_t GetDataID() const;
     VIRTUAL std::string GetFileName() const;
     VIRTUAL std::string GetStream() const;
+    VIRTUAL std::string GetApiVersion() const;
     VIRTUAL void* GetData() const;
     VIRTUAL Opcode GetOpCode() const;
     VIRTUAL const char* GetMessage() const;
diff --git a/receiver/src/request_handler/request_handler_authorize.cpp b/receiver/src/request_handler/request_handler_authorize.cpp
index ca67af48f9d62783e61e3abeb915da7eea09e1a8..314b351a46acf31fc5ef08312a4ee989523fc2a8 100644
--- a/receiver/src/request_handler/request_handler_authorize.cpp
+++ b/receiver/src/request_handler/request_handler_authorize.cpp
@@ -4,6 +4,7 @@
 #include "../request.h"
 
 #include "asapo/json_parser/json_parser.h"
+#include "asapo/common/internal/version.h"
 
 using std::chrono::system_clock;
 
@@ -83,6 +84,17 @@ Error RequestHandlerAuthorize::Authorize(Request* request, const char* source_cr
     return nullptr;
 }
 
+Error RequestHandlerAuthorize::CheckVersion(const std::string& version_from_client) const {
+    int verClient = VersionToNumber(version_from_client);
+    int verService = VersionToNumber(GetReceiverApiVersion());
+    if (verClient > verService) {
+        auto err_string = "client version: "+version_from_client + ", server version: "+GetReceiverApiVersion();
+        return asapo::ReceiverErrorTemplates::kUnsupportedClient.Generate(err_string);
+        log__->Error("failure serving client - unsupported version,  " + err_string);
+    }
+    return nullptr;
+}
+
 Error RequestHandlerAuthorize::ProcessAuthorizationRequest(Request* request) const {
     if (!cached_source_credentials_.empty()) {
         Error auth_error = asapo::ReceiverErrorTemplates::kAuthorizationFailure.Generate();
@@ -92,6 +104,12 @@ Error RequestHandlerAuthorize::ProcessAuthorizationRequest(Request* request) con
         return auth_error;
     }
 
+    auto err = CheckVersion(request->GetApiVersion());
+    if (err) {
+        log__->Error("failure authorizing at client: " + err->Explain());
+        return err;
+    }
+
     return Authorize(request, request->GetMetaData().c_str());
 }
 
diff --git a/receiver/src/request_handler/request_handler_authorize.h b/receiver/src/request_handler/request_handler_authorize.h
index 1798ea8fb31de1e8d0e99459bcf447b2763085ea..3e5e44c31fb985c58aceeb5c50c65a88ad01b89d 100644
--- a/receiver/src/request_handler/request_handler_authorize.h
+++ b/receiver/src/request_handler/request_handler_authorize.h
@@ -35,6 +35,8 @@ class RequestHandlerAuthorize final: public ReceiverRequestHandler {
     Error ProcessReAuthorization(Request* request) const;
     bool NeedReauthorize() const;
     std::string GetRequestString(const Request* request, const char* source_credentials) const;
+    Error CheckVersion(const std::string& version_from_client) const;
+
 };
 
 }
diff --git a/receiver/src/request_handler/requests_dispatcher.cpp b/receiver/src/request_handler/requests_dispatcher.cpp
index 7debacf5013ee5c1fdc16dba815f52ad6a7f864e..2487f2d70ce0d86c4a325e7a7ae0236277a14152 100644
--- a/receiver/src/request_handler/requests_dispatcher.cpp
+++ b/receiver/src/request_handler/requests_dispatcher.cpp
@@ -18,6 +18,8 @@ NetworkErrorCode GetNetworkCodeFromError(const Error& err) {
     if (err) {
         if (err == ReceiverErrorTemplates::kAuthorizationFailure) {
             return NetworkErrorCode::kNetAuthorizationError;
+        } else if (err == ReceiverErrorTemplates::kUnsupportedClient) {
+            return NetworkErrorCode::kNetErrorNotSupported;
         } else if (err == ReceiverErrorTemplates::kReAuthorizationFailure) {
             return NetworkErrorCode::kNetErrorReauthorize;
         } else if (err == DBErrorTemplates::kJsonParseError || err == ReceiverErrorTemplates::kBadRequest) {
diff --git a/receiver/src/statistics/statistics.cpp b/receiver/src/statistics/statistics.cpp
index b35da64b1c6007ee9fda78bc1b55339a81db4bba..4549f1bc43f8d45376f55220f86efb2bed5532b2 100644
--- a/receiver/src/statistics/statistics.cpp
+++ b/receiver/src/statistics/statistics.cpp
@@ -1,7 +1,7 @@
 #include "statistics.h"
 #include "statistics_sender_influx_db.h"
 #include "statistics_sender_fluentd.h"
-
+#include "../receiver_config.h"
 #include <algorithm>
 
 using std::chrono::system_clock;
@@ -9,6 +9,9 @@ using std::chrono::system_clock;
 namespace asapo {
 
 void Statistics::SendIfNeeded(bool send_always) noexcept {
+    if (!GetReceiverConfig()->monitor_performance) {
+        return;
+    }
     if (send_always || GetTotalElapsedMs() > write_interval_) {
         std::lock_guard<std::mutex> lock{mutex_};
         Send();
diff --git a/receiver/unittests/mock_receiver_config.cpp b/receiver/unittests/mock_receiver_config.cpp
index 916f026baa7d64b274d65ee810ca8fe2f230c25b..17e236cbdd665969a80682f1e62e50e49e987430 100644
--- a/receiver/unittests/mock_receiver_config.cpp
+++ b/receiver/unittests/mock_receiver_config.cpp
@@ -44,6 +44,7 @@ Error SetReceiverConfig (const ReceiverConfig& config, std::string error_field)
     auto config_string = std::string("{") + Key("PerformanceDbServer",
                                                 error_field) + "\"" + config.performance_db_uri + "\"";
     config_string += "," + Key("PerformanceDbName", error_field) + "\"" + config.performance_db_name + "\"";
+    config_string += "," + Key("MonitorPerformance", error_field) + (config.monitor_performance?"true":"false");
     config_string += "," + Key("DatabaseServer", error_field) + "\"" + config.database_uri + "\"";
     config_string += "," + Key("DiscoveryServer", error_field) + "\"" + config.discovery_server + "\"";
     config_string += "," + Key("ListenPort", error_field) + std::to_string(config.listen_port);
diff --git a/receiver/unittests/receiver_data_server/request_handler/test_request_handler.cpp b/receiver/unittests/receiver_data_server/request_handler/test_request_handler.cpp
index eedc2f99fd39f534183c4b9256eb16782c6d3791..e5c495b00a1d7b9c8663f7fd48be97487c95aadc 100644
--- a/receiver/unittests/receiver_data_server/request_handler/test_request_handler.cpp
+++ b/receiver/unittests/receiver_data_server/request_handler/test_request_handler.cpp
@@ -122,6 +122,18 @@ TEST_F(RequestHandlerTests, ProcessRequest_WrongOpCode) {
     ASSERT_THAT(success, Eq(true));
 }
 
+TEST_F(RequestHandlerTests, ProcessRequest_WrongClientVersion) {
+    strcpy(request.header.api_version,"v0.2");
+    MockSendResponse(asapo::kNetErrorNotSupported, false);
+    EXPECT_CALL(mock_net, HandleAfterError_t(expected_source_id));
+
+    EXPECT_CALL(mock_logger, Error(HasSubstr("unsupported client")));
+
+    auto success = handler.ProcessRequestUnlocked(&request, &retry);
+
+    ASSERT_THAT(success, Eq(true));
+}
+
 TEST_F(RequestHandlerTests, ProcessRequest_ReturnsNoDataWhenCacheNotUsed) {
     MockSendResponse(asapo::kNetErrorNoData, true);
 
diff --git a/receiver/unittests/receiver_mocking.h b/receiver/unittests/receiver_mocking.h
index 200aeed190a32fbf9b8b958b87723928e11be734..8711a6e70ce6a0bcc26173113891188d3313e197 100644
--- a/receiver/unittests/receiver_mocking.h
+++ b/receiver/unittests/receiver_mocking.h
@@ -66,6 +66,7 @@ class MockRequest: public Request {
 
     MOCK_CONST_METHOD0(GetFileName, std::string());
     MOCK_CONST_METHOD0(GetStream, std::string());
+    MOCK_CONST_METHOD0(GetApiVersion, std::string());
     MOCK_CONST_METHOD0(GetDataSize, uint64_t());
     MOCK_CONST_METHOD0(GetDataID, uint64_t());
     MOCK_CONST_METHOD0(GetSlotId, uint64_t());
diff --git a/receiver/unittests/request_handler/test_request_handler_authorizer.cpp b/receiver/unittests/request_handler/test_request_handler_authorizer.cpp
index c79ec92c965b441454fe60d8cc7bf66a18976c04..e34fa8423a744a1a93a38e8152fac7fa1cd6dae7 100644
--- a/receiver/unittests/request_handler/test_request_handler_authorizer.cpp
+++ b/receiver/unittests/request_handler/test_request_handler_authorizer.cpp
@@ -72,6 +72,8 @@ class AuthorizerHandlerTests : public Test {
     std::string expected_authorization_server = "authorizer_host";
     std::string expect_request_string;
     std::string expected_source_credentials;
+    std::string expected_api_version = "v0.1";
+
     asapo::SourceType expected_source_type = asapo::SourceType::kProcessed;
     std::string expected_source_type_str = "processed";
     std::string expected_access_type_str = "[\"write\"]";
@@ -150,6 +152,11 @@ class AuthorizerHandlerTests : public Test {
         .WillOnce(ReturnRef(expected_source_credentials))
         ;
 
+        EXPECT_CALL(*mock_request, GetApiVersion())
+            .WillOnce(Return(expected_api_version))
+            ;
+
+
         MockAuthRequest(error, code);
         return handler.ProcessRequest(mock_request.get());
     }
@@ -267,6 +274,20 @@ TEST_F(AuthorizerHandlerTests, RequestAuthorizeReturnsDifferentBeamtimeId) {
 }
 
 
+TEST_F(AuthorizerHandlerTests, RequestFromUnsupportedClient) {
+    EXPECT_CALL(*mock_request, GetOpCode())
+        .WillOnce(Return(asapo::kOpcodeAuthorize))
+        ;
+    EXPECT_CALL(*mock_request, GetApiVersion())
+        .WillOnce(Return("v0.2"))
+        ;
+
+    auto err = handler.ProcessRequest(mock_request.get());
+    ASSERT_THAT(err, Eq(asapo::ReceiverErrorTemplates::kUnsupportedClient));
+}
+
+
+
 
 TEST_F(AuthorizerHandlerTests, DataTransferRequestAuthorizeUsesCachedValue) {
     config.authorization_interval_ms = 10000;
diff --git a/receiver/unittests/request_handler/test_requests_dispatcher.cpp b/receiver/unittests/request_handler/test_requests_dispatcher.cpp
index e5d6daaf0354bcd3a9a40f0cd5de60674bf06152..b03fc381186651da8185d8722c8f77c233547b08 100644
--- a/receiver/unittests/request_handler/test_requests_dispatcher.cpp
+++ b/receiver/unittests/request_handler/test_requests_dispatcher.cpp
@@ -294,6 +294,17 @@ TEST_F(RequestsDispatcherTests, ProcessRequestReturnsAuthorizationFailure) {
     ASSERT_THAT(std::string(response.message), HasSubstr("authorization"));
 }
 
+TEST_F(RequestsDispatcherTests, ProcessRequestReturnsUnsupportedClientFailure) {
+    MockHandleRequest(1, asapo::ReceiverErrorTemplates::kUnsupportedClient.Generate());
+    MockSendResponse(&response, false);
+
+    auto err = dispatcher->ProcessRequest(request);
+
+    ASSERT_THAT(err, Eq(asapo::ReceiverErrorTemplates::kUnsupportedClient));
+    ASSERT_THAT(response.error_code, Eq(asapo::kNetErrorNotSupported));
+    ASSERT_THAT(std::string(response.message), HasSubstr("supported"));
+}
+
 TEST_F(RequestsDispatcherTests, ProcessRequestReturnsReAuthorizationFailure) {
     MockHandleRequest(2, asapo::ReceiverErrorTemplates::kReAuthorizationFailure.Generate());
     MockSendResponse(&response, false);
diff --git a/receiver/unittests/statistics/test_statistics.cpp b/receiver/unittests/statistics/test_statistics.cpp
index 4f871e4118a19888ce2acb345e7e5edf7860966d..d31c2282f79c87b6c5d5ce4800888a0495443f69 100644
--- a/receiver/unittests/statistics/test_statistics.cpp
+++ b/receiver/unittests/statistics/test_statistics.cpp
@@ -7,6 +7,9 @@
 #include "../../src/statistics/statistics_sender_influx_db.h"
 #include "../../src/statistics/statistics_sender_fluentd.h"
 #include "../receiver_mocking.h"
+#include "../../src/receiver_config.h"
+#include "../../src/receiver_config_factory.h"
+#include "../mock_receiver_config.h"
 
 using ::testing::Test;
 using ::testing::Gt;
@@ -41,6 +44,9 @@ class StatisticTests : public Test {
     Statistics statistics{0};
     MockStatisticsSender mock_statistics_sender;
     void SetUp() override {
+        asapo::ReceiverConfig test_config;
+        test_config.monitor_performance = true;
+        asapo::SetReceiverConfig(test_config, "none");
         statistics.statistics_sender_list__.clear();
         statistics.statistics_sender_list__.emplace_back(&mock_statistics_sender);
     }
@@ -156,6 +162,16 @@ TEST_F(StatisticTests, SendStaticsDoesCallsSender) {
 }
 
 
+TEST_F(StatisticTests, DoNotSendStatistics) {
+    asapo::ReceiverConfig test_config;
+    test_config.monitor_performance = false;
+    asapo::SetReceiverConfig(test_config, "none");
+
+    EXPECT_CALL(mock_statistics_sender, SendStatistics_t(_)).Times(0);
+
+    statistics.SendIfNeeded(true);
+}
+
 TEST_F(StatisticTests, StatisticsSend) {
     statistics.IncreaseRequestCounter();
 
diff --git a/receiver/unittests/test_config.cpp b/receiver/unittests/test_config.cpp
index e654b439b2a44e231fd8405f034cd467830958d5..06c7c2ddf1f26860b168618ce6f48c4bfdb3d7c1 100644
--- a/receiver/unittests/test_config.cpp
+++ b/receiver/unittests/test_config.cpp
@@ -48,6 +48,7 @@ class ConfigTests : public Test {
         test_config.tag = "receiver1";
         test_config.performance_db_name = "db_test";
         test_config.performance_db_uri = "localhost:8086";
+        test_config.monitor_performance = true;
         test_config.database_uri = "localhost:27017";
         test_config.log_level = asapo::LogLevel::Error;
         test_config.authorization_interval_ms = 10000;
@@ -84,6 +85,7 @@ TEST_F(ConfigTests, ReadSettings) {
     ASSERT_THAT(config->log_level, Eq(asapo::LogLevel::Error));
     ASSERT_THAT(config->tag, Eq("receiver1"));
     ASSERT_THAT(config->use_datacache, Eq(false));
+    ASSERT_THAT(config->monitor_performance, Eq(true));
     ASSERT_THAT(config->datacache_reserved_share, Eq(10));
     ASSERT_THAT(config->datacache_size_gb, Eq(2));
     ASSERT_THAT(config->discovery_server, Eq("discovery"));
@@ -104,7 +106,7 @@ TEST_F(ConfigTests, ErrorReadSettings) {
     std::vector<std::string>fields {"PerformanceDbServer", "ListenPort", "DataServer", "ListenPort",
                                     "DataCache", "Use", "SizeGB", "ReservedShare", "DatabaseServer", "Tag",
                                     "AuthorizationServer", "AuthorizationInterval", "PerformanceDbName", "LogLevel",
-                                    "NThreads", "DiscoveryServer", "AdvertiseURI", "NetworkMode",
+                                    "NThreads", "DiscoveryServer", "AdvertiseURI", "NetworkMode","MonitorPerformance",
                                     "ReceiveToDiskThresholdMB"};
     for (const auto& field : fields) {
         auto err = asapo::SetReceiverConfig(test_config, field);
diff --git a/receiver/unittests/test_request.cpp b/receiver/unittests/test_request.cpp
index cea29e89dc78ee98dc004c9452cb33ac1ca40e96..00d724c03d6b1522b7fecb9133f19a363f95c565 100644
--- a/receiver/unittests/test_request.cpp
+++ b/receiver/unittests/test_request.cpp
@@ -83,6 +83,7 @@ class RequestTests : public Test {
     uint64_t expected_metadata_size = expected_metadata.size();
     asapo::Opcode expected_op_code = asapo::kOpcodeTransferData;
     char expected_request_message[asapo::kMaxMessageSize] = "test_message";
+    std::string expected_api_version = "v0.1";
     std::unique_ptr<Request> request;
     NiceMock<MockIO> mock_io;
     NiceMock<MockStatistics> mock_statistics;
@@ -96,6 +97,7 @@ class RequestTests : public Test {
         generic_request_header.op_code = expected_op_code;
         generic_request_header.custom_data[asapo::kPosIngestMode] = asapo::kDefaultIngestMode;
         strcpy(generic_request_header.message, expected_request_message);
+        strcpy(generic_request_header.api_version, expected_api_version.c_str());
         request.reset(new Request{generic_request_header, expected_socket_id, expected_origin_uri, nullptr, nullptr});
         request->io__ = std::unique_ptr<asapo::IO> {&mock_io};
         ON_CALL(mock_io, Receive_t(expected_socket_id, _, data_size_, _)).WillByDefault(
@@ -157,6 +159,11 @@ TEST_F(RequestTests, GetRequestMessage) {
     ASSERT_THAT(message, testing::StrEq(expected_request_message));
 }
 
+TEST_F(RequestTests, GetApiVersion) {
+    auto ver = request->GetApiVersion();
+    ASSERT_THAT(ver, testing::Eq(expected_api_version));
+}
+
 
 TEST_F(RequestTests, GetOriginUri) {
     auto uri = request->GetOriginUri();
diff --git a/tests/automatic/broker/check_monitoring/check_linux.sh b/tests/automatic/broker/check_monitoring/check_linux.sh
index a9c64328bb00c0de187b3ffed01009a7bf3f0c1b..35ab4eb7cfe57f6c7243b3fb2a9a99aee36e3191 100644
--- a/tests/automatic/broker/check_monitoring/check_linux.sh
+++ b/tests/automatic/broker/check_monitoring/check_linux.sh
@@ -33,16 +33,16 @@ sleep 0.3
 
 brokerid=`echo $!`
 
-groupid=`curl -d '' --silent 127.0.0.1:5005/creategroup`
+groupid=`curl -d '' --silent 127.0.0.1:5005/v0.1/creategroup`
 
 
 for i in `seq 1 50`;
 do
-    curl --silent 127.0.0.1:5005/database/data/source/stream/${groupid}/next?token=$token >/dev/null 2>&1 &
+    curl --silent 127.0.0.1:5005/v0.1/beamtime/data/source/stream/${groupid}/next?token=$token >/dev/null 2>&1 &
 done
 
 
-sleep 3
+sleep 12
 
 influx -execute "select sum(rate) from RequestsRate" -database=${database_name} -format=json | jq .results[0].series[0].values[0][1] | tee /dev/stderr | grep 51
 
diff --git a/tests/automatic/broker/get_last/check_linux.sh b/tests/automatic/broker/get_last/check_linux.sh
index b40aad08881ca2b7ee0c34b53716deec9e30f06b..842fc91a96ccef7259992f2a555800da5742e8cb 100644
--- a/tests/automatic/broker/get_last/check_linux.sh
+++ b/tests/automatic/broker/get_last/check_linux.sh
@@ -31,23 +31,23 @@ sleep 0.3
 brokerid=`echo $!`
 
 
-groupid=`curl -d '' --silent 127.0.0.1:5005/creategroup`
+groupid=`curl -d '' --silent 127.0.0.1:5005/v0.1/creategroup`
 
-curl -v  --silent 127.0.0.1:5005/database/data/detector/${stream}/0/last?token=$token --stderr -
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/0/last?token=$token --stderr -
 
-curl -v  --silent 127.0.0.1:5005/database/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":2'
-curl -v  --silent 127.0.0.1:5005/database/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":2'
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":2'
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":2'
 
 echo "db.data_${stream}.insert({"_id":3})" | mongo ${database_name}
 
-curl -v  --silent 127.0.0.1:5005/database/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":3'
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":3'
 
 echo "db.data_${stream}.insert({"_id":4})" | mongo ${database_name}
 
-curl -v  --silent 127.0.0.1:5005/database/data/detector/${stream}/${groupid}/next?token=$token --stderr - | grep '"_id":1'
-curl -v  --silent 127.0.0.1:5005/database/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":4'
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/${groupid}/next?token=$token --stderr - | grep '"_id":1'
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":4'
 
 #with a new group
-groupid=`curl -d '' --silent 127.0.0.1:5005/creategroup`
-curl -v  --silent 127.0.0.1:5005/database/data/detector/${stream}/${groupid}/next?token=$token --stderr - | grep '"_id":1'
-curl -v  --silent 127.0.0.1:5005/database/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":4'
\ No newline at end of file
+groupid=`curl -d '' --silent 127.0.0.1:5005/v0.1/creategroup`
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/${groupid}/next?token=$token --stderr - | grep '"_id":1'
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/${stream}/0/last?token=$token --stderr - | grep '"_id":4'
\ No newline at end of file
diff --git a/tests/automatic/broker/get_last/check_windows.bat b/tests/automatic/broker/get_last/check_windows.bat
index 580140b410aec1549d06fe16bd19a499a706a980..497384df3d5af7eb9fac5d7419042187ec850066 100644
--- a/tests/automatic/broker/get_last/check_windows.bat
+++ b/tests/automatic/broker/get_last/check_windows.bat
@@ -9,34 +9,34 @@ set short_name="%~nx1"
 
 c:\opt\consul\nomad run authorizer.nmd
 c:\opt\consul\nomad run nginx.nmd
-ping 192.0.2.1 -n 1 -w 3000 > nul
+start /B "" "%full_name%" -config settings.json
+
+ping 192.0.2.1 -n 1 -w 5000 > nul
 
 
 set token=%BT_DATA_TOKEN%
 
-start /B "" "%full_name%" -config settings.json
-ping 192.0.2.1 -n 1 -w 1000 > nul
 
-C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/creategroup > groupid
+C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/v0.1/creategroup > groupid
 set /P groupid=< groupid
 
 
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":2  || goto :error
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":2  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":2  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":2  || goto :error
 
 echo db.data_default.insert({"_id":3}) | %mongo_exe% %database_name%  || goto :error
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":3  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":3  || goto :error
 
 echo db.data_default.insert({"_id":4}) | %mongo_exe% %database_name%  || goto :error
 
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/detector/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1  || goto :error
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":4  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":4  || goto :error
 
 
-C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/creategroup > groupid
+C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/v0.1/creategroup > groupid
 set /P groupid=< groupid
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/detector/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1  || goto :error
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":4  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/last?token=%token% --stderr - | findstr /c:\"_id\":4  || goto :error
 
 
 goto :clean
diff --git a/tests/automatic/broker/get_meta/check_linux.sh b/tests/automatic/broker/get_meta/check_linux.sh
index 2130592555500717d6b207f57817636455a0bd8a..ba084cc02db68612ef667a54c4859060c512f17e 100644
--- a/tests/automatic/broker/get_meta/check_linux.sh
+++ b/tests/automatic/broker/get_meta/check_linux.sh
@@ -29,6 +29,6 @@ $1 -config settings.json &
 sleep 0.3
 brokerid=`echo $!`
 
-curl -v  --silent 127.0.0.1:5005/database/test/detector/default/0/meta/0?token=$token --stderr - | tee /dev/stderr | grep '"data":"test"'
-curl -v  --silent 127.0.0.1:5005/database/test/detector/default/0/meta/1?token=$token --stderr - | tee /dev/stderr | grep 'no documents'
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/test/detector/default/0/meta/0?token=$token --stderr - | tee /dev/stderr | grep '"data":"test"'
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/test/detector/default/0/meta/1?token=$token --stderr - | tee /dev/stderr | grep 'no documents'
 
diff --git a/tests/automatic/broker/get_meta/check_windows.bat b/tests/automatic/broker/get_meta/check_windows.bat
index cf16f3d18a6100657038480b92667f63c932c5ea..ee02ec0a23cff2fd68a12b8e45fb171693c460a6 100644
--- a/tests/automatic/broker/get_meta/check_windows.bat
+++ b/tests/automatic/broker/get_meta/check_windows.bat
@@ -8,17 +8,15 @@ set short_name="%~nx1"
 
 c:\opt\consul\nomad run authorizer.nmd
 c:\opt\consul\nomad run nginx.nmd
-ping 192.0.2.1 -n 1 -w 3000 > nul
+start /B "" "%full_name%" -config settings.json
 
+ping 192.0.2.1 -n 1 -w 5000 > nul
 
 set token=%BT_DATA_TOKEN%
 
-start /B "" "%full_name%" -config settings.json
-
-ping 192.0.2.1 -n 1 -w 1000 > nul
 
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/detector/default/0/meta/0?token=%token% --stderr - | findstr /c:\"_id\":0  || goto :error
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/detector/default/0/meta/1?token=%token% --stderr - | findstr /c:"no documents"  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/meta/0?token=%token% --stderr - | findstr /c:\"_id\":0  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/detector/default/0/meta/1?token=%token% --stderr - | findstr /c:"no documents"  || goto :error
 
 
 goto :clean
diff --git a/tests/automatic/broker/get_next/check_linux.sh b/tests/automatic/broker/get_next/check_linux.sh
index cd204d7248a21956e8dec317e7dfd7435823b4d8..80bb2312f4fcd83c0bb4d0b4c582709785ec2ef5 100644
--- a/tests/automatic/broker/get_next/check_linux.sh
+++ b/tests/automatic/broker/get_next/check_linux.sh
@@ -31,11 +31,11 @@ $1 -config settings.json &
 sleep 0.3
 brokerid=`echo $!`
 
-groupid=`curl -d '' --silent 127.0.0.1:5005/creategroup`
-curl -v  --silent 127.0.0.1:5005/database/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr  | grep '"_id":1'
-curl -v  --silent 127.0.0.1:5005/database/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr  | grep '"_id":2'
-curl -v  --silent 127.0.0.1:5005/database/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr  | grep '"id_max":2'
+groupid=`curl -d '' --silent 127.0.0.1:5005/v0.1/creategroup`
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr  | grep '"_id":1'
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr  | grep '"_id":2'
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr  | grep '"id_max":2'
 
 # with a new group
-groupid=`curl -d '' --silent 127.0.0.1:5005/creategroup`
-curl -v  --silent 127.0.0.1:5005/database/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr | grep '"_id":1'
\ No newline at end of file
+groupid=`curl -d '' --silent 127.0.0.1:5005/v0.1/creategroup`
+curl -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/source/${stream}/${groupid}/next?token=$token --stderr - | tee /dev/stderr | grep '"_id":1'
\ No newline at end of file
diff --git a/tests/automatic/broker/get_next/check_windows.bat b/tests/automatic/broker/get_next/check_windows.bat
index 4d5ed42b65ed9ff318e72739621176c975b50832..89ba33faa721e4c8267d6ae026b5142f1691d140 100644
--- a/tests/automatic/broker/get_next/check_windows.bat
+++ b/tests/automatic/broker/get_next/check_windows.bat
@@ -11,22 +11,19 @@ set token=%BT_DATA_TOKEN%
 
 c:\opt\consul\nomad run authorizer.nmd
 c:\opt\consul\nomad run nginx.nmd
-ping 192.0.2.1 -n 1 -w 3000 > nul
-
-
 start /B "" "%full_name%" -config settings.json
 
-ping 192.0.2.1 -n 1 -w 1000 > nul
+ping 192.0.2.1 -n 1 -w 5000 > nul
 
-C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/creategroup > groupid
+C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/v0.1/creategroup > groupid
 set /P groupid=< groupid
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1  || goto :error
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":2  || goto :error
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/source/default/%groupid%/next?token=%token% --stderr - | findstr  /c:\"id_max\":2  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":2  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/source/default/%groupid%/next?token=%token% --stderr - | findstr  /c:\"id_max\":2  || goto :error
 
-C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/creategroup > groupid
+C:\Curl\curl.exe -d '' --silent 127.0.0.1:5005/v0.1/creategroup > groupid
 set /P groupid=< groupid
-C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/database/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1  || goto :error
+C:\Curl\curl.exe -v  --silent 127.0.0.1:5005/v0.1/beamtime/data/source/default/%groupid%/next?token=%token% --stderr - | findstr /c:\"_id\":1  || goto :error
 
 goto :clean
 
diff --git a/tests/automatic/common_scripts/start_services.bat b/tests/automatic/common_scripts/start_services.bat
index e27bc8ccff35a4b9c29c4ea6fbd7acdeae89870a..cbe15b437378469b298ce4355f6bd4ffa592ef4b 100644
--- a/tests/automatic/common_scripts/start_services.bat
+++ b/tests/automatic/common_scripts/start_services.bat
@@ -16,7 +16,7 @@ if %i% EQU 20 (
     goto :error
 )
 ping 192.0.2.1 -n 1 -w 1000 >nul
-curl --silent --fail 127.0.0.1:8400/asapo-discovery/asapo-receiver --stderr - | findstr 127.0.0.1  || goto :repeat
-curl --silent --fail 127.0.0.1:8400/asapo-discovery/asapo-broker --stderr - | findstr 127.0.0.1 || goto :repeat
-curl --silent --fail 127.0.0.1:8400/asapo-discovery/asapo-file-transfer --stderr -  | findstr 127.0.0.1 || goto :repeat
+curl --silent --fail 127.0.0.1:8400/asapo-discovery/v0.1/asapo-receiver?protocol=v0.1 --stderr - | findstr 127.0.0.1  || goto :repeat
+curl --silent --fail 127.0.0.1:8400/asapo-discovery/v0.1/asapo-broker?protocol=v0.1 --stderr - | findstr 127.0.0.1 || goto :repeat
+curl --silent --fail 127.0.0.1:8400/asapo-discovery/v0.1/asapo-file-transfer?protocol=v0.1 --stderr -  | findstr 127.0.0.1 || goto :repeat
 echo discovery ready
diff --git a/tests/automatic/consumer/consumer_api/consumer_api.cpp b/tests/automatic/consumer/consumer_api/consumer_api.cpp
index 91d802d18e75632333eaac2a0fa657047faa8eee..a6f889c2abb8d5943c6c68bb8153a7db9e8e16ea 100644
--- a/tests/automatic/consumer/consumer_api/consumer_api.cpp
+++ b/tests/automatic/consumer/consumer_api/consumer_api.cpp
@@ -31,6 +31,14 @@ void TestSingle(const std::unique_ptr<asapo::Consumer>& consumer, const std::str
     asapo::MessageMeta fi;
     asapo::Error err;
 
+    std::string client,server;
+    bool supported;
+    err = consumer->GetVersionInfo(&client,&server,&supported);
+    M_AssertTrue(err == nullptr, "Version OK");
+    M_AssertTrue(supported, "client supported by server");
+    M_AssertTrue(!client.empty(), "client version");
+    M_AssertTrue(!server.empty(), "server version");
+
     err = consumer->GetNext(group_id, &fi, nullptr, "default");
     if (err) {
         std::cout << err->Explain() << std::endl;
diff --git a/tests/automatic/consumer/consumer_api_python/consumer_api.py b/tests/automatic/consumer/consumer_api_python/consumer_api.py
index b150e5fb57b5fb14c76e78d1662d6525d43e014b..1b5bf5a153d00bfbd4336529a2ee9a9b9823799f 100644
--- a/tests/automatic/consumer/consumer_api_python/consumer_api.py
+++ b/tests/automatic/consumer/consumer_api_python/consumer_api.py
@@ -29,6 +29,13 @@ def assert_usermetadata(meta, name):
         print('meta: ', json.dumps(meta, indent=4, sort_keys=True))
         sys.exit(1)
 
+def assert_version(version):
+    print("asserting version ",version)
+    ok = version['supported'] and version['client'] and version['server']
+    if not ok:
+        sys.exit(1)
+
+
 
 def assert_eq(val, expected, name):
     print("asserting eq for " + name)
@@ -48,6 +55,10 @@ def check_file_transfer_service(consumer, group_id):
 
 def check_single(consumer, group_id):
     global thread_res
+
+    version = consumer.get_version_info()
+    assert_version(version)
+
     _, meta = consumer.get_next(group_id, meta_only=True)
     assert_metaname(meta, "1", "get next1")
     assert_usermetadata(meta, "get next1")
diff --git a/tests/automatic/curl_http_client/curl_http_client_command/curl_httpclient_command.cpp b/tests/automatic/curl_http_client/curl_http_client_command/curl_httpclient_command.cpp
index 5d03140816ab9dc7651daf7173f31b2bbc7243c8..c3391d9ab9f63c634420893f615484eacdd7762e 100644
--- a/tests/automatic/curl_http_client/curl_http_client_command/curl_httpclient_command.cpp
+++ b/tests/automatic/curl_http_client/curl_http_client_command/curl_httpclient_command.cpp
@@ -44,7 +44,7 @@ int main(int argc, char* argv[]) {
     asapo::HttpCode code;
     std::string response;
     std::string input_data;
-    auto folder_token = consumer_impl->httpclient__->Post(args.uri_authorizer + "/folder", "", authorize_request, &code,
+    auto folder_token = consumer_impl->httpclient__->Post(args.uri_authorizer + "/v0.1/folder", "", authorize_request, &code,
                         &err);
     if (err) {
         std::cout << err->Explain();
@@ -52,7 +52,7 @@ int main(int argc, char* argv[]) {
     M_AssertTrue(err == nullptr);
     M_AssertTrue(code == asapo::HttpCode::OK);
 
-    consumer_impl->httpclient__->Post(args.uri_authorizer + "/folder", "", "", &code, &err);
+    consumer_impl->httpclient__->Post(args.uri_authorizer + "/v0.1/folder", "", "", &code, &err);
     M_AssertTrue(code == asapo::HttpCode::BadRequest);
 
     consumer_impl->httpclient__->Post(args.uri_authorizer + "/bla", "", "", &code, &err);
@@ -61,12 +61,12 @@ int main(int argc, char* argv[]) {
 // check post with data
     std::string transfer = "{\"Folder\":\"" + args.folder + "\",\"FileName\":\"aaa\"}";
     std::string cookie = "Authorization=Bearer " + folder_token + ";";
-    auto content = consumer_impl->httpclient__->Post(args.uri_fts + "/transfer", cookie, transfer, &code, &err);
+    auto content = consumer_impl->httpclient__->Post(args.uri_fts + "/v0.1/transfer", cookie, transfer, &code, &err);
     M_AssertEq("hello", content);
     M_AssertTrue(code == asapo::HttpCode::OK);
 // with array
     asapo::MessageData data;
-    err = consumer_impl->httpclient__->Post(args.uri_fts + "/transfer", cookie, transfer, &data, 5, &code);
+    err = consumer_impl->httpclient__->Post(args.uri_fts + "/v0.1/transfer", cookie, transfer, &data, 5, &code);
     M_AssertEq( "hello", reinterpret_cast<char const*>(data.get()));
     M_AssertTrue(code == asapo::HttpCode::OK);
 
@@ -76,7 +76,7 @@ int main(int argc, char* argv[]) {
     uint64_t size = 0;
     auto expected_data = io->GetDataFromFile(fname, &size, &err);
     M_AssertEq(nullptr, err);
-    err = consumer_impl->httpclient__->Post(args.uri_fts + "/transfer", cookie, transfer, &data, size, &code);
+    err = consumer_impl->httpclient__->Post(args.uri_fts + "/v0.1/transfer", cookie, transfer, &data, size, &code);
     M_AssertTrue(code == asapo::HttpCode::OK);
     for (uint64_t i = 0; i < size; i++) {
         if (expected_data[i] != data[i]) {
@@ -86,11 +86,11 @@ int main(int argc, char* argv[]) {
 
 // with file
     transfer = "{\"Folder\":\"" + args.folder + "\",\"FileName\":\"aaa\"}";
-    err = consumer_impl->httpclient__->Post(args.uri_fts + "/transfer", cookie, transfer, "bbb", &code);
+    err = consumer_impl->httpclient__->Post(args.uri_fts + "/v0.1/transfer", cookie, transfer, "bbb", &code);
     M_AssertTrue(code == asapo::HttpCode::OK);
 
     transfer = "{\"Folder\":\"" + args.folder + "\",\"FileName\":\"random\"}";
-    err = consumer_impl->httpclient__->Post(args.uri_fts + "/transfer", cookie, transfer, "random", &code);
+    err = consumer_impl->httpclient__->Post(args.uri_fts + "/v0.1/transfer", cookie, transfer, "random", &code);
     M_AssertTrue(code == asapo::HttpCode::OK);
 
     return 0;
diff --git a/tests/automatic/file_transfer_service/rest_api/check_linux.sh b/tests/automatic/file_transfer_service/rest_api/check_linux.sh
index 2822d4c15ea4edff502d3816006b7c1994b0f6d0..e7350241666f62bd20a802c6ea921af2f5e3f725 100644
--- a/tests/automatic/file_transfer_service/rest_api/check_linux.sh
+++ b/tests/automatic/file_transfer_service/rest_api/check_linux.sh
@@ -23,22 +23,22 @@ mkdir -p $file_transfer_folder
 
 token=$BT_AAA_TOKEN
 
-folder_token=`curl --silent --data "{\"Folder\":\"$file_transfer_folder\",\"BeamtimeId\":\"aaa\",\"Token\":\"$token\"}" 127.0.0.1:5007/folder`
+folder_token=`curl --silent --data "{\"Folder\":\"$file_transfer_folder\",\"BeamtimeId\":\"aaa\",\"Token\":\"$token\"}" 127.0.0.1:5007/v0.1/folder`
 echo $folder_token
 
 
 dd if=/dev/urandom of=$file_transfer_folder/aaa bs=1 count=100000
 
-curl -o aaa --silent -H "Authorization: Bearer ${folder_token}" --data "{\"Folder\":\"$file_transfer_folder\",\"FileName\":\"aaa\",\"Token\":\"$folder_token\"}" 127.0.0.1:5008/transfer --stderr - | tee /dev/stderr
+curl -o aaa --silent -H "Authorization: Bearer ${folder_token}" --data "{\"Folder\":\"$file_transfer_folder\",\"FileName\":\"aaa\",\"Token\":\"$folder_token\"}" 127.0.0.1:5008/v0.1/transfer --stderr - | tee /dev/stderr
 
-curl -H "Authorization: Bearer ${folder_token}" --data "{\"Folder\":\"$file_transfer_folder\",\"FileName\":\"aaa\",\"Token\":\"$folder_token\"}" 127.0.0.1:5008/transfer?sizeonly=true --stderr - | tee /dev/stderr | grep 100000
+curl -H "Authorization: Bearer ${folder_token}" --data "{\"Folder\":\"$file_transfer_folder\",\"FileName\":\"aaa\",\"Token\":\"$folder_token\"}" 127.0.0.1:5008/v0.1/transfer?sizeonly=true --stderr - | tee /dev/stderr | grep 100000
 
 
 diff -q aaa $file_transfer_folder/aaa
 
 dd if=/dev/zero of=$file_transfer_folder/big_file bs=1 count=0 seek=5368709120
 
-curl -vvv -o big_file -H "Authorization: Bearer ${folder_token}" --data "{\"Folder\":\"$file_transfer_folder\",\"FileName\":\"big_file\",\"Token\":\"$folder_token\"}" 127.0.0.1:5008/transfer --stderr -  | tee /dev/stderr
+curl -vvv -o big_file -H "Authorization: Bearer ${folder_token}" --data "{\"Folder\":\"$file_transfer_folder\",\"FileName\":\"big_file\",\"Token\":\"$folder_token\"}" 127.0.0.1:5008/v0.1/transfer --stderr -  | tee /dev/stderr
 
 ls -ln big_file | awk '{ print $5 }' | tee /dev/stderr | grep 5368709120
 
diff --git a/tests/automatic/file_transfer_service/rest_api/check_windows.bat b/tests/automatic/file_transfer_service/rest_api/check_windows.bat
index 2a49fecc6206a9d5cdf2eae712f2e42907673eee..9f869e0d9973a630e45ea532b1fbe35a10179325 100644
--- a/tests/automatic/file_transfer_service/rest_api/check_windows.bat
+++ b/tests/automatic/file_transfer_service/rest_api/check_windows.bat
@@ -13,12 +13,12 @@ set token=%BT_AAA_TOKEN%
 
 mkdir %file_transfer_folder%
 
-C:\Curl\curl.exe --silent --data "{\"Folder\":\"%file_transfer_folder%\",\"BeamtimeId\":\"aaa\",\"Token\":\"%token%\"}" 127.0.0.1:5007/folder > token
+C:\Curl\curl.exe --silent --data "{\"Folder\":\"%file_transfer_folder%\",\"BeamtimeId\":\"aaa\",\"Token\":\"%token%\"}" 127.0.0.1:5007/v0.1/folder > token
 set /P folder_token=< token
 
 echo hello > %file_transfer_folder%\aaa
 
-C:\Curl\curl.exe --silent -H "Authorization: Bearer %folder_token%" --data "{\"Folder\":\"%file_transfer_folder%\",\"FileName\":\"aaa\",\"Token\":\"%folder_token%\"}" 127.0.0.1:5008/transfer --stderr - | findstr hello  || goto :error
+C:\Curl\curl.exe --silent -H "Authorization: Bearer %folder_token%" --data "{\"Folder\":\"%file_transfer_folder%\",\"FileName\":\"aaa\",\"Token\":\"%folder_token%\"}" 127.0.0.1:5008/v0.1/transfer --stderr - | findstr hello  || goto :error
 
 goto :clean
 
diff --git a/tests/automatic/full_chain/send_recv_streams/send_recv_streams.cpp b/tests/automatic/full_chain/send_recv_streams/send_recv_streams.cpp
index 9e18200837e755a3c9e2fbeca72d7064b1ab4cc3..7858801dcd1ea3b0ef8a4e53225c42fde5be4f16 100644
--- a/tests/automatic/full_chain/send_recv_streams/send_recv_streams.cpp
+++ b/tests/automatic/full_chain/send_recv_streams/send_recv_streams.cpp
@@ -73,7 +73,6 @@ ProducerPtr CreateProducer(const Args& args) {
 }
 
 int main(int argc, char* argv[]) {
-    asapo::ExitAfterPrintVersionIfNeeded("GetNext consumer Example", argc, argv);
     Args args;
     if (argc != 4) {
         std::cout << "Usage: " + std::string{argv[0]}
diff --git a/tests/automatic/full_chain/simple_chain_filegen/check_windows.bat b/tests/automatic/full_chain/simple_chain_filegen/check_windows.bat
index dbbfd65225dc280002466170429ddffa097fa187..9d783bd6ad254ac7674fa9262a2a33617febd228 100644
--- a/tests/automatic/full_chain/simple_chain_filegen/check_windows.bat
+++ b/tests/automatic/full_chain/simple_chain_filegen/check_windows.bat
@@ -23,7 +23,7 @@ mkdir %receiver_folder%
 mkdir  c:\tmp\asapo\test_in\processed
 start /B "" "%1" test.json
 
-ping 192.0.2.1 -n 1 -w 1000 > nul
+ping 192.0.2.1 -n 1 -w 5000 > nul
 
 mkdir  c:\tmp\asapo\test_in\processed\test1
 mkdir  c:\tmp\asapo\test_in\processed\test2
diff --git a/tests/automatic/producer/beamtime_metadata/beamtime_metadata.cpp b/tests/automatic/producer/beamtime_metadata/beamtime_metadata.cpp
index 5d91a1fd83076ae400f20452e146cbd31629e058..dc1c1f1eff961eb3d87f7edbba81922fc1a2b074 100644
--- a/tests/automatic/producer/beamtime_metadata/beamtime_metadata.cpp
+++ b/tests/automatic/producer/beamtime_metadata/beamtime_metadata.cpp
@@ -21,7 +21,6 @@ void PrintCommandArguments(const Args& args) {
 }
 
 void ProcessCommandArguments(int argc, char* argv[], Args* args) {
-    asapo::ExitAfterPrintVersionIfNeeded("dummy beamtime metadata", argc, argv);
     if (argc != 4) {
         std::cout <<
                   "Usage: " << argv[0] <<
diff --git a/tests/automatic/producer/python_api/producer_api.py b/tests/automatic/producer/python_api/producer_api.py
index 11859cc789bf989e00d866f9d45a06f741106a54..2b419865037cb5cc806da97d3bff01743045c5df 100644
--- a/tests/automatic/producer/python_api/producer_api.py
+++ b/tests/automatic/producer/python_api/producer_api.py
@@ -36,11 +36,21 @@ def callback(payload, err):
         print("successfuly sent: ", payload)
     lock.release()
 
+def assert_version(version):
+    print("asserting version ",version)
+    ok = version['supported'] and version['client'] and version['server']
+    if not ok:
+        sys.exit(1)
 
 producer = asapo_producer.create_producer(endpoint,'processed', beamtime, 'auto', data_source, token, nthreads, 60000)
 
 producer.set_log_level("debug")
 
+
+version = producer.get_version_info()
+assert_version(version)
+
+
 # send single file
 producer.send_file(1, local_path="./file1", exposed_path="processed/" + data_source + "/" + "file1",
                    user_meta='{"test_key":"test_val"}', callback=callback)
diff --git a/tests/automatic/settings/broker_settings.json b/tests/automatic/settings/broker_settings.json
index 415622ce7c1ba6fe38424c139f13eb38a3acaf42..a6fb5a48041ae1550dd1f5ffe797929ebac2b0bd 100644
--- a/tests/automatic/settings/broker_settings.json
+++ b/tests/automatic/settings/broker_settings.json
@@ -1,6 +1,7 @@
 {
   "DatabaseServer":"127.0.0.1:27017",
   "PerformanceDbServer": "localhost:8086",
+  "MonitorPerformance": true,
   "AuthorizationServer": "localhost:8400/asapo-authorizer",
   "PerformanceDbName": "db_test",
   "Port":5005,
diff --git a/tests/automatic/settings/broker_settings.json.tpl b/tests/automatic/settings/broker_settings.json.tpl
index 64411c9d4e1e0dc3dc5cc18820243a9901061c65..b79228a7a658f1e465a60a21f4692fb633a5df66 100644
--- a/tests/automatic/settings/broker_settings.json.tpl
+++ b/tests/automatic/settings/broker_settings.json.tpl
@@ -3,6 +3,7 @@
   "DiscoveryServer": "localhost:8400/asapo-discovery",
   "AuthorizationServer": "localhost:8400/asapo-authorizer",
   "PerformanceDbServer": "localhost:8086",
+  "MonitorPerformance": true,
   "CheckResendInterval":0,
   "PerformanceDbName": "db_test",
   "Port":{{ env "NOMAD_PORT_broker" }},
diff --git a/tests/automatic/settings/receiver_fabric.json.tpl.lin.in b/tests/automatic/settings/receiver_fabric.json.tpl.lin.in
index 2138a3296e52ba3c6dd355938c021eb05edbbbf6..6cf20b1cde759790e4373b650413524c0eb10d86 100644
--- a/tests/automatic/settings/receiver_fabric.json.tpl.lin.in
+++ b/tests/automatic/settings/receiver_fabric.json.tpl.lin.in
@@ -1,5 +1,6 @@
 {
   "PerformanceDbServer":"localhost:8086",
+  "MonitorPerformance": true,
   "PerformanceDbName": "db_test",
   "DatabaseServer":"auto",
   "DiscoveryServer": "localhost:8400/asapo-discovery",
diff --git a/tests/automatic/settings/receiver_tcp.json.tpl.lin.in b/tests/automatic/settings/receiver_tcp.json.tpl.lin.in
index 6061a8a9fd8b7438790b209e8d77c756147a629c..a6f98fe37d8b198a61170a5578f0f212c38b5480 100644
--- a/tests/automatic/settings/receiver_tcp.json.tpl.lin.in
+++ b/tests/automatic/settings/receiver_tcp.json.tpl.lin.in
@@ -1,5 +1,6 @@
 {
   "PerformanceDbServer":"localhost:8086",
+  "MonitorPerformance": true,
   "PerformanceDbName": "db_test",
   "DatabaseServer":"auto",
   "DiscoveryServer": "localhost:8400/asapo-discovery",
diff --git a/tests/automatic/settings/receiver_tcp.json.tpl.win.in b/tests/automatic/settings/receiver_tcp.json.tpl.win.in
index f96debf98172ac42fd4ce2854d3d7a5c265b3873..c0989d12e5dc83a5f0293976f68493f1eb8fc2b4 100644
--- a/tests/automatic/settings/receiver_tcp.json.tpl.win.in
+++ b/tests/automatic/settings/receiver_tcp.json.tpl.win.in
@@ -1,5 +1,6 @@
 {
   "PerformanceDbServer":"localhost:8086",
+  "MonitorPerformance": true,
   "PerformanceDbName": "db_test",
   "DatabaseServer":"auto",
   "DiscoveryServer": "localhost:8400/asapo-discovery",
diff --git a/tests/manual/broker_debug_local/broker.json b/tests/manual/broker_debug_local/broker.json
index 55c5f57b1e24f5d0c56b6fd4218b419f04541aa0..cb0155b9ccc950acfb202e8f403c3dda0f229609 100644
--- a/tests/manual/broker_debug_local/broker.json
+++ b/tests/manual/broker_debug_local/broker.json
@@ -3,6 +3,7 @@
   "DiscoveryServer": "localhost:8400/discovery",
   "AuthorizationServer": "localhost:8400/asapo-authorizer",
   "PerformanceDbServer": "localhost:8086",
+  "MonitorPerformance": true,
   "CheckResendInterval":10,
   "PerformanceDbName": "db_test",
   "Port": 5005,
diff --git a/tests/manual/broker_debug_local/receiver.json b/tests/manual/broker_debug_local/receiver.json
index 8a358c98cbb01faf364b65eb56942638c3c57133..3dfd35396ecf0c78607e5a9983ac33b28a64428c 100644
--- a/tests/manual/broker_debug_local/receiver.json
+++ b/tests/manual/broker_debug_local/receiver.json
@@ -1,5 +1,6 @@
 {
   "PerformanceDbServer":"localhost:8086",
+  "MonitorPerformance": true,
   "PerformanceDbName": "db_test",
   "DatabaseServer":"localhost:27017",
   "DiscoveryServer": "localhost:8400/discovery",
diff --git a/tests/manual/broker_debug_local/receiver.json.tpl b/tests/manual/broker_debug_local/receiver.json.tpl
index 02e0441d517806b27fbd6ed906cf97519188cdba..4de57e97bac84e89d88767697ef160ec04e85b39 100644
--- a/tests/manual/broker_debug_local/receiver.json.tpl
+++ b/tests/manual/broker_debug_local/receiver.json.tpl
@@ -1,5 +1,6 @@
 {
   "PerformanceDbServer":"localhost:8086",
+  "MonitorPerformance": true,
   "PerformanceDbName": "db_test",
   "DatabaseServer":"auto",
   "DiscoveryServer": "localhost:8400/discovery",
diff --git a/tests/manual/performance_broker/settings.json b/tests/manual/performance_broker/settings.json
index ddeaeb916d9dacefaa70d5c2ac5b37828087b2c2..b67ac89cdefb2b90aca59811a3675a8351eec59a 100644
--- a/tests/manual/performance_broker/settings.json
+++ b/tests/manual/performance_broker/settings.json
@@ -1,6 +1,7 @@
 {
   "DatabaseServer":"localhost:27017",
   "PerformanceDbServer": "localhost:8086",
+  "MonitorPerformance": true,
   "AuthorizationServer": "localhost:5007",
   "PerformanceDbName": "db_test",
   "Port":5005,
diff --git a/tests/manual/performance_broker_receiver/getlast_broker.cpp b/tests/manual/performance_broker_receiver/getlast_broker.cpp
index 59011a35aeee20a613a19c85b37a8d264715e4fc..f6a3c1a9270c5ec2de4e63a8ecd8345a0e02fa42 100644
--- a/tests/manual/performance_broker_receiver/getlast_broker.cpp
+++ b/tests/manual/performance_broker_receiver/getlast_broker.cpp
@@ -169,7 +169,6 @@ int ReadAllData(const Args& params, uint64_t* duration_ms, int* nerrors, int* nb
 }
 
 int main(int argc, char* argv[]) {
-    asapo::ExitAfterPrintVersionIfNeeded("GetLast consumer Example", argc, argv);
     Args params;
     params.datasets = false;
     if (argc != 9 && argc != 10) {
diff --git a/tests/manual/performance_full_chain_simple/broker.json b/tests/manual/performance_full_chain_simple/broker.json
index ddeaeb916d9dacefaa70d5c2ac5b37828087b2c2..b67ac89cdefb2b90aca59811a3675a8351eec59a 100644
--- a/tests/manual/performance_full_chain_simple/broker.json
+++ b/tests/manual/performance_full_chain_simple/broker.json
@@ -1,6 +1,7 @@
 {
   "DatabaseServer":"localhost:27017",
   "PerformanceDbServer": "localhost:8086",
+  "MonitorPerformance": true,
   "AuthorizationServer": "localhost:5007",
   "PerformanceDbName": "db_test",
   "Port":5005,
diff --git a/tests/manual/performance_full_chain_simple/receiver.json b/tests/manual/performance_full_chain_simple/receiver.json
index 3b4bfd1a0223e5040fe36d04d4c07f3378b24899..3c36dadd38dfa8d90994b45019396eefc119d44f 100644
--- a/tests/manual/performance_full_chain_simple/receiver.json
+++ b/tests/manual/performance_full_chain_simple/receiver.json
@@ -1,5 +1,6 @@
 {
   "PerformanceDbServer":"localhost:8086",
+  "MonitorPerformance": true,
   "PerformanceDbName": "db_test",
   "DatabaseServer":"localhost:27017",
   "AuthorizationServer": "localhost:5007",
diff --git a/tests/manual/performance_producer_receiver/receiver.json b/tests/manual/performance_producer_receiver/receiver.json
index 485e80876e9e42b618d8ff4387bcc9899ba6cfb4..743e5035b20f458bb8183a475fb43d0427581a61 100644
--- a/tests/manual/performance_producer_receiver/receiver.json
+++ b/tests/manual/performance_producer_receiver/receiver.json
@@ -1,5 +1,6 @@
 {
   "PerformanceDbServer":"localhost:8086",
+  "MonitorPerformance": true,
   "PerformanceDbName": "db_test",
   "DatabaseServer":"localhost:27017",
   "DiscoveryServer": "localhost:8400/discovery",
diff --git a/tests/manual/producer_cpp/producer.cpp b/tests/manual/producer_cpp/producer.cpp
index c198a7506144518a54c0f81f5c15aea2935c2a49..03607b93839e1599617ad19286a76e593734c748 100644
--- a/tests/manual/producer_cpp/producer.cpp
+++ b/tests/manual/producer_cpp/producer.cpp
@@ -1,7 +1,7 @@
 #include <thread>
 #include <chrono>
 #include "asapo/asapo_producer.h"
-
+#include <iostream>
 
 void ProcessAfterSend(asapo::RequestCallbackPayload payload, asapo::Error err) {
     if (err) {
diff --git a/tests/manual/python_tests/producer/receiver.json.tpl b/tests/manual/python_tests/producer/receiver.json.tpl
index 93539e5f794765ab6e40d2a589c3cd0d402a4569..14a4032cde80ba693285b7f03f1100dc49fbcba3 100644
--- a/tests/manual/python_tests/producer/receiver.json.tpl
+++ b/tests/manual/python_tests/producer/receiver.json.tpl
@@ -1,5 +1,6 @@
 {
   "PerformanceDbServer":"localhost:8086",
+  "MonitorPerformance": true,
   "PerformanceDbName": "db_test",
   "DatabaseServer":"localhost:27017",
   "DiscoveryServer": "localhost:8400/discovery",
diff --git a/tests/manual/python_tests/producer_wait_bug_mongo/receiver.json.tpl b/tests/manual/python_tests/producer_wait_bug_mongo/receiver.json.tpl
index 93539e5f794765ab6e40d2a589c3cd0d402a4569..14a4032cde80ba693285b7f03f1100dc49fbcba3 100644
--- a/tests/manual/python_tests/producer_wait_bug_mongo/receiver.json.tpl
+++ b/tests/manual/python_tests/producer_wait_bug_mongo/receiver.json.tpl
@@ -1,5 +1,6 @@
 {
   "PerformanceDbServer":"localhost:8086",
+  "MonitorPerformance": true,
   "PerformanceDbName": "db_test",
   "DatabaseServer":"localhost:27017",
   "DiscoveryServer": "localhost:8400/discovery",
diff --git a/tests/manual/receiver_debug_local/broker.json.tpl b/tests/manual/receiver_debug_local/broker.json.tpl
index 7b55f51c9a8f9cf13cea1042afb80dac1b8739db..968227cab95b7ca440592a2e1c3c0c2c9556d48b 100644
--- a/tests/manual/receiver_debug_local/broker.json.tpl
+++ b/tests/manual/receiver_debug_local/broker.json.tpl
@@ -2,6 +2,7 @@
   "DatabaseServer":"auto",
   "DiscoveryServer": "localhost:8400/discovery",
   "PerformanceDbServer": "localhost:8086",
+  "MonitorPerformance": true,
   "PerformanceDbName": "db_test",
   "Port":{{ env "NOMAD_PORT_broker" }},
   "LogLevel":"info",
diff --git a/tests/manual/receiver_debug_local/receiver.json b/tests/manual/receiver_debug_local/receiver.json
index 8a358c98cbb01faf364b65eb56942638c3c57133..3dfd35396ecf0c78607e5a9983ac33b28a64428c 100644
--- a/tests/manual/receiver_debug_local/receiver.json
+++ b/tests/manual/receiver_debug_local/receiver.json
@@ -1,5 +1,6 @@
 {
   "PerformanceDbServer":"localhost:8086",
+  "MonitorPerformance": true,
   "PerformanceDbName": "db_test",
   "DatabaseServer":"localhost:27017",
   "DiscoveryServer": "localhost:8400/discovery",