diff --git a/CMakeLists.txt b/CMakeLists.txt
index 39428fc7170b0c504faee6cf53a2bd39c3afe211..f65eaf1c61de0f4a80418ed13ff8c21c6c08e169 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -129,6 +129,13 @@ if(FAIRROOT_FOUND)
 endif()
 
 
+#Searching for Boost Package
+find_package(ZeroMQ)
+if(ZeroMQ_FOUND)
+  list(APPEND packages ZeroMQ)
+endif()
+
+
 #Searching for Boost Package
 find_package(Boost COMPONENTS serialization regex filesystem log log_setup container program_options thread)
 if(Boost_FOUND)
diff --git a/services/histserv/Roadmap.md b/services/histserv/Roadmap.md
new file mode 100644
index 0000000000000000000000000000000000000000..70b473133767acf554020f7f1d43bc30a923caac
--- /dev/null
+++ b/services/histserv/Roadmap.md
@@ -0,0 +1,26 @@
+Histo source: class/lib + EventBuildChain
+
+- Members: hostname, port, ZMQ socket, list of known histo names
+
+- Interface method/constructor: init socket
+  => Type? PUB or PUSH?
+- Interface function: new entry <histo name, histo, (folder)>
+  => Check if histo already known
+     => No = add config part to message with <histo name, folder>
+  => Add part to message with <histo name, histo>
+     -> How do we stream the Histo1D object? boost streamer call?
+
+- Message format
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+Histo consummer: histserv
+
+- Members: ZMQ socket
+- Interface function: init socket
+  => Type? SUB or PULL?
+  => PULL
+- Exec method: ZMQ poll/get loop
+  => Blocking?
+  => Exit condition?
+- Config deserialization: boost?
+- Histos deserialization: boost?
+- Message processing: parts + calls to deserialization methods for Config and histo depending on size
diff --git a/services/histserv/app/Application.cxx b/services/histserv/app/Application.cxx
index d5ca5d33d95f3b3f3ba0d51c9308c6ee413e12fa..f3caeb2a77b25db91a7b8129c5ab695a5af63171 100644
--- a/services/histserv/app/Application.cxx
+++ b/services/histserv/app/Application.cxx
@@ -20,7 +20,11 @@
 #include "TRootSniffer.h"
 #include "TSystem.h"
 
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
 #include <boost/serialization/utility.hpp>
+#include <boost/serialization/vector.hpp>
 
 #include <mutex>
 
@@ -29,6 +33,9 @@
 
 std::mutex mtx;
 
+namespace b_io = boost::iostreams;
+namespace b_ar = boost::archive;
+
 namespace cbm::services::histserv
 {
 
@@ -36,20 +43,18 @@ namespace cbm::services::histserv
   Application::Application(ProgramOptions const& opt) : fOpt(opt)
   {
     /// Read options from executable
-    LOG(info) << "Options for Application.";
-    // FIXME: alternative to FairMQ fsChannelNameHistosInput  = fConfig->GetValue<std::string>("ChNameIn");
-    LOG(info) << " HTTP server port: " << fOpt.HttpPort();
+    LOG(info) << "Options for Application:";
+    LOG(info) << " Input ZMQ channel: " << fOpt.ComChan();
+    LOG(info) << " HTTP server port:  " << fOpt.HttpPort();
     if ("" != fOpt.HistoFile()) {  //
-      LOG(info) << "Output filename: " << fOpt.HistoFile() << (fOpt.Overwrite() ? " (in overwrite mode)" : "");
+      LOG(info) << " Output filename:   " << fOpt.HistoFile() << (fOpt.Overwrite() ? " (in overwrite mode)" : "");
     }
 
     /// FIXME: SOMETHING_To_Replace_FairMQ!!!!!!!!!!!!!
     /// FIXME: Initialize communication channels of SOMETHING_To_Replace_FairMQ
     /// FIXME: Link channel to method in order to process received messages
-    /*
-    /// Method processing either combined Config+Data or Data only
-    OnData(fsChannelNameHistosInput, &CbmMqHistoServer::ReceiveConfigAndData);
-    * */
+    // fZmqSocket.set(zmq::sockopt::rcvhwm, int(hwm));  // FIXME: need for HWM?
+    fZmqSocket.bind(fOpt.ComChan().c_str());  // This side "binds" the socket => Other side should connect!!!!
 
     fServer = new THttpServer(Form("http:%u", fOpt.HttpPort()));
     /// To avoid the server sucking all Histos from gROOT when no output file is used
@@ -82,12 +87,85 @@ namespace cbm::services::histserv
     fStopThread = false;
     fThread     = std::thread(&Application::UpdateHttpServer, this);
 
+    const std::chrono::milliseconds timeout {10};
+    /*
+     * Flesnet way (also cppzmq tour https://brettviren.github.io/cppzmq-tour)
+     * ZMQ Draft API! Need custom built ZMQ + #include <zmq_addon.hpp>!
+    zmq::poller_t in_poller;
+    in_poller.add(fZmqSocket, zmq::event_flags::pollin);
+    std::vector<decltype(poller)::poller_event> in_events(1);
+    */
+    /* Alternative taken from FairMQ Poller and zmq.hpp/monitor::check_event() */
+    // http://api.zeromq.org/2-1:zmq-poll: void *socket, int fd, short events, short revents
+    zmq_pollitem_t pollit {fZmqSocket.handle(), 0, ZMQ_POLLIN, 0};
+
     while (!bHistoServerStop) {  //
       /// Infinite loop, this is a service which should survive until told otherwise after all
 
       /// FIXME: Start listening to <SOMETHING?!?> to receive histograms and configuration
+      /*
+       * Flesnet way (also cppzmq tour https://brettviren.github.io/cppzmq-tour)
+       * ZMQ Draft API! Need custom built ZMQ + #include <zmq_addon.hpp>!
+      if (in_poller.wait_all(in_events, timeout)) {
+        zmq::message_t msg;
+        zmq::recv_result_t rres = fZmqSocket.recv(msg, zmq::recv_flags::none);
+      }
+      */
+      /* Alternative taken from FairMQ Poller and zmq.hpp/monitor::check_event() */
+      zmq::poll(&pollit, 1, timeout);
+      if (pollit.revents & ZMQ_POLLIN) {
+        std::vector<zmq::message_t> vMsg;
+        int more        = 1;
+        size_t moreSize = sizeof(more);
+        while (more) {
+          vMsg.push_back(zmq::message_t());
+          int rc = zmq_msg_recv(vMsg.back().handle(), fZmqSocket.handle(), 0);
+          if (rc == -1) {
+            switch (zmq_errno()) {
+              case ETERM: {
+                LOG(debug) << "polling exited, reason: socket was terminated (" << zmq_strerror(errno) << ")";
+                more             = 0;
+                bHistoServerStop = true;
+                break;
+              }
+              case EINTR: {
+                LOG(debug) << "polling interrupted by system call";
+                /// FIXME: not sure if should stop or go-on at this point
+                more             = 0;
+                bHistoServerStop = true;
+                break;
+              }
+              default: {
+                LOG(error) << "polling failed, reason: " << zmq_strerror(errno);
+                more             = 0;
+                bHistoServerStop = true;
+                break;
+              }
+            }
+            continue;
+          }
+          else {
+            zmq_getsockopt(fZmqSocket, ZMQ_RCVMORE, &more, &moreSize);
+          }
+        }
+
+        /// Check if multi-parts message
+        if (3 < vMsg.size()) {  //
+          ReceiveConfigAndData(vMsg);
+        }
+        else if (1 == vMsg.size()) {
+          ReceiveData(vMsg[0]);
+        }
+        else if (0 < vMsg.size()) {
+          LOG(error) << "Invalid number of message parts received: should be either 1 or more than 3 vs "
+                     << vMsg.size();
+        }
+        else {
+          LOG(error) << "polling told some data to expect but none successfully readout!";
+        }
+      }
 
-      std::this_thread::sleep_for(std::chrono::milliseconds(10));
+      //std::this_thread::sleep_for(std::chrono::milliseconds(10));
     }
   }
   // -------------------------------------------------------------------------------------------------------------------
@@ -130,24 +208,59 @@ namespace cbm::services::histserv
   // -------------------------------------------------------------------------------------------------------------------
 
   // -----   Server update background thread   -------------------------------------------------------------------------
-  bool Application::ReceiveData(/*FIXME_SOMETHING_To_Replace_FairMQ& parts*/)
+  bool Application::ReceiveData(zmq::message_t& msg)
   {
     LOG(debug) << "Application::ReceiveData => Processing histograms update";
-    TObject* tempObject = nullptr;
 
     /// FIXME: Something to replace FairMQ and extract the histograms!!!!
     /// FIXME: Need something to replace the ROOT serializer which allowed to have any of TH1x, TH2x, TH3x or TProfile
-    cbm::algo::Histo1D source(1, 0.0, 1.0, "dummy");
-
-    /// copied from CbmTaskDigiEventQa::ToTH1D
-    TH1D* result =
-      new TH1D(source.Name().c_str(), source.Name().c_str(), source.NumBins(), source.MinValue(), source.MaxValue());
-    for (uint32_t bin = 0; bin < source.NumBins(); bin++) {
-      result->SetBinContent(bin, source.Content(bin));
+    /// FIXME: Need something to replace the TObjArray which allowed to have a mix of of TH1x, TH2x, TH3x or TProfile
+    b_io::basic_array_source<char> device(static_cast<char*>(msg.data()), msg.size());
+    b_io::stream<b_io::basic_array_source<char>> s(device);
+    b_ar::binary_iarchive iarch(s);
+
+    std::vector<cbm::algo::Histo1D> vHist;
+    iarch >> vHist;
+
+    for (auto& source : vHist) {
+      /// copied from CbmTaskDigiEventQa::ToTH1D
+      /// FIXME: Should be placed in a tools/interface/whatever library with all similar functions!!
+      /// FIXME: Reverse OP need to be implemented + CI unit tests for back and forth in each direction (ROOT <-> Algo)
+      /// FIXME: Lead to "Warning in <TROOT::Append>: Replacing existing TH1: xxxxxx (Potential memory leak)."
+      bool add = TH1::AddDirectoryStatus();
+      TH1::AddDirectory(false);  // Needed to prevent ROOT from adding histogram to its internal registry
+      TH1D* result = new TH1D(source.Name().c_str(), source.Title().c_str(),  // Titles in ROOT convention with ";" sep
+                              source.NumBins(), source.MinValue(), source.MaxValue());
+      TH1::AddDirectory(add);  // Needed to prevent ROOT from adding histogram to its internal registry
+      for (uint32_t bin = 0; bin < source.NumBins(); bin++) {
+        result->SetBinContent(1 + bin, source.Content(bin));
+      }
+      result->SetBinContent(0, source.Underflow());
+      result->SetBinContent(source.NumBins(), source.Overflow());
+      result->SetEntries(source.NumEntries());
+      if (!ReadHistogram<TH1>(result)) {  //
+        return false;
+      }
+      delete result;
     }
-    result->SetEntries(source.NumEntries());
-    tempObject = result;
 
+    /// If new histos received, try to prepare as many canvases as possible
+    /// Should be expensive on start and cheap afterward
+    if (!fbAllCanvasReady) {
+      LOG(debug) << "Application::ReceiveData => Checking for canvases updates";
+      for (uint32_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv) {
+        /// Jump canvases already ready
+        if (fvbCanvasReady[uCanv]) {  //
+          continue;
+        }
+
+        /// Now come the expensive part as we unpack its config and check each histo
+        fvbCanvasReady[uCanv] = PrepareCanvas(uCanv);
+      }  // for( uint32_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv )
+    }    // if( !fbAllCanvasReady )
+
+    /*
+    TObject* tempObject = nullptr;
     if (TString(tempObject->ClassName()).EqualTo("TObjArray")) {
       std::lock_guard<std::mutex> lk(mtx);
       TObjArray* arrayHisto = static_cast<TObjArray*>(tempObject);
@@ -199,23 +312,26 @@ namespace cbm::services::histserv
       throw std::runtime_error(err_msg);
     }
 
-    fNMessages += 1;
-
     if (nullptr != tempObject) delete tempObject;
+    */
+
+    fNMessages += 1;
 
     LOG(debug) << "Application::ReceiveData => Finished processing histograms update";
 
     return true;
   }
 
-  bool Application::ReceiveHistoConfig(/*FIXME_SOMETHING_To_Replace_FairMQ& parts*/)
+  bool Application::ReceiveHistoConfig(zmq::message_t& msg)
   {
-    std::pair<std::string, std::string> tempObject("", "");
-
-    /// FIXME: Something to replace FairMQ and extract the histograms!!!!
-    //  Deserialize<BoostSerializer<std::pair<std::string, std::string>>>(*msg, tempObject);
-    //  BoostSerializer<std::pair<std::string, std::string>>().Deserialize(*msg, tempObject);
+    /// FIXME: Something to replace FairMQ and extract the config!!!!
+    //  BoostSerializer<std::pair<std::string, std::string>>().Deserialize(msg, tempObject);
+    b_io::basic_array_source<char> device(static_cast<char*>(msg.data()), msg.size());
+    b_io::stream<b_io::basic_array_source<char>> s(device);
+    b_ar::binary_iarchive iarch(s);
 
+    std::pair<std::string, std::string> tempObject("", "");
+    iarch >> tempObject;
 
     LOG(info) << " Received configuration for histo " << tempObject.first << " : " << tempObject.second;
 
@@ -243,13 +359,16 @@ namespace cbm::services::histserv
     return true;
   }
 
-  bool Application::ReceiveCanvasConfig(/*FIXME_SOMETHING_To_Replace_FairMQ& parts*/)
+  bool Application::ReceiveCanvasConfig(zmq::message_t& msg)
   {
-    std::pair<std::string, std::string> tempObject("", "");
+    /// FIXME: Something to replace FairMQ and extract the config!!!!
+    //  BoostSerializer<std::pair<std::string, std::string>>().Deserialize(msg, tempObject);
+    b_io::basic_array_source<char> device(static_cast<char*>(msg.data()), msg.size());
+    b_io::stream<b_io::basic_array_source<char>> s(device);
+    b_ar::binary_iarchive iarch(s);
 
-    /// FIXME: Something to replace FairMQ and extract the histograms!!!!
-    //  Deserialize<BoostSerializer<std::pair<std::string, std::string>>>(*msg, tempObject);
-    //  BoostSerializer<std::pair<std::string, std::string>>().Deserialize(*msg, tempObject);
+    std::pair<std::string, std::string> tempObject("", "");
+    iarch >> tempObject;
 
     LOG(info) << " Received configuration for canvas " << tempObject.first << " : " << tempObject.second;
 
@@ -279,44 +398,32 @@ namespace cbm::services::histserv
     return true;
   }
 
-  bool Application::ReceiveConfigAndData(/*FIXME_SOMETHING_To_Replace_FairMQ& parts*/)
+  bool Application::ReceiveConfigAndData(std::vector<zmq::message_t>& vMsg)
   {
     /// FIXME: Something to replace FairMQ and extract the histograms!!!!
-    /*
-    /// Reject anything but
-    /// - Header + Histo Config + Canvas Config + Histo Data
-    /// - Histo data only
-    if (4 != parts.Size()) {
-      if (1 == parts.Size()) {
-        /// Catch case of having only the histograms updates
-        return ReceiveData(parts.At(0), 0);
-      }  // if( 1 == parts.Size() )
-
-      fStopThread = true;
-      std::string err_msg = "Application::ReceiveConfigAndData => Wrong number of parts: ";
-      err_msg += parts.Size();
-      err_msg += " instead of 4 (Header + Histo Config + Canvas config + Data) or 1 (Data)!";
-      throw std::runtime_error(err_msg);
-    }  // if( parts.Size() < 4 )
+    LOG(debug) << "Application::ReceiveConfigAndData => Received composed message with " << vMsg.size() << " parts";
 
-    LOG(info) << "Application::ReceiveConfigAndData => Received composed message with " << parts.Size() << " parts";
+    /// Header contains a pair of unsigned integers
+    /// FIXME: Something to replace FairMQ and extract the header!!!!
+    // BoostSerializer<std::pair<uint32_t, uint32_t>>().Deserialize(vMsg.at(0), pairHeader);
+    b_io::basic_array_source<char> device_header(static_cast<char*>(vMsg.at(0).data()), vMsg.at(0).size());
+    b_io::stream<b_io::basic_array_source<char>> s_header(device_header);
+    b_ar::binary_iarchive iarch_header(s_header);
 
-    /// Header contains a pair of
     std::pair<uint32_t, uint32_t> pairHeader;
-    //  Deserialize<BoostSerializer<std::pair<uint32_t, uint32_t>>>(*parts.At(0), pairHeader);
-    BoostSerializer<std::pair<uint32_t, uint32_t>>().Deserialize(*parts.At(0), pairHeader);
-
-    LOG(info) << "Application::ReceiveConfigAndData => Received configuration for " << pairHeader.first
-              << " histos and " << pairHeader.second << " canvases";
+    iarch_header >> pairHeader;
+    LOG(debug) << "Application::ReceiveConfigAndData => Received configuration for " << pairHeader.first
+               << " histos and " << pairHeader.second << " canvases";
 
     uint32_t uOffsetHistoConfig = pairHeader.first;
     if (0 == pairHeader.first) {
       uOffsetHistoConfig = 1;
-      if (0 < (parts.At(uOffsetHistoConfig))->GetSize()) {
-        fStopThread = true;
+      if (0 < vMsg[uOffsetHistoConfig].size()) {
+        fStopThread         = true;
+        bHistoServerStop    = true;
         std::string err_msg = "Application::ReceiveConfigAndData => No histo config expected but corresponding message";
         err_msg += " is not empty: ";
-        err_msg += (parts.At(uOffsetHistoConfig))->GetSize();
+        err_msg += vMsg[uOffsetHistoConfig].size();
         throw std::runtime_error(err_msg);
       }
     }
@@ -324,40 +431,42 @@ namespace cbm::services::histserv
     uint32_t uOffsetCanvasConfig = pairHeader.second;
     if (0 == pairHeader.second) {
       uOffsetCanvasConfig = 1;
-      if (0 < (parts.At(uOffsetHistoConfig + uOffsetCanvasConfig))->GetSize()) {
-        fStopThread = true;
-        std::string err_msg = "Application::ReceiveConfigAndData => No Canvas config expected but corresponding message";
-        err_msg += " is not empty: ";
-        err_msg += (parts.At(uOffsetHistoConfig + uOffsetCanvasConfig))->GetSize();
+      if (0 < vMsg[uOffsetHistoConfig + uOffsetCanvasConfig].size()) {
+        fStopThread         = true;
+        bHistoServerStop    = true;
+        std::string err_msg = "Application::ReceiveConfigAndData => No Canvas config expected but corresponding ";
+        err_msg += " message is not empty: ";
+        err_msg += vMsg[uOffsetHistoConfig + uOffsetCanvasConfig].size();
         throw std::runtime_error(err_msg);
       }
     }
 
-    if (static_cast<size_t>(parts.Size()) != 1 + uOffsetHistoConfig + uOffsetCanvasConfig + 1) {
-      fStopThread = true;
-      std::string err_msg = "Application::ReceiveConfigAndData => Number of parts not matching header: ";
-      err_msg += parts.Size();
-      err_msg += " instead of ";
+    if ((1 + uOffsetHistoConfig + uOffsetCanvasConfig + 1) != vMsg.size()) {
+      fStopThread         = true;
+      bHistoServerStop    = true;
+      std::string err_msg = "Application::ReceiveConfigAndData => Nb parts in message not matching configs numbers ";
+      err_msg += " declared in header";
+      err_msg += vMsg.size();
+      err_msg += " VS ";
       err_msg += 1 + uOffsetHistoConfig + uOffsetCanvasConfig + 1;
       throw std::runtime_error(err_msg);
-    }  // if( parts.Size() != 1 + pairHeader.first + pairHeader.second )
+    }
 
-    /// Decode parts for histograms configuration
+    /// Decode parts for histograms configuration (auto-skip empty message if 0 declared in header)
     for (uint32_t uHisto = 0; uHisto < pairHeader.first; ++uHisto) {
-      ReceiveHistoConfig(parts.At(1 + uHisto), 0);
+      ReceiveHistoConfig(vMsg[1 + uHisto]);
     }  // for (UInt_t uHisto = 0; uHisto < pairHeader.first; ++uHisto)
+    LOG(debug) << "Application::ReceiveConfigAndData => Processed configuration for " << pairHeader.first << " histos";
 
-    /// Decode parts for histograms configuration
+    /// Decode parts for histograms configuration (auto-skip empty message if 0 declared in header)
     for (uint32_t uCanv = 0; uCanv < pairHeader.second; ++uCanv) {
-      ReceiveCanvasConfig(parts.At(1 + uOffsetHistoConfig + uCanv), 0);
+      ReceiveCanvasConfig(vMsg[1 + uOffsetHistoConfig + uCanv]);
     }  // for (UInt_t uCanv = 0; uCanv < pairHeader.second; ++uCanv)
+    LOG(debug) << "Application::ReceiveConfigAndData => Processed configuration for " << pairHeader.second
+               << " canvases";
 
     /// Decode the histograms data now that the configuration is loaded
-    ReceiveData(parts.At(1 + uOffsetHistoConfig + uOffsetCanvasConfig), 0);
-    *
-    LOG(info) << "Application::ReceiveConfigAndData => Finished processing  composed message with " << parts.Size()
-              << " parts";
-    */
+    ReceiveData(vMsg[1 + uOffsetHistoConfig + uOffsetCanvasConfig]);
 
     return true;
   }
@@ -432,7 +541,7 @@ namespace cbm::services::histserv
 
   bool Application::PrepareCanvas(uint32_t uCanvIdx)
   {
-    LOG(debug) << " Extracting configuration for canvas index " << uCanvIdx;
+    LOG(info) << " Extracting configuration for canvas index " << uCanvIdx;
     CanvasConfig conf(ExtractCanvasConfigFromString(fvpsCanvasConfig[uCanvIdx].second));
 
     /// First check if all objects to be drawn are present
@@ -546,29 +655,35 @@ namespace cbm::services::histserv
 
     /// Register the histos in the HTTP server
     for (UInt_t uHisto = 0; uHisto < fvHistos.size(); ++uHisto) {
-      /// Make sure we end up in chosen folder
-      TString sFolder = fvHistos[uHisto].second.data();
-      if (nullptr == gDirectory->Get(sFolder)) {  //
-        gDirectory->mkdir(sFolder);
+      /// catch case of histograms declared in config but not yet received
+      if (nullptr != fvHistos[uHisto].first) {
+        /// Make sure we end up in chosen folder
+        TString sFolder = fvHistos[uHisto].second.data();
+        if (nullptr == gDirectory->Get(sFolder)) {  //
+          gDirectory->mkdir(sFolder);
+        }
+        gDirectory->cd(sFolder);
+
+        /// Write plot
+        fvHistos[uHisto].first->Write();
       }
-      gDirectory->cd(sFolder);
-
-      /// Write plot
-      fvHistos[uHisto].first->Write();
 
       histoFile->cd();
     }  // for( UInt_t uHisto = 0; uHisto < fvHistos.size(); ++uHisto )
 
     for (UInt_t uCanvas = 0; uCanvas < fvCanvas.size(); ++uCanvas) {
-      /// Make sure we end up in chosen folder
-      TString sFolder = fvCanvas[uCanvas].second.data();
-      if (nullptr == gDirectory->Get(sFolder)) {  //
-        gDirectory->mkdir(sFolder);
+      /// catch case of canvases declared in config but for which not all histos were yet received
+      if (nullptr != fvCanvas[uCanvas].first) {
+        /// Make sure we end up in chosen folder
+        TString sFolder = fvCanvas[uCanvas].second.data();
+        if (nullptr == gDirectory->Get(sFolder)) {  //
+          gDirectory->mkdir(sFolder);
+        }
+        gDirectory->cd(sFolder);
+
+        /// Write plot
+        fvCanvas[uCanvas].first->Write();
       }
-      gDirectory->cd(sFolder);
-
-      /// Write plot
-      fvCanvas[uCanvas].first->Write();
 
       histoFile->cd();
     }  // for( UInt_t uHisto = 0; uHisto < fvCanvas.size(); ++uHisto )
diff --git a/services/histserv/app/Application.h b/services/histserv/app/Application.h
index 2b8168df58fdbc9c9dba17d0f659ad759d2e1bd3..fb52caec36c9c6a36839765401d89218110bb1c3 100644
--- a/services/histserv/app/Application.h
+++ b/services/histserv/app/Application.h
@@ -8,9 +8,9 @@
 #include "THttpServer.h"
 #include "TObjArray.h"
 
-#include <memory>
 #include <string>
 #include <thread>
+#include <zmq.hpp>
 
 #include "ProgramOptions.h"
 
@@ -43,15 +43,12 @@ namespace cbm::services::histserv
     void UpdateHttpServer();
 
   private:
-    const std::string& OutputFile() const;
-    const std::string& ParamFile() const;
-    const std::string& SetupTag() const;
     //const std::string& ConfigFile() const;
 
-    bool ReceiveData(/*FIXME_SOMETHING_To_Replace_FairMQ& parts*/);
-    bool ReceiveHistoConfig(/*FIXME_SOMETHING_To_Replace_FairMQ& parts*/);
-    bool ReceiveCanvasConfig(/*FIXME_SOMETHING_To_Replace_FairMQ& parts*/);
-    bool ReceiveConfigAndData(/*FIXME_SOMETHING_To_Replace_FairMQ& parts*/);
+    bool ReceiveData(zmq::message_t& msg);
+    bool ReceiveHistoConfig(zmq::message_t& msg);
+    bool ReceiveCanvasConfig(zmq::message_t& msg);
+    bool ReceiveConfigAndData(std::vector<zmq::message_t>& vMsg);
 
     template<class HistoT>
     bool ReadHistogram(HistoT* pHist);
@@ -67,6 +64,10 @@ namespace cbm::services::histserv
     std::thread fThread;
     bool fStopThread = false;
 
+    /// Interface
+    zmq::context_t fZmqContext {1};
+    zmq::socket_t fZmqSocket {fZmqContext, ZMQ_PULL};
+
     /// Array of histograms with unique names
     TObjArray fArrayHisto;
     /// Vector of string with ( HistoName, FolderPath ) to configure the histogram
diff --git a/services/histserv/app/CMakeLists.txt b/services/histserv/app/CMakeLists.txt
index b614872a252d4a900e0b7d2ca64a2a34822da4c4..3d240995634bd1583d81586d23f26460f34802de 100644
--- a/services/histserv/app/CMakeLists.txt
+++ b/services/histserv/app/CMakeLists.txt
@@ -38,6 +38,8 @@ target_link_libraries(histserv_nofairmq
     ROOT::Hist
     ROOT::RIO
     ROOT::RHTTP
+    libzmq
+    cppzmq
   )
 
 install(TARGETS histserv_nofairmq DESTINATION bin)
diff --git a/services/histserv/app/ProgramOptions.cxx b/services/histserv/app/ProgramOptions.cxx
index d5826bbe284c49fb3331d05d9b862264729a134c..cfe378e94af9b114fa763a04b2959f744ec929a5 100644
--- a/services/histserv/app/ProgramOptions.cxx
+++ b/services/histserv/app/ProgramOptions.cxx
@@ -34,8 +34,9 @@ namespace cbm::services::histserv
     // --- Define configuration options
     po::options_description config("Configuration");
     auto config_add = config.add_options();
-    config_add("input,i", po::value<string>(&fsChanHistosIn)->value_name("<???????>"),
-               "name or host:port or whatever is needed for input channel (histos/canvases config and data)");
+    config_add("input,i", po::value<string>(&fsChanHistosIn)->value_name("<protocol://xxxxxx>"),
+               "name or host:port or whatever is needed for input channel (histos/canvases config and data), "
+               " cf http://api.zeromq.org/2-1:zmq-bind");
     config_add("port,p", po::value<uint32_t>(&fuHttpServerPort)->default_value(8080),
                "port on which the http ROOT server (JSroot) will be available");
     config_add("output,o", po::value<string>(&fsHistoFileName)->value_name("<file name>"),