diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f51a59417b31a6f55ca56ed9cf73c95fca4e0685..2e74b11197002d0cf42a653a6c93cdd44b72435c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,5 +1,5 @@
 variables:
-    VERSION: "5.2"
+    VERSION: "6.2"
     IMAGE: "crestapi"
      # Overriding the variables from the template files.
     TESTS_DIR: test
@@ -63,8 +63,6 @@ auto-fix:
     - merge_requests  # Optionally, run this job only on merge requests
 
 build_container_job:
-  rules:
-    - if: $DO_DOCKER_IMAGE == "yes" && $CI_PIPELINE_SOURCE != 'merge_request_event'
   stage: build_docker_image
   extends: .build_kaniko
   variables:
@@ -107,6 +105,6 @@ apitest:
 crestcmd:  # or any other appropriate stage
   stage: compile-crestcmd
   script:
-    - curl -X POST -F token=$CRESTCMD_TOKEN -F ref=release-5.1-CR2 https://gitlab.cern.ch/api/v4/projects/144796/trigger/pipeline
+    - curl -X POST -F token=$CRESTCMD_TOKEN -F ref=release-6.1-CR1 https://gitlab.cern.ch/api/v4/projects/144796/trigger/pipeline
   only:
     - release-5.1-CR2  # or whichever branch in Project 1 should trigger Project 2
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c555d5b70c209345b099a620814b417a0dfdcfdc..cde58007c948844dc464dc97b3a38051e44f5e61 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,6 +44,8 @@ set(HEADERS
     "CrestApi/CrestApiFs.h"
     "CrestApi/CrestLogger.h"
     "CrestApi/CrestRequest.h"
+    "CrestApi/CrestAuth.h"
+    "CrestApi/JwtUtils.h"
     "CrestApi/CrestApiExt.h"
     "CrestApi/CrestException.h"
     "CrestApi/CrestCondException.h"
@@ -71,11 +73,15 @@ set(HEADERS
     "CrestApi/TagMetaDto.h"
     "CrestApi/TagMetaSetDto.h"
     "CrestApi/TagSetDto.h"
+    "CrestApi/RunLumiDto.h"
+    "CrestApi/RunLumiSetDto.h"
     "${CRESTAPI_VERSION_FILE_DIR}/version.h")
 
 set(SOURCES
     "src/CrestApi.cxx"
     "src/CrestRequest.cxx"
+    "src/CrestAuth.cxx"
+    "src/JwtUtils.cxx"
     "src/CrestLogger.cxx"
     "src/StringUtils.cxx"
     "src/CrestApiFs.cxx"
@@ -103,6 +109,8 @@ set(SOURCES
     "src/StoreSetDto.cxx"
     "src/TagInfoDto.cxx"
     "src/TagSetDto.cxx"
+    "src/RunLumiDto.cxx"
+    "src/RunLumiSetDto.cxx"
 )
 
 # Set up the build of the main library of the project.
@@ -150,6 +158,8 @@ option(CRESTAPI_BUILD_EXAMPLES
     "Flag for building the examples" TRUE)
 if(CRESTAPI_BUILD_EXAMPLES)
     add_subdirectory(examples)
+##    add_subdirectory(acts)
+    add_subdirectory(tools)
 endif()
 
 # Export the project.
diff --git a/CRESTAPI_USAGE.md b/CRESTAPI_USAGE.md
index db8670c28fd928dd8dd0b03c06a9cdb0421379cd..731ca6bd1e6516f815236c3fd8393e6652f50d23 100644
--- a/CRESTAPI_USAGE.md
+++ b/CRESTAPI_USAGE.md
@@ -38,7 +38,7 @@ Here a set of code snippets represting this workflow.
     {"name", tagname},
     {"timeType", "time"},
     {"description", "test"},
-    {"synchronization", "none"},
+    {"synchronization", "ALL"},
     {"insertionTime", "2018-12-18T11:32:58.081+0000"},
     {"modificationTime", "2018-12-18T11:32:57.952+0000"},
     {"payloadSpec", "JSON"}, // For athena reading you need to be careful to this field [crest-json-single-iov | crest-json-multi-iov]
diff --git a/CrestApi/CrestApi.h b/CrestApi/CrestApi.h
index 6caa33fcdee743e018d26323342cff9392044f3f..4ec654d21f86cec21886a37a3327d7443a960c83 100644
--- a/CrestApi/CrestApi.h
+++ b/CrestApi/CrestApi.h
@@ -34,6 +34,7 @@
 #include <CrestApi/PayloadDto.h>
 #include <CrestApi/PayloadSetDto.h>
 #include <CrestApi/PayloadTagInfoSetDto.h>
+#include <CrestApi/RunLumiSetDto.h>
 #include <CrestApi/StoreSetDto.h>
 #include <CrestApi/TagMetaSetDto.h>
 #include <CrestApi/TagSetDto.h>
@@ -531,6 +532,13 @@ class CrestApi : public CrestApiBase {
    */
   PayloadDto getPayloadMeta(const std::string &hash) override;
 
+  /**
+   *  This method finds a streamer info for the hash.
+   * @param hash - hash.
+   * @return streamer info.
+   */
+  std::string getStreamerInfo(const std::string &hash) override;
+
   /**
    * This method returns the full CREST Server version.
    * @return CREST server version.
@@ -547,7 +555,24 @@ class CrestApi : public CrestApiBase {
    * @return JSON payload tag info list as a PayloadTagInfoSetDto.<br>
    */
   PayloadTagInfoSetDto listPayloadTagInfo(const std::string &tagname, int size,
-                                          int page, const std::string &sort);
+                                          int page,
+                                          const std::string &sort) override;
+
+  /**
+   * This method retrieves run lumi information.
+   * @param since - since time (the beginning of the time interval),
+   * @param until - until time (end of the time interval),
+   * @param format - time format for since/until ([iso, number, run-lumi]),
+   * @param mode - the mode parameter is used to determine the meaning of
+   * since/until [daterange, runrange].
+   * @param size - page size,
+   * @param page - page number,
+   * @param sort - sorting order (runNumber:ASC or runNumber:DESC),
+   * @return JSON run lumi info list as a RunLumiSetDto.<br>
+   */
+  RunLumiSetDto listRunInfo(const std::string &since, const std::string &until,
+                            const std::string format, const std::string mode,
+                            int size, int page, const std::string &sort);
 };
 
 }  // namespace Crest
diff --git a/CrestApi/CrestApiBase.h b/CrestApi/CrestApiBase.h
index 07343118ef87866df0b56d24aebdd8032e048746..935b4aa8918022c740b17d3019a065684c4611fb 100644
--- a/CrestApi/CrestApiBase.h
+++ b/CrestApi/CrestApiBase.h
@@ -468,6 +468,13 @@ class CrestApiBase {
    */
   virtual PayloadDto getPayloadMeta(const std::string &hash) = 0;
 
+  /**
+   *  This method finds a streamer info for the hash.
+   * @param hash - hash.
+   * @return streamer info.
+   */
+  virtual std::string getStreamerInfo(const std::string &hash) = 0;
+
   /**
    * This method returns the full CREST Server version.
    * @return CREST server version.
@@ -479,6 +486,19 @@ class CrestApiBase {
    * @return CrestApi library version.
    */
   std::string getClientVersion();
+
+  /**
+   * This method retrieves monitoring information on payload as a list of
+   * payload tag information.
+   * @param tagname - tag name pattern, "%" can be used for any symbols,
+   * @param size - page size,
+   * @param page - page number,
+   * @param sort - sorting order (name:ASC or name:DESC),
+   * @return JSON payload tag info list as a PayloadTagInfoSetDto.<br>
+   */
+  virtual PayloadTagInfoSetDto listPayloadTagInfo(const std::string &tagname,
+                                                  int size, int page,
+                                                  const std::string &sort) = 0;
 };
 
 }  // namespace Crest
diff --git a/CrestApi/CrestApiFs.h b/CrestApi/CrestApiFs.h
index 0408d2abb60ba778dbde0b9f1d34e1b2112651c3..62c7e9c0d6966b5b3f9bf0b7d0fb96f252c3bc6c 100644
--- a/CrestApi/CrestApiFs.h
+++ b/CrestApi/CrestApiFs.h
@@ -97,6 +97,15 @@ class CrestApiFs : public CrestApiBase {
    */
   void flush();
 
+  /**
+   * Auxiliary method to store the streamer info on the file storage.
+   * @param hash - the payload hash.
+   * @param streamerInfo - the payload streamer info.
+   *
+   */
+  void createStreamerInfo(const std::string &hash,
+                          const std::string streamerInfo);
+
  public:
   /**
    * CrestApiFs constructor.
@@ -502,6 +511,13 @@ class CrestApiFs : public CrestApiBase {
    */
   PayloadDto getPayloadMeta(const std::string &hash) override;
 
+  /**
+   *  This method finds a streamer info for the hash.
+   * @param hash - hash.
+   * @return streamer info.
+   */
+  std::string getStreamerInfo(const std::string &hash) override;
+
   /**
    * This method returns the full CREST Server version.
    * @return CREST server version.
@@ -591,6 +607,19 @@ class CrestApiFs : public CrestApiBase {
                         const std::string &compressionType,
                         const std::string &version,
                         const std::string &streamerInfo);
+
+  /**
+   * This method retrieves monitoring information on payload as a list of
+   * payload tag information.
+   * @param tagname - tag name pattern, "%" can be used for any symbols,
+   * @param size - page size,
+   * @param page - page number,
+   * @param sort - sorting order (name:ASC or name:DESC),
+   * @return JSON payload tag info list as a PayloadTagInfoSetDto.<br>
+   */
+  PayloadTagInfoSetDto listPayloadTagInfo(const std::string &tagname, int size,
+                                          int page,
+                                          const std::string &sort) override;
 };
 
 }  // namespace Crest
diff --git a/CrestApi/CrestAuth.h b/CrestApi/CrestAuth.h
new file mode 100644
index 0000000000000000000000000000000000000000..83bf766453871a084d1e8a7508b624b8948f4ddc
--- /dev/null
+++ b/CrestApi/CrestAuth.h
@@ -0,0 +1,130 @@
+// CrestAuth.h
+#ifndef CRESTAPI_AUTH_H
+#define CRESTAPI_AUTH_H
+
+#include <curl/curl.h>
+
+#include <ctime>
+#include <nlohmann/json.hpp>
+#include <string>
+
+namespace Crest {
+
+/**
+ * Class handling authentication for CREST requests.
+ * It loads, refreshes, and exchanges tokens used to authorize access.
+ */
+class CrestAuth {
+ private:
+  std::string m_tokenFilePath;
+  std::string m_tokenEndpoint;
+  std::string m_apiEndpoint;
+  std::string m_clientId;
+  std::string m_audience;
+
+  std::string m_exchangeToken;
+  std::string m_refreshToken;
+  std::string m_finalAccessToken;
+
+  std::time_t m_exchangeTokenExpiresAt;
+
+  /**
+   * Save the full token JSON response to the configured token file.
+   * @param tokenJson Full JSON response from the authentication service.
+   * @return true if saving was successful, false otherwise.
+   */
+  bool saveTokens(const nlohmann::json& tokenJson) const;
+
+  /**
+   * Sends a form-encoded POST request using libcurl to the given URL.
+   * @param url Target endpoint URL.
+   * @param postFields POST body formatted as application/x-www-form-urlencoded.
+   * @return The response body as a string, or empty string on failure.
+   */
+  std::string postRequest(const std::string& url,
+                          const std::string& postFields) const;
+
+  /**
+   * libcurl write callback to accumulate received data into a string.
+   * @param contents Raw data pointer.
+   * @param size Size of each data chunk.
+   * @param nmemb Number of data chunks.
+   * @param userp Pointer to std::string used to collect output.
+   * @return Total bytes handled (size * nmemb).
+   */
+  static size_t WriteCallback(void* contents, size_t size, size_t nmemb,
+                              void* userp);
+
+ public:
+  /**
+   * Default constructor. Initializes internal variables from default
+   * environment-based settings or hardcoded defaults.
+   */
+  CrestAuth();
+
+  /**
+   * Loads the exchange and refresh tokens from a file on disk.
+   * Sets internal state based on the saved token data.
+   * @return true if loading and parsing succeeded; false if file missing or
+   * malformed.
+   */
+  bool loadTokens();
+
+  /**
+   * Uses the current refresh token to request a new exchange token from the
+   * authentication service. Stores the entire response to the token file and
+   * updates internal state.
+   * @return true if the refresh was successful, false otherwise.
+   */
+  bool refreshExchangeToken();
+
+  /**
+   * Exchanges the current exchange token for a final access token used for
+   * authorization. This does not persist the access token to file.
+   * @return true if access token was successfully acquired, false otherwise.
+   */
+  bool exchangeTokenForAccess();
+
+  /**
+   * Checks whether the current exchange token is expired based on the 'exp'
+   * claim.
+   * @return true if the exchange token is expired or invalid.
+   */
+  bool isExchangeTokenExpired() const;
+
+  /**
+   * Returns the currently cached access token. This method does not initiate a
+   * new exchange.
+   * @return Access token string if previously acquired; otherwise an empty
+   * string.
+   */
+  std::string getAccessToken() const;
+
+  /**
+   * Initializes exchange credentials:
+   * - Loads exchange and refresh tokens from file
+   * - Refreshes the exchange token if expired
+   * - Performs token exchange to obtain an access token
+   * @return true if all steps succeed; throws std::runtime_error on fatal
+   * errors.
+   */
+  bool setupExchangeCredentials();
+
+  /**
+   * Requests an access token using the OAuth2 client credentials flow.
+   * Reads client ID and client secret from environment variables.
+   * Stores the resulting access token in memory.
+   *
+   * Environment variables:
+   * - CREST_CLIENT_ID
+   * - CREST_CLIENT_SECRET
+   *
+   * @return true if the token was successfully obtained and stored, false
+   * otherwise.
+   */
+  bool setupClientCredentials();
+};
+
+}  // namespace Crest
+
+#endif  // CRESTAPI_AUTH_H
diff --git a/CrestApi/CrestBaseResponse.h b/CrestApi/CrestBaseResponse.h
index 8cf2e760aff868d28a515de4e040fefdd43e552c..281e87213c5aaf086b86a34a7eeebe5006a29c80 100644
--- a/CrestApi/CrestBaseResponse.h
+++ b/CrestApi/CrestBaseResponse.h
@@ -31,6 +31,7 @@ class CrestBaseResponse {
   std::optional<RespPage> getRespPage() const { return page; }
   std::optional<GenericMap> getFilter() const { return filter; }
 
+  void setRespPage(const RespPage &page) { this->page = page; }
   void setDataType(const std::string &dtype) { datatype = dtype; }
 
   json toJson() const;
diff --git a/CrestApi/CrestRequest.h b/CrestApi/CrestRequest.h
index a6cbd67749f8f6031b189d5b3d3307cc6ad87cce..401b60571a97abd88d53dd13030375f8e27b0fc5 100644
--- a/CrestApi/CrestRequest.h
+++ b/CrestApi/CrestRequest.h
@@ -5,6 +5,7 @@
 #ifndef CRESTAPI_REQUEST_H
 #define CRESTAPI_REQUEST_H
 
+#include <CrestApi/CrestAuth.h>
 #include <curl/curl.h>
 
 #include <cstdint>
@@ -49,6 +50,8 @@ class CrestRequest {
   std::string m_port;
   std::string m_url;
 
+  CrestAuth m_auth;
+
   char *m_CREST_PROXY = NULL;
   const char *m_CREST_PROXY_VAR = "SOCKS_PROXY";
 
@@ -79,6 +82,35 @@ class CrestRequest {
   // Getters
   std::string getUrl();
 
+  /**
+   * Initializes authentication and authorization for CREST requests.
+   *
+   * This method reads the specified execution mode (e.g., "JWT",
+   * "CLIENT_CREDENTIALS") and sets up access credentials accordingly. It:
+   * - Requests an access token via an exchange token if mode="JWT"
+   * - Requests an access token via client id and secret if
+   * mode="CLIENT_CREDENTIALS"
+   *
+   * If the mode is nullptr (i.e. environment variable not set), no special
+   * behavior is applied.
+   *
+   * @param mode - A C-style string indicating the execution mode (e.g., from
+   * the CREST_AUTH_MODE environment variable). If nullptr, the default behavior
+   * is applied.
+   *
+   * @throws std::runtime_error if authentication fails critically (e.g.,
+   * missing token file or failed token exchange).
+   */
+  void initAuth(const char *mode);
+
+  /**
+   * Creates an Authorization header using the current access token from
+   * CrestAuth.
+   * @return A curl_slist pointer containing the Authorization header, or
+   * nullptr if no token is available.
+   */
+  struct curl_slist *createAuthHeader() const;
+
   /**
    * General auxillary method to make request to the CREST Server. This method
    * is used by other methods realizing the requests with the concrete kinds of
diff --git a/CrestApi/JwtUtils.h b/CrestApi/JwtUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..2a15a6449104576758985025c4738af4cd126cd6
--- /dev/null
+++ b/CrestApi/JwtUtils.h
@@ -0,0 +1,38 @@
+#ifndef JWT_UTILS_H
+#define JWT_UTILS_H
+
+#include <ctime>
+#include <string>
+
+namespace Crest {
+
+/**
+ * Utility class for decoding and inspecting JWT (JSON Web Token) claims.
+ */
+class JwtUtils {
+ public:
+  /**
+   * Extracts the `exp` (expiration) claim from a JWT access token.
+   * Optionally subtracts a grace period to account for clock skew.
+   *
+   * @param jwt A JWT string (in the format header.payload.signature).
+   * @param graceSeconds Optional number of seconds to subtract from the
+   * extracted expiration time.
+   * @return The expiration timestamp as time_t (Unix time).
+   * @throws std::runtime_error if the token is malformed or the exp claim is
+   * missing.
+   */
+  static std::time_t extractExp(const std::string& jwt, int graceSeconds = 0);
+
+ private:
+  /**
+   * Decodes a Base64URL-encoded string (used in JWT header and payload).
+   *
+   * @param input The Base64URL-encoded string.
+   * @return The decoded string.
+   */
+  static std::string base64urlDecode(const std::string& input);
+};
+}  // namespace Crest
+
+#endif  // JWT_UTILS_H
diff --git a/CrestApi/RespPage.h b/CrestApi/RespPage.h
index c27c131929f1c94f5388985448a251ef22978af8..c3daa49cc90a429c3c0f3658e811c207065976bb 100644
--- a/CrestApi/RespPage.h
+++ b/CrestApi/RespPage.h
@@ -23,11 +23,27 @@ class RespPage {
   int number;
 
  public:
+  RespPage() : size(0), totalElements(0), totalPages(0), number(0) {}
+
+  RespPage(int size, int64_t totalElements, int totalPages, int number)
+      : size(size),
+        totalElements(totalElements),
+        totalPages(totalPages),
+        number(number) {}
+
   int getSize() const { return size; }
   int64_t getTotalElements() const { return totalElements; }
   int getTotalPages() const { return totalPages; }
   int getNumber() const { return number; }
 
+  // Define setters
+  void setSize(int size) { this->size = size; }
+  void setTotalElements(int64_t totalElements) {
+    this->totalElements = totalElements;
+  }
+  void setTotalPages(int totalPages) { this->totalPages = totalPages; }
+  void setNumber(int number) { this->number = number; }
+
   json toJson() const;
   static RespPage fromJson(const json &j);
 };
diff --git a/CrestApi/RunLumiDto.h b/CrestApi/RunLumiDto.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e78f72664e168aed914aa11531b77fc58621a5f
--- /dev/null
+++ b/CrestApi/RunLumiDto.h
@@ -0,0 +1,59 @@
+/*
+   Copyright (C) 2019-2024 CERN for the benefit of the ATLAS collaboration
+ */
+
+#ifndef CREST_RUN_LUMI_DTO_HPP
+#define CREST_RUN_LUMI_DTO_HPP
+
+#include <CrestApi/CrestException.h>
+
+#include <nlohmann/json.hpp>
+#include <optional>
+#include <string>
+
+using json = nlohmann::json;
+
+namespace Crest {
+
+/**
+ * @brief The RunLumiDto class
+ * It contains CTP information of run,lb,start and end time of each lumi block.
+ *
+ * @param runNumber The run number.
+ * @param lb The lumi block number.
+ * @param starttime The start time of the lumi block, in milliseconds since
+ * epoch.
+ * @param endtime The end time of the lumi block, in milliseconds since epoch.
+ */
+
+class RunLumiDto {
+ private:
+  uint64_t runNumber;
+  uint64_t lb;
+  uint64_t starttime;
+  uint64_t endtime;
+
+ public:
+  // Ctor
+  RunLumiDto(uint64_t runNumber, uint64_t lb, uint64_t starttime,
+             uint64_t endtime)
+      : runNumber(runNumber), lb(lb), starttime(starttime), endtime(endtime) {};
+  // Default Ctor
+  RunLumiDto();
+  const uint64_t &getRunNumber() const { return runNumber; }
+  const uint64_t &getLumiBlock() const { return lb; }
+  const uint64_t &getStartTime() const { return starttime; }
+  const uint64_t &getEndTime() const { return endtime; }
+  // Define setters
+  void setRunNumber(uint64_t runNumber) { this->runNumber = runNumber; }
+  void setLumiBlock(uint64_t lb) { this->lb = lb; }
+  void setStartTime(uint64_t starttime) { this->starttime = starttime; }
+  void setEndTime(uint64_t endtime) { this->endtime = endtime; }
+
+  json toJson() const;
+  static RunLumiDto fromJson(const json &j);
+};
+
+}  // namespace Crest
+
+#endif  // CREST_RUN_LUMI_DTO_HPP
diff --git a/CrestApi/RunLumiSetDto.h b/CrestApi/RunLumiSetDto.h
new file mode 100644
index 0000000000000000000000000000000000000000..186217adb9e2bac6fea67bea57a9880a2b91ec83
--- /dev/null
+++ b/CrestApi/RunLumiSetDto.h
@@ -0,0 +1,45 @@
+/*
+   Copyright (C) 2019-2024 CERN for the benefit of the ATLAS collaboration
+ */
+
+#ifndef CREST_RUN_LUMI_SET_DTO_HPP
+#define CREST_RUN_LUMI_SET_DTO_HPP
+
+#include <CrestApi/CrestBaseResponse.h>
+#include <CrestApi/CrestDetail.h>
+#include <CrestApi/CrestException.h>
+#include <CrestApi/RunLumiDto.h>
+
+#include <string>
+#include <vector>
+
+#include "nlohmann/json.hpp"
+
+using json = nlohmann::json;
+
+namespace Crest {
+
+class RunLumiSetDto : public CrestBaseResponse {
+ private:
+  inline static const std::string s_dtoType = "RunLumiSetDto";
+  std::vector<RunLumiDto> resources;
+
+ public:
+  RunLumiSetDto(const std::vector<RunLumiDto> &resources)
+      : resources(resources) {}
+  RunLumiSetDto() : resources() {}
+  const std::string &getFormat() const { return s_dtoType; }
+
+  size_t size() const { return resources.size(); }
+
+  void add(const RunLumiDto &rl) { resources.push_back(rl); }
+
+  const std::vector<RunLumiDto> &getResources() const { return resources; }
+
+  json toJson() const;
+  static RunLumiSetDto fromJson(const json &j);
+};
+
+}  // namespace Crest
+
+#endif  // CREST_RUN_LUMI_SET_DTO_HPP
diff --git a/README.md b/README.md
index c7eb90c290a415a83a7b77fcdd7ad47b1b923a8b..e846005d4a1db05fd7d3e8d9cfa1812953010e7f 100644
--- a/README.md
+++ b/README.md
@@ -52,6 +52,22 @@ cmake -DCMAKE_INSTALL_PREFIX=$HOME/local_lib ..
 make
 make install
 ```
+
+## Authorization
+Currently, the API supports two types of authorization workflows:
+* `Client credentials`: the client is authenticated using a client id and secret.
+```shell
+export CREST_CLIENT_ID=<client id>
+export CREST_CLIENT_SECRET=<secret>
+export CREST_AUTH_MODE=CLIENT_CREDENTIALS
+```
+* `Token exchange`: the client is authenticated using an exchange token. To obtain the token excute `auth-get-user-token`.
+```shell
+auth-get-user-token -c crest-client -o ~/.client-exchange-token.json
+export CREST_AUTH_MODE=JWT
+```
+Make sure to use `https` in `export CREST_API_URL=https://...`
+
 ## Testing
 The simple examples are in the `doc` and `test` directory. The executables will be created in the `build` directory.
 
@@ -64,4 +80,4 @@ The simple examples are in the `doc` and `test` directory. The executables will
 You can validate your installation for example using:
 ```shell
 ./crest_example_server http://crest-j23.cern.ch:8080/api-v5.0
-```
\ No newline at end of file
+```
diff --git a/acts/CMakeLists.txt b/acts/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5f8152e3c34df8773b2c63f75e874ce26ce0eb73
--- /dev/null
+++ b/acts/CMakeLists.txt
@@ -0,0 +1,54 @@
+# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
+# Set the name of the package.
+cmake_minimum_required(VERSION 3.12)
+project(CrestResolver VERSION 6.1 LANGUAGES CXX)
+
+# Find the necessary externals.
+find_package(CrestApi REQUIRED)
+
+
+# Set the C++ standard to use.
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL
+    "Whether to enable compiler-specific C++ extensions")
+
+# Set the default library type to build.
+option(BUILD_SHARED_LIBS
+    "Flag for building shared/static libraries" TRUE)
+
+# Use the standard GNU installation directories.
+include(GNUInstallDirs)
+set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/CrestResolver")
+
+# Turn on all warnings with GCC and Clang.
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
+endif()
+
+# Declare the header and source file names.
+set(HEADERS
+    "./CrestFileResolver.h"
+)
+
+set(SOURCES
+    "./CrestFileResolver.cxx"
+)
+
+# Set up the build of the main library of the project.
+add_library(CrestResolverLib ${SOURCES} ${HEADERS})
+target_link_libraries(CrestResolverLib
+    PUBLIC
+        CURL::libcurl
+        Boost::boost
+        nlohmann_json::nlohmann_json
+        CrestApi::CrestApiLib
+    PRIVATE
+        OpenSSL::SSL
+)
+target_include_directories(CrestResolverLib
+    PUBLIC
+        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
diff --git a/acts/CrestFileResolver.cxx b/acts/CrestFileResolver.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a625d148cac5c5e503764aaadfe1ae92a8716171
--- /dev/null
+++ b/acts/CrestFileResolver.cxx
@@ -0,0 +1,80 @@
+
+/**
+ * @file CrestApi/test/CrestApi_test.cxx
+ * @brief Some tests for server methods.
+ */
+
+#include "CrestFileResolver.h"
+
+using namespace Crest;
+
+std::string CrestFileResolver::resolveFilePath(const std::string &geometry_gtag,
+                                               const std::string &label,
+                                               const std::string &file_name) {
+  // Here you can implement the logic to resolve the file path.
+  // Use crestapi to resolve mappings and detect the tag.
+  std::cout << "Load mappings for " << geometry_gtag << std::endl;
+  GlobalTagMapSetDto mapset =
+      m_crestApi.findGlobalTagMap(geometry_gtag, "Trace");
+  std::cout << "test: listTagsInGlobalTag (Trace) =" << std::endl;
+  std::cout << mapset.toJson().dump(4) << std::endl;
+
+  if (mapset.getResources().size() < 1) {
+    std::cerr << "No mapping found for the global tag: " << geometry_gtag
+              << std::endl;
+    return "";
+  }
+  // Get the mapping (geometry tag name)
+  GlobalTagMapDto map = mapset.getResources()[0];
+  std::cout << "Found map " << map.toJson().dump(4) << std::endl;
+  std::cout << "Compare label " << this->mat_label << " with " << map.getLabel()
+            << std::endl;
+  // Check that the label is correct
+  if (this->mat_label != map.getLabel()) {
+    std::cerr << "Label mismatch: expected " << mat_label << ", got "
+              << map.getLabel() << std::endl;
+    return "";
+  }
+  std::string mat_tag = map.getTagName();
+  std::cout << "Load iovs for tag " << mat_tag << std::endl;
+  // Now get the IOV.
+  IovSetDto iovset =
+      m_crestApi.selectIovs(mat_tag, 0, 10, 0, 10, 0, "id.since:ASC");
+  if (iovset.getResources().size() < 1) {
+    std::cerr << "No IOV found for the tag: " << mat_tag << std::endl;
+    return "";
+  }
+  // Get the IOV
+  IovDto iov = iovset.getResources()[0];
+  std::cout << "Found IOV " << iov.toJson().dump(4) << std::endl;
+  // Get the payload using the iov hash
+  std::string hash = iov.getPayloadHash();
+  std::string payload = m_crestApi.getPayload(hash);
+  // Dump the payload to a file
+  std::string file_path = m_file_path + file_name;
+  // Write the payload to the file
+  std::cout << "Dump payload to file " << file_path << std::endl;
+  dumpToFile(file_path, payload);
+  return file_path;
+}
+
+void CrestFileResolver::dumpToFile(const std::string &filePath,
+                                   const std::string &content) {
+  // Open the file in write mode
+  std::ofstream outFile(filePath);
+
+  // Check if the file was successfully opened
+  if (!outFile) {
+    std::cerr << "Error: Could not open file " << filePath << " for writing."
+              << std::endl;
+    return;
+  }
+
+  // Write the content to the file
+  outFile << content;
+
+  // Close the file
+  outFile.close();
+
+  std::cout << "Content successfully written to " << filePath << std::endl;
+}
diff --git a/acts/CrestFileResolver.h b/acts/CrestFileResolver.h
new file mode 100644
index 0000000000000000000000000000000000000000..128bf0e2285ff465ee913f83cf9d316d7460144f
--- /dev/null
+++ b/acts/CrestFileResolver.h
@@ -0,0 +1,68 @@
+
+/**
+ * @file CrestApi/test/CrestApi_test.cxx
+ * @brief Some tests for server methods.
+ */
+#ifndef CRESTAPI_CRESTRESOLVER_H
+#define CRESTAPI_CRESTRESOLVER_H
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include "CrestApi/CrestApi.h"
+#include "CrestApi/GlobalTagMapDto.h"
+#include "CrestApi/GlobalTagMapSetDto.h"
+#include "CrestApi/IovSetDto.h"
+#include "CrestApi/StringUtils.h"
+
+using namespace Crest;
+
+/**
+ * Class to resolve a geometry tracking file.
+ * These files are linked to a geometry global tag, and contain only one IOV
+ * (since=0).
+ */
+class CrestFileResolver {
+ private:
+  std::string m_crest_server;
+  CrestApi m_crestApi;
+  // This should be somehow linked to the type of geometry tag (ITK, ...)
+  std::string mat_label = "ITK";
+  // Base directoy where the file will be dumped.
+  std::string m_file_path;
+
+ public:
+  CrestFileResolver(const std::string &crest_server)
+      : m_crest_server(crest_server),
+        m_crestApi(crest_server),
+        m_file_path("/tmp/crest_test/") {
+    // Check CrestApi version.
+    if (m_crestApi.getCrestVersion() != "v6.0") {
+      std::cerr << "CrestApi version mismatch!" << std::endl;
+    }
+  }
+
+  CrestFileResolver(const std::string &crest_server,
+                    const std::string &file_path, const std::string &label)
+      : m_crest_server(crest_server),
+        m_crestApi(crest_server),
+        mat_label(label),
+        m_file_path(file_path) {
+    // Check CrestApi version
+    if (m_crestApi.getCrestVersion() != "v6.0") {
+      std::cerr << "CrestApi version mismatch!" << std::endl;
+    }
+  }
+  // Destructor
+  ~CrestFileResolver() = default;
+
+  // Resolve the file path for a given geometry global tag.
+  std::string resolveFilePath(const std::string &geometry_gtag,
+                              const std::string &label,
+                              const std::string &file_name);
+  // Dump the payload to a file.
+  void dumpToFile(const std::string &filePath, const std::string &content);
+};
+
+#endif  // CRESTAPI_CRESTRESOLVER_H
\ No newline at end of file
diff --git a/examples/crest_example_fs.cxx b/examples/crest_example_fs.cxx
index 63492ccd7cd8a2801e0a2f1732e06c2fe9b77f11..c37fe8cb641d483feda988ce6674ace94f8fcbd6 100644
--- a/examples/crest_example_fs.cxx
+++ b/examples/crest_example_fs.cxx
@@ -41,7 +41,7 @@ void testCreateGlobalTag_FS(const std::string &tagname) {
   std::cout << std::endl << "test file system: createGlobalTag" << std::endl;
   CrestApiFs myCrestApi = CrestApiFs(true, "/tmp/crest");
 
-  /* 
+  /*
 
   nlohmann::json js = {
       {"name", tagname},
@@ -107,14 +107,14 @@ void testCreateTag_FS(const std::string &tagname) {
   */
 
   // the tag innitialization with the constructor:
-  
+
   TagDto dto(tagname, "time", "test");
   dto.setSynchronization("ALL");
   dto.setObjectType("JSON");
   dto.setStatus("UNLOCKED");
   dto.setLastValidatedTime(0.0);
   dto.setEndOfValidity(0.0);
-  
+
   try {
     myCrestApi.createTag(dto);
     std::cout << std::endl << "test: createTag FS (success)" << std::endl;
@@ -272,16 +272,16 @@ void testStorePayloads_FS(const std::string &tagname) {
   TagDto dto = TagDto();
   dto = dto.fromJson(tag_js);
   */
-  
+
   // the tag innitialization with the constructor:
-  
+
   TagDto dto(tagname, "time", "test");
   dto.setSynchronization("ALL");
   dto.setObjectType("JSON");
   dto.setStatus("UNLOCKED");
   dto.setLastValidatedTime(0.0);
   dto.setEndOfValidity(0.0);
-  
+
   try {
     myCrestApi.createTag(dto);
     std::cout << std::endl
@@ -298,7 +298,7 @@ void testStorePayloads_FS(const std::string &tagname) {
 
   /*
   // OLD variant, StoreSetDto defined via JSON
-  
+
   // Your JSON string
   std::string jsonString = R"(
       {
@@ -325,7 +325,7 @@ void testStorePayloads_FS(const std::string &tagname) {
   */
 
   // New version:
-  
+
   StoreSetDto storeSetDto;
 
   StoreDto dto1(1000, "", "Sample data");
@@ -349,7 +349,7 @@ void testStorePayloads_FS(const std::string &tagname) {
   }
 
   /*
-  
+
   // Your JSON string
   std::string jsonString2 = R"(
       {
@@ -376,7 +376,7 @@ void testStorePayloads_FS(const std::string &tagname) {
   */
 
   // New version:
-  
+
   StoreSetDto storeSetDto2;
 
   StoreDto dto3(3000, "", "Sample data 3");
@@ -550,6 +550,34 @@ void testGetPayload_FS(const std::string &hash) {
   }
 }
 
+void testGetPayload_FS_2(const std::string &tagname) {
+  std::cout << std::endl << "test: getPayload 2" << std::endl;
+  CrestApiFs myCrestApi = CrestApiFs(true, "/tmp/crest");
+
+  try {
+    IovSetDto dto =
+        myCrestApi.selectIovs(tagname, 0, -1, 0, 1000, 0, "id.since:ASC");
+    std::cout << std::endl
+              << "test: listIovs (result) = " << std::endl
+              << dto.toJson().dump(4) << std::endl;
+    std::vector<IovDto> iovs = dto.getResources();
+    for (auto iov : iovs) {
+      std::cout << "iov.since = " << iov.getSince() << std::endl;
+      std::cout << "iov.payloadHash = " << iov.getPayloadHash() << std::endl;
+      std::string payload = myCrestApi.getPayload(iov.getPayloadHash());
+      std::cout << "payload = " << payload.substr(0, 100) << std::endl;
+      PayloadDto payloadDto = myCrestApi.getPayloadMeta(iov.getPayloadHash());
+      std::cout << "payloadDto = " << payloadDto.toJson().dump(4) << std::endl;
+      std::cout << "      size = " << payloadDto.size() << std::endl;
+      std::string streamer = myCrestApi.getStreamerInfo(iov.getPayloadHash());
+      std::cout << "streamerInfo = " << streamer << std::endl;
+    }
+  } catch (const std::exception &e) {
+    std::cout << std::endl << "test: getPayload 2 (failed)" << std::endl;
+    std::cout << e.what() << std::endl;
+  }
+}
+
 void testGetPayloadMeta_FS(const std::string &hash) {
   std::cout << std::endl << "test: getPayloadMeta FS" << std::endl;
 
@@ -766,7 +794,7 @@ void createNTags_FS(const std::string &tagname, int n) {
     */
 
     // the tag innitialization with the constructor:
-    
+
     TagDto dto(tg, "time", "test");
     dto.setSynchronization("ALL");
     dto.setObjectType("JSON");
@@ -912,14 +940,14 @@ void createNGlobalTags_FS(const std::string &tagname, int n) {
     GlobalTagDto dto = GlobalTagDto();
     dto = dto.fromJson(js);
     */
-    
+
     // global tag innitialization with the constructor:
 
     GlobalTagDto dto(tg, "test", "1", "M");
     dto.setValidity(0);
     dto.setType("N");
     dto.setScenario("test");
-    
+
     try {
       myCrestApi.createGlobalTag(dto);
       std::cout << std::endl << "global tag " << tg << " created" << std::endl;
@@ -1111,6 +1139,7 @@ int main() {
   testFindTag_FS(tagname);
   testStorePayloads_FS(tagname);
   testGetSize_FS(tagname);
+  testGetPayload_FS_2(tagname);
   */
 
   /*
diff --git a/examples/crest_example_server.cxx b/examples/crest_example_server.cxx
index 4e84887c751bbf43ffa8f137afaacc7c74038cb5..f0446b2904feb53ea4c4d11d1f46e60d6ad2cb57 100644
--- a/examples/crest_example_server.cxx
+++ b/examples/crest_example_server.cxx
@@ -371,7 +371,7 @@ void testStorePayloads(const std::string &tagname) {
   */
 
   // New version:
-  
+
   StoreSetDto storeSetDto;
 
   StoreDto dto1(1000, "", "Sample data");
@@ -471,6 +471,8 @@ void testGetPayload(const std::string &tagname) {
       PayloadDto payloadDto = myCrestApi.getPayloadMeta(iov.getPayloadHash());
       std::cout << "payloadDto = " << payloadDto.toJson().dump(4) << std::endl;
       std::cout << "      size = " << payloadDto.size() << std::endl;
+      std::string streamer = myCrestApi.getStreamerInfo(iov.getPayloadHash());
+      std::cout << "streamerInfo = " << streamer << std::endl;
     }
   } catch (const std::exception &e) {
     std::cout << std::endl << "test: listIovs (failed)" << std::endl;
@@ -855,7 +857,7 @@ int main(int argc, char *argv[]) {
     testGetSize(tagname);
     testRemoveTag(tagname);
 
-    testFindExistingTagMeta("SCTDAQConfigChipSlim-HEAD");
+    // testFindExistingTagMeta("SCTDAQConfigChipSlim-HEAD");
 
     // testGetVersion();
 
diff --git a/src/CrestApi.cxx b/src/CrestApi.cxx
index 2aad225d4b21a434f80ec37efc08685d4a91d786..b403d6e1edb84cc9a5d41878bb122ba9316bab49 100644
--- a/src/CrestApi.cxx
+++ b/src/CrestApi.cxx
@@ -36,6 +36,7 @@ CrestApi::CrestApi(const std::string &host, const std::string &port,
   m_request.setHost(host);
   m_request.setPort(port);
   m_request.setPrefix(protocol);
+  m_request.initAuth(std::getenv("CREST_AUTH_MODE"));
 }
 
 /**
@@ -60,6 +61,7 @@ CrestApi::CrestApi(std::string_view url, std::string_view apipath,
   m_request.setHost(parsedUrl.host.data());
   m_request.setPort(std::to_string(*parsedUrl.port));
   m_request.setPrefix(parsedUrl.protocol.data());
+  m_request.initAuth(std::getenv("CREST_AUTH_MODE"));
 
   if (parsedUrl.apipath == "") {
     m_PATH = urlPaths[UrlPathIndex::CREST_ROOT];
@@ -481,6 +483,21 @@ void CrestApi::removeGlobalTagMap(const std::string &name,
   std::string retv;
   nlohmann::json js = nullptr;
   retv = m_request.performRequest(current_path, Action::DELETE, js);
+
+  nlohmann::json response = StringUtils::getJson(retv);
+  GlobalTagMapSetDto dto = GlobalTagMapSetDto::fromJson(response);
+  if (dto.size() != 0) {
+    GlobalTagMapDto gtmap = dto.getResources()[0];
+    if (name != gtmap.getGlobalTagName() || tagname != gtmap.getTagName() ||
+        label != gtmap.getLabel()) {
+      throw CrestException(
+          "ERROR in CrestApi::removeGlobalTagMap Cannot delete global tag "
+          "map.");
+    }
+  } else {
+    throw CrestException(
+        "ERROR in CrestApi::removeGlobalTagMap Cannot delete global tag map.");
+  }
 }
 
 //==============================================================================================================
@@ -761,4 +778,57 @@ void CrestApi::checkHash(const std::string &hash, const std::string &str,
   return;
 }
 
+std::string CrestApi::getStreamerInfo(const std::string &hash) {
+  std::string current_path = m_PATH;
+  current_path += urlPaths[UrlPathIndex::PAYLOADS];
+  current_path += urlPaths[UrlPathIndex::DATA];
+  current_path += "?format=STREAMER&hash=";
+  current_path += hash;
+  std::string retv;
+  nlohmann::json js = nullptr;
+  retv = m_request.performRequest(current_path, Action::GET, js);
+  return retv;
+}
+
+RunLumiSetDto CrestApi::listRunInfo(const std::string &since,
+                                    const std::string &until,
+                                    const std::string format,
+                                    const std::string mode, int size, int page,
+                                    const std::string &sort) {
+  std::string current_path = m_PATH;
+  current_path += urlPaths[UrlPathIndex::RUNINFO];
+  current_path += "?since=";
+  current_path += since;
+  current_path += "&until=";
+  current_path += until;
+  current_path += "&format=";
+  current_path += format;
+  current_path += "&mode=";
+  current_path += mode;
+
+  if (size != -1) {
+    current_path += "&size=";
+    current_path += std::to_string(size);
+  }
+  if (page != -1) {
+    current_path += "&page=";
+    current_path += std::to_string(page);
+  }
+  if (sort != "") {
+    current_path += "&sort=";
+    current_path += sort;
+  }
+
+  std::string retv;
+
+  nlohmann::json js = nullptr;
+  retv = m_request.performRequest(current_path, Action::GET, js);
+  nlohmann::json response = StringUtils::getJson(retv);
+
+  RunLumiSetDto dto = RunLumiSetDto::fromJson(response);
+
+  return dto;
+}
+//==============================================================================================================
+
 }  // namespace Crest
diff --git a/src/CrestApiFs.cxx b/src/CrestApiFs.cxx
index 476505ba9c21f2b4280b7f3e7867433a7c976520..ba0922c7f1272e750e492bb4b4dff3cfed733b20 100644
--- a/src/CrestApiFs.cxx
+++ b/src/CrestApiFs.cxx
@@ -160,6 +160,7 @@ GlobalTagSetDto CrestApiFs::listGlobalTags(const std::string &name, int size,
         "ERROR in CrestApiFs::listTags: wrong sort parameter." + sort);
   }
 
+  int totalItems = 0;  // total global tag number
   try {
     std::vector<std::string> taglist = nameList(folder, ascending);
     std::vector<std::string> clearedTaglist;
@@ -178,6 +179,8 @@ GlobalTagSetDto CrestApiFs::listGlobalTags(const std::string &name, int size,
       }
     }
 
+    totalItems = clearedTaglist.size();  // total global tag number
+
     taglist = getVectorPage(clearedTaglist, size, page);
     for (const std::string &tag : taglist) {
       std::string file_name = folder + "/" + tag + "/" + s_FS_GLOBALTAG_FILE;
@@ -190,6 +193,11 @@ GlobalTagSetDto CrestApiFs::listGlobalTags(const std::string &name, int size,
         "ERROR in CrestApiFs::listGlobalTags: cannot get the tag list.");
   }
 
+  // add RespPage:
+  int tPages = std::ceil((double)totalItems / size);
+  RespPage respp(tagSet.size(), totalItems, tPages, page);
+  tagSet.setRespPage(respp);
+
   return tagSet;
 }
 
@@ -268,6 +276,7 @@ TagSetDto CrestApiFs::listTags(const std::string &name, int size, int page,
         "ERROR in CrestApiFs::listTags: wrong sort parameter." + sort);
   }
 
+  int totalItems = 0;  // total tag number
   try {
     std::vector<std::string> taglist = nameList(folder, ascending);
     std::vector<std::string> clearedTaglist;
@@ -286,6 +295,8 @@ TagSetDto CrestApiFs::listTags(const std::string &name, int size, int page,
       }
     }
 
+    totalItems = clearedTaglist.size();  // total tag number
+
     taglist = getVectorPage(clearedTaglist, size, page);
     for (const std::string &tag : taglist) {
       std::string file_name = folder + "/" + tag + "/" + s_FS_TAG_FILE;
@@ -298,6 +309,11 @@ TagSetDto CrestApiFs::listTags(const std::string &name, int size, int page,
         "ERROR in CrestApiFs::listTags: cannot get the tag list.");
   }
 
+  // add RespPage:
+  int tPages = std::ceil((double)totalItems / size);
+  RespPage respp(tagSet.size(), totalItems, tPages, page);
+  tagSet.setRespPage(respp);
+
   return tagSet;
 }
 
@@ -477,6 +493,13 @@ GlobalTagMapSetDto CrestApiFs::findGlobalTagMap(
 
   GlobalTagMapSetDto dto;
   dto = GlobalTagMapSetDto::fromFsJson(js);
+
+  // add RespPage:
+  int totalItems = dto.size();
+  RespPage respp(totalItems, totalItems, 1,
+                 0);  // full global tag map in one response
+  dto.setRespPage(respp);
+
   return dto;
 }
 
@@ -489,10 +512,11 @@ IovSetDto CrestApiFs::selectIovs(
   IovSetDto dto;
 
   nlohmann::json js = nlohmann::json::array();
+  int niovs = 0;
 
   try {
     nlohmann::json iovList = findAllIovs(name);
-    int niovs = iovList.size();
+    niovs = iovList.size();
 
     for (int i = 0; i < niovs; i++) {
       if (iovList[i].find("since") != iovList[i].end()) {
@@ -529,6 +553,11 @@ IovSetDto CrestApiFs::selectIovs(
   nlohmann::json ext = getPage(sorted, size, page);
   dto = IovSetDto::fromFsJson(ext);
 
+  // add RespPage:
+  int tPages = std::ceil((double)niovs / size);
+  RespPage respp(dto.size(), niovs, tPages, page);
+  dto.setRespPage(respp);
+
   return dto;
 }
 
@@ -708,7 +737,6 @@ void CrestApiFs::storePayloadDump(const std::string &tag, uint64_t since,
                         {"objectType", objectType},
                         {"version", version},
                         {"size", js.size()},
-                        {"streamerInfo", streamerInfo},
                         {"compressionType", compressionType},
                         {"insertionTime", getDateAndTime()}};
 
@@ -719,6 +747,9 @@ void CrestApiFs::storePayloadDump(const std::string &tag, uint64_t since,
   outFile << jsn.dump();
   outFile.close();
 
+  // streamer info:
+  createStreamerInfo(hashCode, streamerInfo);
+
   // check if data exists
 
   if (m_data.find(tag) == m_data.end()) {
@@ -815,6 +846,56 @@ PayloadDto CrestApiFs::getPayloadMeta(const std::string &hash) {
   return dto;
 }
 
+std::string CrestApiFs::getStreamerInfo(const std::string &hash) {
+  std::string workDir = m_data_folder;
+  workDir += '/';
+  workDir += getFirstLetters(hash);
+  workDir += '/';
+  workDir += hash;
+  std::string filePath = workDir + "/streamer.json";
+  std::string res = "";
+
+  try {
+    if (std::filesystem::exists(filePath)) {
+      res = getFileString(filePath);
+    } else {
+      throw CrestException("streamer info with hash " + hash +
+                           " does not exist.");
+    }
+  } catch (const std::exception &e) {
+    std::string message = e.what();
+    throw CrestException(
+        "ERROR in CrestApiFs::getStreamerInfo cannot get the "
+        "streamer info form file storage, " +
+        message);
+  }
+
+  return res;
+}
+
+void CrestApiFs::createStreamerInfo(const std::string &hash,
+                                    const std::string streamerInfo) {
+  std::string workDir = m_data_folder;
+  workDir += '/';
+  workDir += getFirstLetters(hash);
+  workDir += '/';
+  workDir += hash;
+  std::string filePath = workDir + "/streamer.json";
+
+  if (m_isRewrite) {
+    if (std::filesystem::exists(std::filesystem::path(filePath))) {
+      std::filesystem::remove(std::filesystem::path(filePath));
+    }
+
+    std::ofstream outFile;
+
+    outFile.open(filePath.c_str());
+    outFile << streamerInfo;
+    outFile.close();
+  }
+}
+//
+
 nlohmann::json CrestApiFs::getPage(nlohmann::json data, int size, int page) {
   nlohmann::json js = nlohmann::json::array();
   int dataSize = data.size();
@@ -989,4 +1070,11 @@ std::string CrestApiFs::getCrestVersion() {
       "CREST server version for file storage.");
 }
 
+PayloadTagInfoSetDto CrestApiFs::listPayloadTagInfo(const std::string &tagname,
+                                                    int size, int page,
+                                                    const std::string &sort) {
+  checkFsException("CrestApiFs::listPayloadTagInfo");
+  return PayloadTagInfoSetDto();
+}
+
 }  // namespace Crest
diff --git a/src/CrestAuth.cxx b/src/CrestAuth.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..98900ec5c219f36856d37dfda229bf423f340365
--- /dev/null
+++ b/src/CrestAuth.cxx
@@ -0,0 +1,263 @@
+// CrestAuth.cxx
+#include <CrestApi/CrestAuth.h>
+#include <CrestApi/CrestLogger.h>
+#include <CrestApi/JwtUtils.h>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+namespace Crest {
+
+CrestAuth::CrestAuth()
+    : m_tokenFilePath(std::getenv("HOME") +
+                      std::string("/.client-exchange-token.json")),
+      m_tokenEndpoint(
+          "https://auth.cern.ch/auth/realms/cern/protocol/openid-connect/"
+          "token"),
+      m_apiEndpoint("https://auth.cern.ch/auth/realms/cern/api-access/token"),
+      m_clientId("crest-client"),
+      m_audience("crest-server"),
+      m_exchangeTokenExpiresAt(0) {}
+
+bool CrestAuth::loadTokens() {
+  std::ifstream file(m_tokenFilePath);
+  if (!file.is_open()) {
+    Logger::log(LogLevel::ERROR,
+                "Failed to open token file: " + m_tokenFilePath);
+    return false;
+  }
+
+  std::string content((std::istreambuf_iterator<char>(file)),
+                      std::istreambuf_iterator<char>());
+  if (content.empty()) {
+    Logger::log(LogLevel::ERROR, "Token file is empty");
+    return false;
+  }
+
+  file.clear();
+  file.seekg(0);
+
+  nlohmann::json js;
+  try {
+    file >> js;
+  } catch (const std::exception& e) {
+    Logger::log(LogLevel::ERROR,
+                "Failed to parse token JSON: " + (std::string)e.what());
+    return false;
+  }
+
+  m_exchangeToken = js.value("access_token", "");
+  m_refreshToken = js.value("refresh_token", "");
+  try {
+    m_exchangeTokenExpiresAt = JwtUtils::extractExp(m_exchangeToken, 30);
+  } catch (const std::exception& e) {
+    Logger::log(LogLevel::ERROR,
+                "Failed to extract 'exp' from JWT: " + (std::string)e.what());
+    m_exchangeTokenExpiresAt = std::time(nullptr) + 300;  // fallback
+  }
+
+  Logger::log(LogLevel::DEBUG, "Loaded exchange and refresh tokens from file");
+  return true;
+}
+
+bool CrestAuth::saveTokens(const nlohmann::json& tokenJson) const {
+  std::ofstream file(m_tokenFilePath);
+  if (!file.is_open()) {
+    Logger::log(LogLevel::ERROR,
+                "Failed to open token file for writing: " + m_tokenFilePath);
+    return false;
+  }
+
+  file << tokenJson.dump();
+  Logger::log(LogLevel::DEBUG, "Saved exchanged token to file");
+  return true;
+}
+
+bool CrestAuth::isExchangeTokenExpired() const {
+  return std::time(nullptr) >= m_exchangeTokenExpiresAt;
+}
+
+std::string CrestAuth::getAccessToken() const {
+  return m_finalAccessToken;
+}
+
+bool CrestAuth::refreshExchangeToken() {
+  std::ostringstream oss;
+  oss << "grant_type=refresh_token"
+      << "&refresh_token=" << m_refreshToken << "&client_id=" << m_clientId;
+
+  std::string response = postRequest(m_tokenEndpoint, oss.str());
+  if (response.empty())
+    return false;
+
+  auto js = nlohmann::json::parse(response, nullptr, false);
+  if (js.is_discarded() || js.contains("error")) {
+    Logger::log(LogLevel::ERROR,
+                "Failed to refresh exchange token: " + js.dump());
+    return false;
+  }
+
+  m_exchangeToken = js["access_token"];
+  m_refreshToken = js.value("refresh_token", m_refreshToken);
+  try {
+    m_exchangeTokenExpiresAt = JwtUtils::extractExp(m_exchangeToken, 30);
+  } catch (const std::exception& e) {
+    Logger::log(LogLevel::ERROR,
+                "Failed to extract 'exp' from JWT: " + (std::string)e.what());
+    m_exchangeTokenExpiresAt = std::time(nullptr) + 300;  // fallback
+  }
+  Logger::log(LogLevel::DEBUG, "Successfully refreshed exchange token");
+  return saveTokens(js);
+}
+
+bool CrestAuth::exchangeTokenForAccess() {
+  CURL* curl = curl_easy_init();
+  if (!curl) {
+    Logger::log(LogLevel::ERROR, "Failed to initialize CURL");
+    return false;
+  }
+
+  if (m_exchangeToken.empty()) {
+    Logger::log(LogLevel::ERROR, "Exchange token is empty");
+    curl_easy_cleanup(curl);
+    return false;
+  }
+
+  std::ostringstream oss;
+  oss << "grant_type=urn:ietf:params:oauth:grant-type:token-exchange"
+      << "&subject_token=" << m_exchangeToken
+      << "&subject_token_type=urn:ietf:params:oauth:token-type:access_token"
+      << "&client_id=" << m_clientId << "&audience=" << m_audience;
+
+  std::string response = postRequest(m_tokenEndpoint, oss.str());
+  curl_easy_cleanup(curl);
+
+  if (response.empty())
+    return false;
+
+  auto js = nlohmann::json::parse(response, nullptr, false);
+  if (js.is_discarded() || !js.contains("access_token")) {
+    Logger::log(LogLevel::ERROR, "Token exchange failed: " + js.dump(2));
+    return false;
+  }
+
+  m_finalAccessToken = js["access_token"];
+
+  Logger::log(LogLevel::DEBUG, "Token exchanged successfully");
+
+  return true;
+}
+
+std::string CrestAuth::postRequest(const std::string& url,
+                                   const std::string& postFields) const {
+  CURL* curl = curl_easy_init();
+  if (!curl)
+    return "";
+
+  std::string response;
+  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str());
+  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
+  curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
+
+  struct curl_slist* headers = nullptr;
+  headers = curl_slist_append(
+      headers, "Content-Type: application/x-www-form-urlencoded");
+  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+  // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+
+  CURLcode res = curl_easy_perform(curl);
+  if (res != CURLE_OK) {
+    std::string errMsg = curl_easy_strerror(res);
+    Logger::log(LogLevel::ERROR, "curl_easy_perform failed: " + errMsg);
+  }
+
+  curl_slist_free_all(headers);
+  curl_easy_cleanup(curl);
+  return response;
+}
+
+size_t CrestAuth::WriteCallback(void* contents, size_t size, size_t nmemb,
+                                void* userp) {
+  size_t totalSize = size * nmemb;
+  std::string* out = static_cast<std::string*>(userp);
+  out->append(static_cast<char*>(contents), totalSize);
+  return totalSize;
+}
+
+bool CrestAuth::setupExchangeCredentials() {
+  Logger::log(LogLevel::DEBUG,
+              "Setting up authorization - requesting access token...");
+
+  bool tokensLoaded = loadTokens();
+  if (!tokensLoaded) {
+    Logger::log(LogLevel::ERROR,
+                "No valid token file found.\nExecute: auth-get-user-token -c "
+                "crest-client -o ~/.client-exchange-token.json");
+    return false;
+  }
+
+  Logger::log(LogLevel::DEBUG, "Checking if exchange token is expired...");
+  if (isExchangeTokenExpired()) {
+    Logger::log(LogLevel::DEBUG,
+                "Exchange token is expired. Attempting refresh...");
+    if (!refreshExchangeToken()) {
+      Logger::log(LogLevel::ERROR,
+                  "Exchange token is expired and refresh failed.\nExecute: "
+                  "auth-get-user-token -c crest-client -o "
+                  "~/.client-exchange-token.json");
+      return false;
+    }
+  }
+
+  if (!exchangeTokenForAccess()) {
+    Logger::log(LogLevel::ERROR, "Failed to obtain access token from exchange");
+    return false;
+  }
+
+  Logger::log(LogLevel::DEBUG, "Setup complete — access token obtained");
+  return true;
+}
+
+bool CrestAuth::setupClientCredentials() {
+  const char* clientId = std::getenv("CREST_CLIENT_ID");
+  const char* clientSecret = std::getenv("CREST_CLIENT_SECRET");
+
+  if (!clientId || !clientSecret) {
+    Logger::log(
+        LogLevel::ERROR,
+        "Missing CREST_CLIENT_ID or CREST_CLIENT_SECRET environment variable.");
+    return false;
+  }
+
+  std::ostringstream oss;
+  oss << "grant_type=client_credentials"
+      << "&client_id=" << clientId << "&client_secret=" << clientSecret
+      << "&subject_token_type=urn:ietf:params:oauth:token-type:access_token"
+      << "scope=openid"
+      << "&audience=" << m_audience;
+
+  std::string response = postRequest(m_apiEndpoint, oss.str());
+  if (response.empty()) {
+    Logger::log(LogLevel::ERROR,
+                "No response received from client credentials request.");
+    return false;
+  }
+
+  auto js = nlohmann::json::parse(response, nullptr, false);
+  if (js.is_discarded() || !js.contains("access_token")) {
+    Logger::log(LogLevel::ERROR,
+                "Failed to obtain access token using client credentials: " +
+                    js.dump(2));
+    return false;
+  }
+
+  m_finalAccessToken = js["access_token"];
+
+  Logger::log(LogLevel::DEBUG,
+              "Access token acquired via client credentials flow");
+
+  return true;
+}
+}  // namespace Crest
diff --git a/src/CrestRequest.cxx b/src/CrestRequest.cxx
index 9d8e9ceb9f000ba6cd95e72a104edaaf92857aeb..cbae7d40ae5f60771599414b7ab37da12c75b78c 100644
--- a/src/CrestRequest.cxx
+++ b/src/CrestRequest.cxx
@@ -77,6 +77,39 @@ std::string CrestRequest::getUrl() {
   return m_url;
 }
 
+void CrestRequest::initAuth(const char *mode) {
+  if (!mode) {
+    Logger::log(LogLevel::WARNING,
+                "CREST_AUTH_MODE is unset — skipping client authorization");
+    return;
+  }
+
+  std::string modeStr = mode;
+  Logger::log(LogLevel::DEBUG, "CREST_AUTH_MODE is set to: " + modeStr);
+
+  if (modeStr == "JWT") {
+    Logger::log(LogLevel::DEBUG, "Authorizing via JWT");
+    m_auth.setupExchangeCredentials();
+  } else if (modeStr == "CLIENT_CREDENTIALS") {
+    Logger::log(LogLevel::DEBUG, "Authorizing via client id and secret");
+    m_auth.setupClientCredentials();
+  } else {
+    Logger::log(LogLevel::DEBUG,
+                "Valid values of CREST_AUTH_MODE: JWT, CLIENT_CREDENTIALS — "
+                "skipping client authorization");
+  }
+}
+
+struct curl_slist *CrestRequest::createAuthHeader() const {
+  struct curl_slist *headers = nullptr;
+  std::string token = m_auth.getAccessToken();
+  if (!token.empty()) {
+    std::string authHeader = "Authorization: Bearer " + token;
+    headers = curl_slist_append(headers, authHeader.c_str());
+  }
+  return headers;
+}
+
 size_t WriteCallback(void *contents, size_t size, size_t nmemb,
                      std::vector<char> *output) {
   size_t total_size = size * nmemb;
@@ -124,7 +157,10 @@ std::string CrestRequest::performRequest(const std::string &current_path,
   /* get a curl handle */
   curl = curl_easy_init();
   std::string stt;
-  struct curl_slist *headers = NULL;
+  struct curl_slist *headers = createAuthHeader();
+  if (headers) {
+    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+  }
   if (curl) {
     std::string url = Crest::StringUtils::appendEndpoint(m_url, current_path);
     std::string s;
@@ -147,7 +183,7 @@ std::string CrestRequest::performRequest(const std::string &current_path,
     // -k analogue:
     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
-
+    // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
     if (js.is_null()) {
       if (action == Action::DELETE)
         curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
@@ -210,7 +246,10 @@ std::vector<char> CrestRequest::getPayloadRequest(
 
   curl_global_init(CURL_GLOBAL_DEFAULT);
   curl = curl_easy_init();
-
+  struct curl_slist *headers = createAuthHeader();
+  if (headers) {
+    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+  }
   if (curl) {
     std::string url = Crest::StringUtils::appendEndpoint(m_url, current_path);
     std::string response;
@@ -252,6 +291,7 @@ std::vector<char> CrestRequest::getPayloadRequest(
     long response_code;
     curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
 
+    curl_slist_free_all(headers);
     curl_easy_cleanup(curl);
 
     // error checking in the server response:
@@ -275,8 +315,10 @@ std::string CrestRequest::uploadPayload(
   curl_global_init(CURL_GLOBAL_DEFAULT);
   curl = curl_easy_init();
 
-  struct curl_slist *headers = NULL;
-
+  struct curl_slist *headers = createAuthHeader();
+  if (headers) {
+    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+  }
   if (curl) {
     std::string url = Crest::StringUtils::appendEndpoint(m_url, current_path);
     std::string response;
diff --git a/src/JwtUtils.cxx b/src/JwtUtils.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f8e2f05d98db3ed69f18b6e1c0282d441205b0c2
--- /dev/null
+++ b/src/JwtUtils.cxx
@@ -0,0 +1,77 @@
+#include <CrestApi/JwtUtils.h>
+
+#include <algorithm>
+#include <nlohmann/json.hpp>
+#include <sstream>
+#include <stdexcept>
+
+namespace Crest {
+
+std::string JwtUtils::base64urlDecode(const std::string& input) {
+  std::string base64 = input;
+  std::replace(base64.begin(), base64.end(), '-', '+');
+  std::replace(base64.begin(), base64.end(), '_', '/');
+  while (base64.length() % 4 != 0)
+    base64 += '=';
+
+  static constexpr unsigned char kDecodeTable[256] = {
+      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+      64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57,
+      58, 59, 60, 61, 64, 64, 64, 0,  64, 64, 64, 0,  1,  2,  3,  4,  5,  6,
+      7,  8,  9,  10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+      25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+      37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64,
+      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+      64, 64, 64, 64};
+
+  std::string output;
+  size_t i = 0;
+  while (i < base64.length()) {
+    uint32_t val = 0;
+    int valb = -8;
+    for (int j = 0; j < 4 && i < base64.length(); ++j) {
+      unsigned char c = base64[i++];
+      if (kDecodeTable[c] == 64)
+        throw std::runtime_error("Invalid base64url character");
+      val = (val << 6) + kDecodeTable[c];
+      valb += 6;
+    }
+    while (valb >= 0) {
+      output.push_back(static_cast<char>((val >> valb) & 0xFF));
+      valb -= 8;
+    }
+  }
+  return output;
+}
+
+std::time_t JwtUtils::extractExp(const std::string& jwt, int graceSeconds) {
+  size_t dot1 = jwt.find('.');
+  size_t dot2 = jwt.find('.', dot1 + 1);
+  if (dot1 == std::string::npos || dot2 == std::string::npos) {
+    throw std::runtime_error("Invalid JWT format");
+  }
+
+  std::string payloadEncoded = jwt.substr(dot1 + 1, dot2 - dot1 - 1);
+  std::string payloadJson = base64urlDecode(payloadEncoded);
+
+  auto js = nlohmann::json::parse(payloadJson, nullptr, false);
+  if (js.is_discarded()) {
+    throw std::runtime_error("Failed to parse JWT payload");
+  }
+
+  if (!js.contains("exp") || !js["exp"].is_number()) {
+    throw std::runtime_error("JWT payload does not contain valid 'exp'");
+  }
+
+  std::time_t rawExp = js["exp"];
+  return rawExp - graceSeconds;
+}
+
+}  // namespace Crest
diff --git a/src/RunLumiDto.cxx b/src/RunLumiDto.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..2b1e5d6e5a69432fb4495a0a6972a74acdd588b8
--- /dev/null
+++ b/src/RunLumiDto.cxx
@@ -0,0 +1,29 @@
+/*
+  Copyright (C) 2020-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include <CrestApi/RunLumiDto.h>
+
+namespace Crest {
+
+RunLumiDto::RunLumiDto() : runNumber(0), lb(0), starttime(0), endtime(0) {}
+
+json RunLumiDto::toJson() const {
+  json rl = {};
+  rl["runNumber"] = runNumber;
+  rl["lb"] = lb;
+  rl["starttime"] = starttime;
+  rl["endtime"] = endtime;
+  return rl;
+}
+
+RunLumiDto RunLumiDto::fromJson(const json &j) {
+  RunLumiDto rl;
+  rl.runNumber = j.value<uint64_t>("runNumber", 0);
+  rl.lb = j.value<uint64_t>("lb", 0);
+  rl.starttime = j.value<uint64_t>("starttime", 0);
+  rl.endtime = j.value<uint64_t>("endtime", 0);
+  return rl;
+}
+
+}  // namespace Crest
diff --git a/src/RunLumiSetDto.cxx b/src/RunLumiSetDto.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a6499b1f89eaaeed04c9ca5d53b6a6d616dca1c1
--- /dev/null
+++ b/src/RunLumiSetDto.cxx
@@ -0,0 +1,30 @@
+/*
+  Copyright (C) 2020-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include <CrestApi/RunLumiSetDto.h>
+
+namespace Crest {
+
+json RunLumiSetDto::toJson() const {
+  json baseJson = CrestBaseResponse::toJson();
+  json jsonResources = json::array();
+  for (const auto &resource : resources) {
+    jsonResources.push_back(((RunLumiDto)resource).toJson());
+  }
+  baseJson["resources"] = jsonResources;
+  return baseJson;
+}
+
+RunLumiSetDto RunLumiSetDto::fromJson(const json &j) {
+  RunLumiSetDto rlSet;
+  rlSet.loadFromJson(j);
+  json jsonResources = j.value("resources", json::array());
+  for (auto it = jsonResources.begin(); it != jsonResources.end(); ++it) {
+    rlSet.resources.push_back(RunLumiDto::fromJson(*it));
+  }
+
+  return rlSet;
+}
+
+}  // namespace Crest
diff --git a/src/StringUtils.cxx b/src/StringUtils.cxx
index bcf41966357b539fd073c5dc795aed3dc0eaaf8f..f6f3e1d1a041d3e8733874ff0c38bd340ae84cf1 100644
--- a/src/StringUtils.cxx
+++ b/src/StringUtils.cxx
@@ -63,7 +63,7 @@ ParsedUrl Crest::StringUtils::parseUrl(std::string_view url) {
 
   // The remaining part is the apipath
   if (!url.empty() && url[0] == '/') {
-    result.apipath = "";
+    result.apipath = url;
   }
 
   return result;
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index e12cbee9b3c5913d98e99752fc50b2b3b204ad55..37d9c7b88800bbf0617047ba776a3a236868a286 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -8,6 +8,7 @@ function(crestapi_add_test TESTNAME)
             Boost::unit_test_framework
             nlohmann_json::nlohmann_json
             CrestApiLib
+            # this is for ACTS: CrestResolverLib
     )
     add_test(
         NAME ${TESTNAME}
@@ -15,8 +16,10 @@ function(crestapi_add_test TESTNAME)
     )
 endfunction()
 
+
 # Declare the tests.
 crestapi_add_test(CrestApi_test)
 crestapi_add_test(CrestApiFs_test)
 crestapi_add_test(json_parse)
-#crestapi_add_test(test-json)
+## crestapi_add_test(test-json)
+## crestapi_add_test(CrestFileResolver_test)
diff --git a/test/CrestApi_test.cxx b/test/CrestApi_test.cxx
index 9e675120322462dbfef499a6993659dd5a5a1a26..fcb0812f2ff8d08610a91a6a2def84529027223d 100644
--- a/test/CrestApi_test.cxx
+++ b/test/CrestApi_test.cxx
@@ -20,7 +20,7 @@ using namespace Crest;
 
 BOOST_AUTO_TEST_SUITE(CrestApiTest)
 
-const std::string crest_server = "https://atlaf-alma9-01.cern.ch/api-v6.0";
+const std::string crest_server = "http://atlaf-alma9-02.cern.ch:8080/api-v6.0";
 const std::string tagname = "test_ctest_tag_01";
 const std::string global_tag = "TEST_GLOBAL_TAG_01";
 
diff --git a/test/CrestFileResolver_test.cxx b/test/CrestFileResolver_test.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..abb1b4190c679b0c7083c468089fd43123534dde
--- /dev/null
+++ b/test/CrestFileResolver_test.cxx
@@ -0,0 +1,46 @@
+
+/**
+ * @file CrestApi/test/CrestApi_test.cxx
+ * @brief Some tests for server methods.
+ */
+
+#include "CrestApi/GlobalTagMapDto.h"
+#include "CrestApi/GlobalTagMapSetDto.h"
+#include "CrestApi/IovSetDto.h"
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MAIN
+#define BOOST_TEST_MODULE TEST_CRESTAPI
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include "../CrestApi/CrestApi.h"
+#include "../CrestApi/StringUtils.h"
+#include "../acts/CrestFileResolver.h"
+
+using namespace Crest;
+
+const std::string crest_server = "http://atlaf-alma9-02.cern.ch:8080/api-v6.0";
+const std::string global_tag = "TEST-GEOMETRY-01";
+
+int main() {
+  std::string geoglobal_tag = "TEST-GEOMETRY-01";
+  std::cout << "Global tag for geometry: " << geoglobal_tag << std::endl;
+
+  try {
+    // Create an instance of CrestFileResolver
+    CrestFileResolver crestFileResolver(crest_server, "/tmp/crest_test/",
+                                        "/Material/TrackingGeo");
+    // Resolve the file path
+    std::string file_path = crestFileResolver.resolveFilePath(
+        geoglobal_tag, "/Material/TrackingGeo", "test_file.json");
+    // Print the parsed inner JSON
+    std::cout << "Dumped JSON from Geometry Global Tag for tracking material: "
+              << file_path << std::endl;
+  } catch (const std::exception &e) {
+    std::cerr << "Error parsing JSON: " << e.what() << std::endl;
+  }
+
+  return 0;
+}
diff --git a/test/test-json.cxx b/test/test-json.cxx
index bfd349542250cd9894386fb7e7121bcaa6d5a6f7..a93618a1893d3fbfaa17e03f3734497a864c44e5 100644
--- a/test/test-json.cxx
+++ b/test/test-json.cxx
@@ -79,10 +79,11 @@ int main() {
   std::cout << std::endl;
 
   // Fill a json object with data
+  bool test_boolean = true;
   json j4;
   j4["a_char"] = new char('c');
   j4["a_string"] = "string";
-  j4["a_bool"] = true;
+  j4["a_bool"] = test_boolean;
   j4["a_int"] = 42;
   j4["a_float"] = 3.141;
   j4["a_null"] = nullptr;
@@ -90,6 +91,8 @@ int main() {
   j4["an_unsigned_long"] = 42ul;
   j4["an_unsigned_long_long"] = 42ull;
 
+  // Print the json object
+  std::cout << "Print JSON object j4:\n";
   std::cout << j4 << '\n';
 
   // Read back data using iterators
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4dcd6489500c4b1cbcd5d4e491b2277bdb724204
--- /dev/null
+++ b/tools/CMakeLists.txt
@@ -0,0 +1,96 @@
+# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
+# Set the name of the package.
+cmake_minimum_required(VERSION 3.12)
+project(CrestContainer VERSION 6.1 LANGUAGES CXX)
+
+# Find the necessary externals.
+#find_package(CrestApi 6.1 REQUIRED)
+
+
+# Set the C++ standard to use.
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL
+    "Whether to enable compiler-specific C++ extensions")
+
+# Set the default library type to build.
+option(BUILD_SHARED_LIBS
+    "Flag for building shared/static libraries" TRUE)
+
+# Use the standard GNU installation directories.
+include(GNUInstallDirs)
+set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/CrestContainer")
+
+# Turn on all warnings with GCC and Clang.
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
+endif()
+
+# Declare the header and source file names.
+set(HEADERS
+    "./CrestContainer.h"
+)
+
+set(SOURCES
+    "./CrestContainer.cxx"
+)
+# Use RPATH for build tree
+set(CMAKE_SKIP_BUILD_RPATH FALSE)
+# Don't use RPATH for install tree when building
+set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
+# Add the automatically determined parts of the RPATH
+set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+
+# Set up the build of the main library of the project.
+add_library(CrestContainerLib ${SOURCES} ${HEADERS})
+target_link_libraries(CrestContainerLib
+    PUBLIC
+        CURL::libcurl
+        Boost::boost
+        nlohmann_json::nlohmann_json
+	CrestApiLib
+    PRIVATE
+        OpenSSL::SSL
+)
+target_include_directories(CrestContainerLib
+    PUBLIC
+        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+set_target_properties(CrestContainerLib PROPERTIES
+    PUBLIC_HEADER "${HEADERS}"
+    VERSION "${PROJECT_VERSION}"
+)
+
+# Install the library.
+install(TARGETS CrestContainerLib
+    EXPORT CrestContainerTargets
+    RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+    LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+    ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+    PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/CrestContainer"
+)
+
+# Export the project.
+include(CMakePackageConfigHelpers)
+write_basic_package_version_file(
+    "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CrestContainerConfigVersion.cmake"
+    VERSION "${PROJECT_VERSION}"
+    COMPATIBILITY AnyNewerVersion
+)
+configure_package_config_file(
+    "${CMAKE_CURRENT_SOURCE_DIR}/cmake/CrestContainerConfig.cmake.in"
+    "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CrestContainerConfig.cmake"
+    INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}"
+    PATH_VARS CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_LIBDIR
+)
+install(FILES
+    "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CrestContainerConfigVersion.cmake"
+    "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CrestContainerConfig.cmake"
+    DESTINATION "${CMAKE_INSTALL_CMAKEDIR}"
+)
+install(EXPORT CrestContainerTargets
+    NAMESPACE CrestApi::
+    DESTINATION "${CMAKE_INSTALL_CMAKEDIR}"
+)
diff --git a/tools/CrestContainer.cxx b/tools/CrestContainer.cxx
index 2e31ab0a4dd483c35824c14a1e1c3c1644a5de35..747c29d7b57b0e7d001f945b50a0b0a84427c695 100644
--- a/tools/CrestContainer.cxx
+++ b/tools/CrestContainer.cxx
@@ -4,6 +4,7 @@
 
 #include "CrestContainer.h"
 
+#include <CrestApi/CrestCondException.h>
 #include <stdarg.h>
 
 #include <boost/algorithm/string.hpp>
@@ -13,33 +14,15 @@
 #include <fstream>
 #include <iomanip>
 
-#include "CrestApi/CrestCondException.h"
-
 using json = nlohmann::json;
 
-Crest::CrestContainer::CrestContainer() : m_modeId(ModeId::Standard) {
-  initStringToType();
+Crest::CrestContainer::CrestContainer(Crest::ModeId mode) : m_modeId(mode) {
+  ;
 }
 Crest::CrestContainer::~CrestContainer() {
   flush();
 }
 
-void Crest::CrestContainer::initStringToType() {
-  // Loop over key value pairs in s_typeToString map and fill s_StringToType
-  for (const auto &[key, value] : s_typeToString) {
-    s_StringToType[value] = key;
-  }
-}
-
-void Crest::CrestContainer::addStreamerInfoField(const std::string &key,
-                                                 const std::string &value) {
-  m_streamer_info_data[key] = value;
-}
-
-void Crest::CrestContainer::cleanStreamerInfo() {
-  m_streamer_info_data.clear();
-}
-
 bool Crest::CrestContainer::isVectorPayload() {
   return m_isVectorPayload;
 }
@@ -49,11 +32,21 @@ void Crest::CrestContainer::setVectorPayload(bool isVectorPayload) {
 
 Crest::TypeId Crest::CrestContainer::stringToTypeId(
     const std::string &type) const {
-  auto it = s_StringToType.find(type);
-  if (it == s_StringToType.end()) {
-    throw CommonCrestException("The type of parameter is not defined.");
+  for (auto &t : s_typeToString) {
+    if (t.second.compare(type) == 0)
+      return t.first;
   }
-  return it->second;
+  throw CommonCrestException("The type of parameter is not defined.");
+}
+
+bool Crest::CrestContainer::compareStrTimestamp(std::string as,
+                                                std::string bs) {
+  auto a = std::stol(as);
+  auto b = std::stol(bs);
+
+  // first parameter should be greater than
+  // second one (for decreasing order)
+  return a < b;
 }
 
 // Function to convert an integer to a TypeId
@@ -64,8 +57,8 @@ Crest::TypeId Crest::CrestContainer::intToTypeId(int value) const {
   return static_cast<Crest::TypeId>(value);
 }
 
-std::string Crest::CrestContainer::base64Encode(const uint8_t *data,
-                                                unsigned int len) {
+std::string Crest::CrestContainer::base64_encode(const uint8_t *data,
+                                                 unsigned int len) {
   using namespace boost::archive::iterators;
   typedef base64_from_binary<transform_width<const char *, 6, 8>>
       base64_encoder;
@@ -81,7 +74,7 @@ std::string Crest::CrestContainer::base64Encode(const uint8_t *data,
 }
 
 // Decode base64 data to binary
-std::vector<unsigned char> Crest::CrestContainer::base64Decode(
+std::vector<unsigned char> Crest::CrestContainer::base64_decode(
     const std::string &encodedData) {
   using namespace boost::archive::iterators;
   typedef transform_width<binary_from_base64<std::string::const_iterator>, 8, 6>
@@ -160,10 +153,8 @@ void Crest::CrestContainer::addRecord(const char *name, int number, ...) {
       case TypeId::String4k:
       case TypeId::String64k:
       case TypeId::String16M:
-      case TypeId::String128M:
       case TypeId::Blob64k:
       case TypeId::Blob16M:
-      case TypeId::Blob128M:
         m_row[name] = std::string(va_arg(ap, const char *));
         break;
       default:
@@ -179,22 +170,21 @@ void Crest::CrestContainer::addData(const char *channel_id) {
 
 void Crest::CrestContainer::addExternalData(const char *channel_id,
                                             const nlohmann::json &data) {
-
-  validatePayloadSize(data);
+  // std::cerr<<"addExternalData channel_id="<<channel_id<<"
+  // json="<<data.dump()<<std::endl;
   nlohmann::json arr_data =
       m_isVectorPayload ? nlohmann::json::array() : nlohmann::json();
-
-  for (const auto &data_row : data)  // m_vector_data)
-  {
-    auto row_arr_data = createRowArray(data_row);
-
-    if (m_isVectorPayload) {
+  if (m_isVectorPayload) {
+    for (const auto &data_row : data)  // m_vector_data)
+    {
+      auto row_arr_data = createRowArray(data_row);
       arr_data.push_back(row_arr_data);
-    } else {
-      arr_data = row_arr_data;
     }
+    m_payload[channel_id] = arr_data;
+  } else {
+    auto row_arr_data = createRowArray(data);
+    m_payload[channel_id] = row_arr_data;
   }
-  m_payload[channel_id] = arr_data;
   m_vector_data.clear();
   m_row.clear();
 }
@@ -203,12 +193,12 @@ void Crest::CrestContainer::validatePayloadSize(
     const nlohmann::json &data) const {
   if (!data.is_array())
     throw CommonCrestException(
-        "The format of data is wrong. It should be the "
-        "vector (size 1 for non vector payload)");
+        "The format of data is wrong. It should be the vector (size 1 for non "
+        "vector payload)");
   if (!m_isVectorPayload && m_vector_data.size() > 1) {
     throw CommonCrestException(
-        "The payload is not a vector, but the size "
-        "seems to be larger than 1....");
+        "The payload is not a vector, but the size seems to be larger than "
+        "1....");
   }
 }
 
@@ -228,13 +218,28 @@ nlohmann::json Crest::CrestContainer::createRowArray(
 void Crest::CrestContainer::addIov(const uint64_t since) {
   m_iov_data["since"] = since;
   m_iov_data["data"] = m_payload;
-  m_full_data[std::to_string(since)] = m_payload;
+  m_full_data[since] = m_payload;
   m_payload.clear();
 }
 
 void Crest::CrestContainer::selectIov(const uint64_t since) {
+  // std::cerr<<"Crest::CrestContainer::selectIov start"<<std::endl;
   m_iov_data["since"] = since;
-  m_iov_data["data"] = m_full_data[std::to_string(since)];
+  if (m_full_data.contains(since)) {
+    m_iov_data["data"] = m_full_data[since];
+    m_payload = m_full_data[since];
+  } else {
+    m_iov_data["data"] = {};
+    m_payload = {};
+  }
+  // std::cerr<<"Crest::CrestContainer::selectIov end"<<std::endl;
+}
+
+uint64_t Crest::CrestContainer::getFirstTime() {
+  if (m_full_data.size() == 0) {
+    throw CommonCrestException("No IOV in CrestContainer");
+  }
+  return m_full_data.begin()->first;
 }
 
 std::vector<std::string> Crest::CrestContainer::channelIds() {
@@ -242,6 +247,7 @@ std::vector<std::string> Crest::CrestContainer::channelIds() {
   for (auto &x : m_iov_data["data"].items()) {
     chs.push_back(x.key());
   }
+  sort(chs.begin(), chs.end(), Crest::CrestContainer::compareStrTimestamp);
   return chs;
 }
 const std::vector<std::pair<std::string, Crest::TypeId>> &
@@ -249,7 +255,7 @@ Crest::CrestContainer::getMPayloadSpec() {
   return m_payload_spec;
 }
 
-const nlohmann::json &Crest::CrestContainer::getPayloadChannel(
+const nlohmann::json Crest::CrestContainer::getPayloadChannel(
     const char *channel_id) {
   if (m_payload.empty()) {
     m_payload = m_iov_data["data"];
@@ -297,8 +303,7 @@ void Crest::CrestContainer::putRow2Vector() {
 const nlohmann::json &Crest::CrestContainer::getRow() {
   if (m_isVectorPayload)
     return m_vector_data;
-  m_vector_data.push_back(m_row);
-  return m_vector_data;
+  return m_row;
 }
 
 const nlohmann::json &Crest::CrestContainer::getPayload() {
@@ -336,27 +341,6 @@ std::string Crest::CrestContainer::getJsonIovData() {
   return m_iov_data.dump();
 }
 
-nlohmann::json Crest::CrestContainer::getStoreSetDto() {
-  nlohmann::json j;
-  nlohmann::json resources = nlohmann::json::array();
-
-  nlohmann::json storeDto;
-  // Loop over the iov list container to add the data to the storeDto
-  // Iterating over the keys of m_full_data
-  for (auto &[key, data] : m_full_data.items()) {
-    storeDto["since"] = (uint64_t)std::stoull(key);
-    storeDto["data"] = data.dump();
-    storeDto["streamerInfo"] = m_streamer_info_data.dump();
-    resources.push_back(storeDto);
-  }
-
-  j["resources"] = resources;
-  j["format"] = "StoreSetDto";
-  j["datatype"] = "data";
-  j["size"] = resources.size();
-  return j;
-}
-
 json Crest::CrestContainer::getPayloadSpec() {
   json pspec_data = json::array();
   for (auto &column : m_payload_spec) {
@@ -523,17 +507,120 @@ void Crest::CrestContainer::parseOldFormat(std::string &colName,
       }
       default: {
         throw std::runtime_error("UNTREATED TYPE!");
-        break;
       }
     }
+
   } catch (json::exception &e) {
     std::cerr << e.what() << std::endl;
     throw std::runtime_error(e.what());
   }
 }
-
-void Crest::CrestContainer::fromJson(const uint64_t since,
-                                     const nlohmann::json &j_in) {
+void Crest::CrestContainer::parseData(const nlohmann::json &values) {
+  if (values.is_array() && values.size() == m_payload_spec.size()) {
+    for (size_t i = 0; i < values.size(); ++i) {
+      const auto &spec = m_payload_spec[i];
+      std::string colName = spec.first;
+      TypeId colType = spec.second;
+      if (values[i].is_string() &&
+          (colType == TypeId::UChar || colType == TypeId::Bool ||
+           colType == TypeId::Int16 || colType == TypeId::UInt16 ||
+           colType == TypeId::Int32 || colType == TypeId::UInt32 ||
+           colType == TypeId::Int64 || colType == TypeId::UInt63 ||
+           colType == TypeId::Float || colType == TypeId::Double)) {
+        parseOldFormat(colName, colType, values[i]);
+        continue;
+      }
+      if (values[i].is_null()) {
+        m_row[colName] = nullptr;
+        continue;
+      }
+      switch (colType) {
+        case TypeId::Bool:
+          m_row[colName] = values[i].get<bool>();
+          break;
+        case TypeId::UChar:
+          m_row[colName] = values[i].get<unsigned char>();
+          break;
+        case TypeId::Int16:
+        case TypeId::Int32:
+          m_row[colName] = values[i].get<int>();
+          break;
+        case TypeId::UInt16:
+        case TypeId::UInt32:
+          m_row[colName] = values[i].get<unsigned int>();
+          break;
+        case TypeId::UInt63:
+          m_row[colName] = values[i].get<uint64_t>();
+          break;
+        case TypeId::Int64:
+          m_row[colName] = values[i].get<int64_t>();
+          break;
+        case TypeId::Float:
+        case TypeId::Double:
+          m_row[colName] = values[i].get<double>();
+          break;
+        case TypeId::String255:
+        case TypeId::String4k:
+        case TypeId::String64k:
+        case TypeId::String16M:
+        case TypeId::String128M:
+          m_row[colName] = values[i].get<std::string>();
+          break;
+        case TypeId::Blob128M:
+        case TypeId::Blob64k:
+        case TypeId::Blob16M:
+          m_row[colName] = values[i].get<std::string>();
+          break;
+        default:
+          throw CommonCrestException(
+              "CrestContainer::parseData: Unsupported column type.");
+      }
+    }
+  } else {
+    if (!values.is_array())
+      std::cerr << "CrestContainer::parseData values is not array" << std::endl;
+    else
+      std::cerr << "CrestContainer::parseData values number=" << values.size()
+                << " m_payload_spec.size()=" << m_payload_spec.size()
+                << std::endl;
+    throw CommonCrestException(
+        "CrestContainer::parseData: Mismatch in number of values.");
+  }
+}
+std::vector<uint64_t> Crest::CrestContainer::fromJson(
+    uint64_t since, const nlohmann::json &j_in) {
+  if (m_modeId == Crest::ModeId::Standard) {
+    std::cerr << "CrestContainer::fromJson mode=Standard" << std::endl;
+    nlohmann::json j = j_in;
+    if (j.is_string()) {
+      std::istringstream ss(to_string(j));
+      std::string st;
+      ss >> std::quoted(st);
+      j = json::parse(st);
+    }
+    // Accessing the "data" object
+    if (j.contains("data") && j["data"].is_object()) {
+      readCommonType(since, j_in);
+    } else if (j.is_object()) {
+      readCommonType(since, j);
+    } else {
+      std::cerr << "CrestContainer::fromJson json:" << j << std::endl;
+      throw CommonCrestException(
+          "CrestContainer::fromJson: JSON  is not a JSON object.");
+    }
+    std::vector<uint64_t> ret;
+    ret.push_back(since);
+    return ret;
+  } else if (m_modeId == Crest::ModeId::DCS_FULL) {
+    std::cerr << "CrestContainer::fromJson mode=DCS_FULL" << std::endl;
+    return readDcsFullType(j_in);
+  } else {
+    throw CommonCrestException(
+        "CrestContainer::fromJson: Unsupported type of payload.");
+  }
+}
+std::vector<uint64_t> Crest::CrestContainer::readDcsFullType(
+    const nlohmann::json &j_in) {
   nlohmann::json j = j_in;
   if (j.is_string()) {
     std::istringstream ss(to_string(j));
@@ -541,96 +628,119 @@ void Crest::CrestContainer::fromJson(const uint64_t since,
     ss >> std::quoted(st);
     j = json::parse(st);
   }
-  if (m_modeId != ModeId::Standard)
-    throw CommonCrestException("Unsupported type of payload.");
-  // Accessing the "data" object
+  // std::cerr<<"readDcsFullType: "<<j<<std::endl;
+  nlohmann::json dcs_data;
   if (j.contains("data") && j["data"].is_object()) {
-    const auto &data = j["data"];
-
-    // Loop over each channel in the data
-    for (const auto &channel : data.items()) {
-      std::string channelKey = channel.key();
-      const auto &data_ch = channel.value();
-      nlohmann::json vecJson(json::value_t::array);
-      if (m_isVectorPayload)
-        vecJson = data_ch;
+    // std::cerr<<"readDcsFullType: "<<j<<std::endl;
+    dcs_data = j["data"];
+  } else
+    dcs_data = j;
+  std::vector<uint64_t> ret;
+  if (j.is_object()) {
+    for (const auto &[key, value] : dcs_data.items()) {
+      uint64_t since = std::stoull(key);
+      // std::cerr<<"read since="<<since<<std::endl;
+      readCommonType(since, value);
+      ret.push_back(since);
+      /*if(data.contains("since"))
+        since=data["since"].template get<std::int64_t>();
       else
-        vecJson.push_back(data_ch);
-
-      for (const auto &values : vecJson) {
-        // TODO: this will not work for vector payloads
-        // Check if the number of values in the array matches the expected
-        // number of columns
-        if (values.is_array() && values.size() == m_payload_spec.size()) {
-          for (size_t i = 0; i < values.size(); ++i) {
-            const auto &spec = m_payload_spec[i];
-            std::string colName = spec.first;
-            TypeId colType = spec.second;
-            if (values[i].is_string() &&
-                (colType == TypeId::Bool || colType == TypeId::Int16 ||
-                 colType == TypeId::UInt16 || colType == TypeId::Int32 ||
-                 colType == TypeId::UInt32 || colType == TypeId::Int64 ||
-                 colType == TypeId::UInt63 || colType == TypeId::Float ||
-                 colType == TypeId::Double)) {
-              parseOldFormat(colName, colType, values[i]);
-              continue;
-            }
-            switch (colType) {
-              case TypeId::Bool:
-                m_row[colName] = values[i].get<bool>();
-                break;
-              case TypeId::UChar:
-                m_row[colName] = values[i].get<unsigned char>();
-                break;
-              case TypeId::Int16:
-              case TypeId::Int32:
-                m_row[colName] = values[i].get<int>();
-                break;
-              case TypeId::UInt16:
-              case TypeId::UInt32:
-                m_row[colName] = values[i].get<unsigned int>();
-                break;
-              case TypeId::UInt63:
-                m_row[colName] = values[i].get<uint64_t>();
-                break;
-              case TypeId::Int64:
-                m_row[colName] = values[i].get<int64_t>();
-                break;
-              case TypeId::Float:
-              case TypeId::Double:
-                m_row[colName] = values[i].get<double>();
-                break;
-              case TypeId::String255:
-              case TypeId::String4k:
-              case TypeId::String64k:
-              case TypeId::String16M:
-              case TypeId::String128M:
-                m_row[colName] = values[i].get<std::string>();
-                break;
-              case TypeId::Blob128M:
-              case TypeId::Blob64k:
-              case TypeId::Blob16M:
-                m_row[colName] = values[i].get<std::string>();
-                break;
-              default:
-                throw CommonCrestException("Unsupported column type.");
-            }
-          }
-        } else {
-          std::cerr << "CrestContainer::fromJson: Mismatch in number of values "
-                       "for channel "
-                    << channelKey << std::endl;
-        }
-        if (m_isVectorPayload)
-          putRow2Vector();
-      }
-      addData(channelKey.c_str());
+        throw CommonCrestException("CrestContainer::readDcsFullType: Wrong
+      payload format."); readCommonType(since,data);*/
     }
-  } else {
-    std::cerr << "CrestContainer::fromJson: JSON does not contain a 'data' "
-                 "object or it is not a JSON object."
-              << std::endl;
-    std::cerr << "CrestContainer::fromJson json:" << j << std::endl;
+  }
+  return ret;
+}
+void Crest::CrestContainer::readCommonType(uint64_t since,
+                                           const nlohmann::json &j_in) {
+  // std::cerr<<"readCommonType j_in="<<j_in.dump()<<std::endl;
+  //  Loop over each channel in the data
+  for (const auto &channel : j_in.items()) {
+    std::string channelKey = channel.key();
+    const auto &data_ch = channel.value();
+    nlohmann::json vecJson(json::value_t::array);
+    if (m_isVectorPayload)
+      vecJson = data_ch;
+    else
+      vecJson.push_back(data_ch);
+
+    for (const auto &values : vecJson) {
+      parseData(values);
+      if (m_isVectorPayload)
+        putRow2Vector();
+    }
+    addData(channelKey.c_str());
   }
   addIov(since);
+  // std::cout << "       m_iov_data: " << m_iov_data.dump(2) << std::endl;
+  //  std::cout << "CondContainer: from json method has filled internal
+  //  attributes" << std::endl;
+}
+
+nlohmann::json Crest::CrestContainer::getStoreSetDto(uint64_t period) {
+  nlohmann::json j;
+  nlohmann::json resources = nlohmann::json::array();
+  if (m_modeId == Crest::ModeId::Standard) {
+    nlohmann::json storeDto;
+    // Loop over the iov list container to add the data to the storeDto
+    for (const auto &[key, value] : m_full_data) {
+      storeDto["since"] = key;
+      storeDto["data"] = value.dump();
+      storeDto["streamerInfo"] = "";  // m_streamer_info_data.dump();
+      resources.push_back(storeDto);
+    }
+  } else if (m_modeId == Crest::ModeId::DCS_FULL) {
+    uint64_t since = getFirstTime();
+    //  std::cerr<<"Number of IOV="<<m_full_data.size()<<std::endl;
+    nlohmann::json storeDto;
+    nlohmann::json dcs_payload;
+    nlohmann::json curPayload = m_full_data[since];
+    // std::cerr<<"Number of chs="<<curPayload.size()<<std::endl;
+    // for (std::pair<uint64_t, uint64_t> pair : m_iovs) {
+    for (const auto &[key, value] : m_full_data) {
+      curPayload.update(value);
+      dcs_payload[std::to_string(key)] = curPayload;
+      if (period > 0 && (key - since) > period) {
+        storeDto["since"] = since;
+        storeDto["data"] = dcs_payload.dump();
+        storeDto["streamerInfo"] = "";
+        resources.push_back(storeDto);
+        since = key;
+        dcs_payload = {};
+      }
+    }
+    // nlohmann::json obj={};
+    // obj["iovs"]=iovs;
+    // obj["obj"]=dcs_payload;
+    if (dcs_payload.size() > 0) {
+      storeDto["since"] = since;
+      storeDto["data"] = dcs_payload.dump();
+      storeDto["streamerInfo"] = "";
+      resources.push_back(storeDto);
+    }
+  }
+  j["resources"] = resources;
+  j["format"] = "StoreSetDto";
+  j["datatype"] = "data";
+  j["size"] = resources.size();
+
+  return j;
+}
+
+void Crest::CrestContainer::addChannel(const std::string &channelId,
+                                       const std::string &channelName) {
+  // Check if the channel is already in the map
+  if (m_chanMap.find(channelId) == m_chanMap.end()) {
+    if (channelName.c_str() == nullptr) {
+      m_chanMap[channelId] = "";
+    } else {
+      m_chanMap[channelId] = channelName;
+    }
+    std::cout << "CrestContainer: added to m_chanMap " << channelId << " = "
+              << m_chanMap[channelId] << std::endl;
+    return;
+  }
+  std::cout << "CrestContainer: ChannelID " << channelId
+            << " found in map ... don't do anything - size is "
+            << m_chanMap.size() << std::endl;
 }
diff --git a/tools/CrestContainer.h b/tools/CrestContainer.h
index f5315e34384767c6852c84d78941f46591b0b749..5a8cc30aaa26f81418b8d36939433b6ee1421192 100644
--- a/tools/CrestContainer.h
+++ b/tools/CrestContainer.h
@@ -68,50 +68,26 @@ const static std::map<TypeId, std::string> s_typeToString = {
 enum class ModeId { Standard, DCS, DCS_FULL };
 class CrestContainer {
  private:
-  std::map<std::string, TypeId> s_StringToType;
   std::vector<std::pair<std::string, TypeId>> m_payload_spec;
   nlohmann::json m_payload = {};
   nlohmann::json m_row = {};
   nlohmann::json m_iov_data = {};
-  nlohmann::json m_streamer_info_data = {};
   nlohmann::json m_vector_data = nlohmann::json::array();
-  // nlohmann::json m_iov_list=nlohmann::json::array();
+  std::map<uint64_t, nlohmann::json> m_full_data;
+  // Utility map to store the channel_id and the index of the channel
+  std::map<std::string, std::string> m_chanMap;
+  std::map<std::string, std::string> m_chanIdxMap;
 
-  nlohmann::json m_full_data = {};
   ModeId m_modeId;
   bool m_isVectorPayload = false;
-  void initStringToType();
 
-  void validatePayloadSize(const nlohmann::json &data) const;
-  nlohmann::json createRowArray(const nlohmann::json &data_row) const;
-  const nlohmann::json &getRow();
+  void validatePayloadSize(const nlohmann::json& data) const;
+  nlohmann::json createRowArray(const nlohmann::json& data_row) const;
+  const nlohmann::json& getRow();
 
  public:
-  /**
-   * Constructor and destructor.
-   * The container is used to store the payload and the iov data, helping in the
-   * definition of the payload structure. The payload is a json object that is
-   * added to the iov data. It contains a set of channels, each one with its own
-   * data. Once the container has been filled, it can be converted to a json
-   * object. When consumed, it is necessary to flush it in order to reuse it.
-   */
-  CrestContainer();
+  CrestContainer(ModeId mode = ModeId::Standard);
   ~CrestContainer();
-
-  /**
-   * Utility function to add a field to the streamer info.
-   * The streamer info is a json object that is added to the payload.
-   * It is used to store metadata information about the payload.
-   * @param key The key of the field.
-   * @param value The value of the field.
-   */
-  void addStreamerInfoField(const std::string &key, const std::string &value);
-
-  /**
-   * Utility function to clean the streamer info.
-   */
-  void cleanStreamerInfo();
-
   /**
    * @brief It adds a column to the payload specification.
    * @param name The name of the column.
@@ -121,9 +97,9 @@ class CrestContainer {
    * m_payload_spec. The methods with a different signature are just overloads
    * to make it easier to use.
    */
-  void addColumn(const std::string &name, TypeId type);
-  void addColumn(const std::string &name, const char *type);
-  void addColumn(const std::string &name, uint32_t type);
+  void addColumn(const std::string& name, TypeId type);
+  void addColumn(const std::string& name, const char* type);
+  void addColumn(const std::string& name, uint32_t type);
 
   /**
    * @brief It sets the mode of the container.
@@ -131,7 +107,7 @@ class CrestContainer {
   bool isVectorPayload();
   void setVectorPayload(bool isVectorPayload);
 
-  Crest::TypeId stringToTypeId(const std::string &type) const;
+  Crest::TypeId stringToTypeId(const std::string& type) const;
   Crest::TypeId intToTypeId(int value) const;
 
   /**
@@ -148,7 +124,12 @@ class CrestContainer {
    *
    * This method adds a null to the payload. It fills the json object m_row.
    */
-  void addNullRecord(const char *name);
+  void addNullRecord(const char* name);
+
+  /**
+   * @brief It adds a channel to the channels map.
+   */
+  void addChannel(const std::string& channelId, const std::string& channelName);
 
   /**
    * @brief It adds a record to the payload.
@@ -158,7 +139,7 @@ class CrestContainer {
    *
    * This method adds a record to the payload. It fills the json object m_row.
    */
-  void addRecord(const char *name, int number, ...);
+  void addRecord(const char* name, int number, ...);
   /**
    * @brief It associate the payload row to a channel_id.
    * @param channel_id The channel_id to associate the payload row.
@@ -166,7 +147,7 @@ class CrestContainer {
    * The method adds the current payload row to the json object m_payload. The
    * row is associated with the channel_id.
    */
-  void addData(const char *channel_id);
+  void addData(const char* channel_id);
   /**
    * @brief It associate the payload row to a channel_id.
    * @param channel_id The channel_id to associate the payload row.
@@ -176,7 +157,7 @@ class CrestContainer {
    * associated with the channel_id. The data is the data to be associated with
    * the channel_id, and they belong to a previously filled payload row.
    */
-  void addExternalData(const char *channel_id, const nlohmann::json &data);
+  void addExternalData(const char* channel_id, const nlohmann::json& data);
   /**
    * @brief It adds an IOV to the json object m_iov_data.
    * @param since The since value of the IOV.
@@ -186,15 +167,15 @@ class CrestContainer {
    */
   void addIov(const uint64_t since);
 
-  const std::vector<std::pair<std::string, TypeId>> &getMPayloadSpec();
+  const std::vector<std::pair<std::string, TypeId>>& getMPayloadSpec();
 
   template <typename T>
-  T getRecord(const std::string &name) {
-    for (const auto &column : m_payload_spec) {
+  T getRecord(const std::string& name) {
+    for (const auto& column : m_payload_spec) {
       if (column.first == name) {
         try {
           return m_row.at(name).get<T>();
-        } catch (nlohmann::json::exception &e) {
+        } catch (nlohmann::json::exception& e) {
           throw std::runtime_error("JSON exception for key: " + name);
         }
       }
@@ -202,33 +183,33 @@ class CrestContainer {
     throw std::runtime_error("Column name not found or type mismatch.");
   }
 
-  const nlohmann::json &getPayload();
-  const nlohmann::json &getIovData();
+  const nlohmann::json& getPayload();
+  const nlohmann::json& getIovData();
 
-  const nlohmann::json &getPayloadChannel(const char *channel_id);
+  const nlohmann::json getPayloadChannel(const char* channel_id);
 
-  void setIovData(const nlohmann::json &j);
-  void setPayload(const nlohmann::json &j);
+  void setIovData(const nlohmann::json& j);
+  void setPayload(const nlohmann::json& j);
   // return the payload spec as a copy
   nlohmann::json getPayloadSpec();
-  void setPayloadSpec(const nlohmann::json &j);
+  void setPayloadSpec(const nlohmann::json& j);
 
   /**
    * @brief It encodes the input string to base64.
    */
-  static std::string base64Encode(const uint8_t *bytes_to_encode,
-                                  unsigned int in_len);
+  static std::string base64_encode(const uint8_t* bytes_to_encode,
+                                   unsigned int in_len);
   /**
    * @brief It decodes the input string from base64.
    */
-  static std::vector<unsigned char> base64Decode(
-      const std::string &encodedData);
+  static std::vector<unsigned char> base64_decode(
+      const std::string& encodedData);
   /**
    * @brief It returns the index of the column with the given name.
    * @param name The name of the column.
    * It checks the payload spec array to get the index back.
    */
-  int getColumnIndex(const std::string &name);
+  int getColumnIndex(const std::string& name);
   /**
    * @brief It reinitializes the containers.
    */
@@ -244,26 +225,31 @@ class CrestContainer {
    * @brief It returns the json representation of the container.
    */
   std::string getJsonIovData();
-  /**
-   * @brief It returns the StoreSetDto json representation of the container.
-   */
-  nlohmann::json getStoreSetDto();
   /**
    * @brief It creates a file with the json representation of the container.
    */
-  void dumpJsonToFile(const nlohmann::json &j, const std::string &filename);
+  void dumpJsonToFile(const nlohmann::json& j, const std::string& filename);
   /**
    * @brief It reads a json file and returns the json object.
    */
-  nlohmann::json readJsonFromFile(const std::string &filename,
-                                  const std::string &spec_filename);
+  nlohmann::json readJsonFromFile(const std::string& filename,
+                                  const std::string& spec_filename);
   /**
    * @brief It reads a json object to fill the containers.
    */
-  void fromJson(const uint64_t since, const nlohmann::json &j);
+  std::vector<uint64_t> fromJson(uint64_t since, const nlohmann::json& j);
+
+  void parseOldFormat(std::string& colName, TypeId& typespec,
+                      const nlohmann::json& j);
+
+  nlohmann::json getStoreSetDto(uint64_t period = -1);
+
+  uint64_t getFirstTime();
 
-  void parseOldFormat(std::string &colName, TypeId &typespec,
-                      const nlohmann::json &j);
+  void parseData(const nlohmann::json& values);
+  std::vector<uint64_t> readDcsFullType(const nlohmann::json& j_in);
+  void readCommonType(uint64_t since, const nlohmann::json& j_in);
+  static bool compareStrTimestamp(std::string as, std::string bs);
 };
 }  // namespace Crest
 #endif
diff --git a/tools/cmake/CrestContainerConfig.cmake.in b/tools/cmake/CrestContainerConfig.cmake.in
new file mode 100644
index 0000000000000000000000000000000000000000..c1153fe281511111b1ca81980d23db981edbd1ab
--- /dev/null
+++ b/tools/cmake/CrestContainerConfig.cmake.in
@@ -0,0 +1,33 @@
+# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
+
+# Avoid hard-coding absolute paths
+# This calculates ${PACKAGE_PREFIX_DIR} at run-time based on the
+# relative locations of the CMAKE_INSTALL_PREFIX and this config file
+# after installation
+@PACKAGE_INIT@
+
+# Set up useful variables.
+set_and_check(CrestContainer_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
+set_and_check(CrestContainer_LIBRARY_DIR "@PACKAGE_CMAKE_INSTALL_LIBDIR@")
+
+# Set the include directories that dependent projects will need
+set(CrestContainerLib_INCLUDE_DIRS "${CrestContainer_INCLUDE_DIR}")
+set(CrestContainer_INCLUDE_DIRS "${CrestContainer_INCLUDE_DIR}")  # For backward compatibility
+
+# Find dependencies
+include(CMakeFindDependencyMacro)
+find_dependency(CURL)
+find_dependency(OpenSSL)
+find_dependency(nlohmann_json 3.2.0)
+find_dependency(Boost)
+find_dependency(CrestApi)
+
+# Use the cmake generated target
+include("${CMAKE_CURRENT_LIST_DIR}/CrestContainerTargets.cmake")
+set(CrestContainer_LIBRARIES CrestApi::CrestContainerLib)
+
+# Print a standard information message about the package being found.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CrestContainer
+   REQUIRED_VARS CMAKE_CURRENT_LIST_FILE CrestContainer_INCLUDE_DIR
+   VERSION_VAR CrestContainer_VERSION )