diff --git a/libs/client/CMakeLists.txt b/libs/client/CMakeLists.txt
index 0af157fac054e0a4b82e4ba02cae00aba412ca3f..6912da86d8ce816d80084b8cddf0281cde13c678 100644
--- a/libs/client/CMakeLists.txt
+++ b/libs/client/CMakeLists.txt
@@ -10,6 +10,7 @@ set (CLIENT_LIB_SRC_FILES
   FileSystemNode.cpp
   FileSystemStorageClass.cpp
   FileSystemStorageClasses.cpp
+  MigrationRoute.cpp
   MockClientAPI.cpp
   SecurityIdentity.cpp
   StorageClass.cpp
diff --git a/libs/client/ClientAPI.hpp b/libs/client/ClientAPI.hpp
index b11f2a4c78f50e9e0d8c88d40b1e94c1a91c4e2a..ee7b2cdc68dbd2700f6e1ca568a3001c5d1e1f22 100644
--- a/libs/client/ClientAPI.hpp
+++ b/libs/client/ClientAPI.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "DirectoryIterator.hpp"
+#include "MigrationRoute.hpp"
 #include "SecurityIdentity.hpp"
 #include "StorageClass.hpp"
 #include "TapePool.hpp"
@@ -153,6 +154,46 @@ public:
   virtual std::list<TapePool> getTapePools(
     const SecurityIdentity &requester) const = 0;
 
+  /**
+   * Creates the specified migration route.
+   *
+   * @param requester The identity of the user requesting the creation of the
+   * migration route.
+   * @param storageClassName The name of the storage class that identifies the
+   * source disk files.
+   * @param copyNb The tape copy number.
+   * @param tapePoolName The name of the destination tape pool.
+   * @param comment The comment describing the migration roue.
+   */
+  virtual void createMigrationRoute(
+    const SecurityIdentity &requester,
+    const std::string &storageClassName,
+    const uint8_t copyNb,
+    const std::string &tapePoolName,
+    const std::string &comment) = 0;
+
+  /**
+   * Deletes the specified migration route.
+   *
+   * @param requester The identity of the user requesting the deletion of the
+   * migration route.
+   * @param storageClassName The name of the storage class that identifies the
+   * source disk files.
+   * @param copyNb The tape copy number.
+   */
+  virtual void deleteMigrationRoute(
+    const SecurityIdentity &requester,
+    const std::string &storageClassName,
+    const uint8_t copyNb) = 0;
+
+  /**
+   * Gets the current list of migration routes.
+   *
+   * @param requester The identity of the user requesting the list.
+   */
+  virtual std::list<MigrationRoute> getMigrationRoutes(
+    const SecurityIdentity &requester) const = 0;
+
   /**
    * Creates the specified directory.
    *
diff --git a/libs/client/DirectoryEntry.hpp b/libs/client/DirectoryEntry.hpp
index 5c0707e0e98c36c6270ac111d446698f6dda7103..b45463e42a8f92268c2c3174f52fbf257057f027 100644
--- a/libs/client/DirectoryEntry.hpp
+++ b/libs/client/DirectoryEntry.hpp
@@ -68,14 +68,14 @@ public:
   uint32_t getOwnerId() const throw();
 
   /**
-   * Returns The group ID of the directory entry.
+   * Returns the group ID of the directory entry.
    *
    * @return The group ID of the directory entry.
    */
   uint32_t getGroupId() const throw();
 
   /**
-   * Returns The mode bits of the directory entry.
+   * Returns the mode bits of the directory entry.
    *
    * @return The mode bits of the directory entry.
    */
@@ -130,6 +130,6 @@ private:
    */
   std::string m_storageClassName;
 
-}; // DirectoryEntry
+}; // class DirectoryEntry
 
 } // namespace cta
diff --git a/libs/client/MigrationRoute.cpp b/libs/client/MigrationRoute.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6706cac94f3842a79a6d3c15a2604dbe850ff2b8
--- /dev/null
+++ b/libs/client/MigrationRoute.cpp
@@ -0,0 +1,61 @@
+#include "MigrationRoute.hpp"
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::MigrationRoute::MigrationRoute():
+  m_copyNb(0),
+  m_creationTime(time(NULL)) {
+}
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::MigrationRoute::MigrationRoute(
+  const std::string &storageClassName,
+  const uint8_t copyNb,
+  const std::string &tapePoolName,
+  const UserIdentity &creator,
+  const std::string &comment):
+  m_storageClassName(storageClassName),
+  m_copyNb(copyNb),
+  m_tapePoolName(tapePoolName),
+  m_creationTime(time(NULL)),
+  m_creator(creator),
+  m_comment(comment) {
+}
+
+//------------------------------------------------------------------------------
+// getStorageClassName
+//------------------------------------------------------------------------------
+const std::string &cta::MigrationRoute::getStorageClassName() const throw() {
+  return m_storageClassName;
+}
+
+//------------------------------------------------------------------------------
+// getCopyNb
+//------------------------------------------------------------------------------
+uint8_t cta::MigrationRoute::getCopyNb() const throw() {
+  return m_copyNb;
+}
+
+//------------------------------------------------------------------------------
+// getTapePoolName
+//------------------------------------------------------------------------------
+const std::string &cta::MigrationRoute::getTapePoolName() const throw() {
+  return m_tapePoolName;
+}
+
+//------------------------------------------------------------------------------
+// getCreator
+//------------------------------------------------------------------------------
+const cta::UserIdentity &cta::MigrationRoute::getCreator() const throw() {
+  return m_creator;
+}
+
+//------------------------------------------------------------------------------
+// getComment
+//------------------------------------------------------------------------------
+const std::string &cta::MigrationRoute::getComment() const throw() {
+  return m_comment;
+}
diff --git a/libs/client/MigrationRoute.hpp b/libs/client/MigrationRoute.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d54569c691a2126d54461e9157cf85c8aee40fc9
--- /dev/null
+++ b/libs/client/MigrationRoute.hpp
@@ -0,0 +1,110 @@
+#pragma once
+
+#include "UserIdentity.hpp"
+
+#include <stdint.h>
+#include <string>
+#include <time.h>
+
+namespace cta {
+
+/**
+ * A migration route.
+ */
+class MigrationRoute {
+public:
+
+  /**
+   * Constructor.
+   */
+  MigrationRoute();
+
+  /**
+   * Constructor.
+   *
+   * @param storageClassName The name of the storage class that identifies the
+   * source disk files.
+   * @param copyNb The tape copy number.
+   * @param tapePoolName The name of the destination tape pool.
+   * @param creator The identity of the user that created the storage class.
+   * @param comment Comment describing the storage class.
+   */
+  MigrationRoute(
+    const std::string &storageClassName,
+    const uint8_t copyNb,
+    const std::string &tapePoolName,
+    const UserIdentity &creator,
+    const std::string &comment);
+
+  /**
+   * Returns the name of the storage class that identifies the source disk
+   * files.
+   *
+   * @return The name of the storage class that identifies the source disk
+   * files.
+   */
+  const std::string &getStorageClassName() const throw();
+
+  /**
+   * Returns the tape copy number.
+   *
+   * @return The tape copy number.
+   */
+  uint8_t getCopyNb() const throw();
+
+  /**
+   * Returns the name of the destination tape pool.
+   *
+   * @return The name of the destination tape pool.
+   */
+  const std::string &getTapePoolName() const throw();
+
+  /**
+   * Returns the identity of the user that created the storage class.
+   *
+   * @return The identity of the user that created the storage class.
+   */
+  const UserIdentity &getCreator() const throw();
+
+  /**
+   * Returns the comment describing the storage class.
+   *
+   * @return The comment describing the storage class.
+   */
+  const std::string &getComment() const throw();
+
+private:
+
+  /**
+   * The name of the storage class that identifies the source disk files.
+   */
+  std::string m_storageClassName;
+
+  /**
+   * The tape copy number.
+   */
+  uint32_t m_copyNb;
+
+  /**
+   * The name of the destination tape pool.
+   */
+  std::string m_tapePoolName;
+
+  /**
+   * The time when the storage class was created.
+   */
+  time_t m_creationTime;
+
+  /**
+   * The identity of the user that created the storage class.
+   */
+  UserIdentity m_creator;
+
+  /**
+   * Comment describing the storage class.
+   */
+  std::string m_comment;
+
+}; // class MigrationRoute
+
+} // namespace cta
diff --git a/libs/client/MockClientAPI.cpp b/libs/client/MockClientAPI.cpp
index 339ce10dda16cfdb7f360938b8d7c0a933f02986..2de846ad65595fe909b50e5e1b2c605281e63bf7 100644
--- a/libs/client/MockClientAPI.cpp
+++ b/libs/client/MockClientAPI.cpp
@@ -202,6 +202,35 @@ std::list<cta::TapePool> cta::MockClientAPI::getTapePools(
   return tapePools;
 }
 
+//------------------------------------------------------------------------------
+// createMigrationRoute
+//------------------------------------------------------------------------------
+void cta::MockClientAPI::createMigrationRoute(
+  const SecurityIdentity &requester,
+  const std::string &storageClassName,
+  const uint8_t copyNb,
+  const std::string &tapePoolName,
+  const std::string &comment) {
+}
+
+//------------------------------------------------------------------------------
+// deleteMigrationRoute
+//------------------------------------------------------------------------------
+void cta::MockClientAPI::deleteMigrationRoute(
+  const SecurityIdentity &requester,
+  const std::string &storageClassName,
+  const uint8_t copyNb) {
+}
+
+//------------------------------------------------------------------------------
+// getMigrationRoutes
+//------------------------------------------------------------------------------
+std::list<cta::MigrationRoute> cta::MockClientAPI::getMigrationRoutes(
+  const SecurityIdentity &requester) const {
+  std::list<MigrationRoute> migrationRoutes;
+  return migrationRoutes;
+}
+
 //------------------------------------------------------------------------------
 // createDirectory
 //------------------------------------------------------------------------------
diff --git a/libs/client/MockClientAPI.hpp b/libs/client/MockClientAPI.hpp
index 0ac86088a0414fdfdd6b6f830f5d40cb85bfff31..61727b61a7ccdc5fba55c01b3cc6e654d8755238 100644
--- a/libs/client/MockClientAPI.hpp
+++ b/libs/client/MockClientAPI.hpp
@@ -155,6 +155,46 @@ public:
   std::list<TapePool> getTapePools(
     const SecurityIdentity &requester) const;
 
+  /**
+   * Creates the specified migration route.
+   *
+   * @param requester The identity of the user requesting the creation of the
+   * migration route.
+   * @param storageClassName The name of the storage class that identifies the
+   * source disk files.
+   * @param copyNb The tape copy number.
+   * @param tapePoolName The name of the destination tape pool.
+   * @param comment The comment describing the migration roue.
+   */
+  void createMigrationRoute(
+    const SecurityIdentity &requester,
+    const std::string &storageClassName,
+    const uint8_t copyNb,
+    const std::string &tapePoolName,
+    const std::string &comment);
+
+  /**
+   * Deletes the specified migration route.
+   *
+   * @param requester The identity of the user requesting the deletion of the
+   * migration route.
+   * @param storageClassName The name of the storage class that identifies the
+   * source disk files.
+   * @param copyNb The tape copy number.
+   */
+  void deleteMigrationRoute(
+    const SecurityIdentity &requester,
+    const std::string &storageClassName,
+    const uint8_t copyNb);
+
+  /**
+   * Gets the current list of migration routes.
+   *
+   * @param requester The identity of the user requesting the list.
+   */
+  std::list<MigrationRoute> getMigrationRoutes(
+    const SecurityIdentity &requester) const;
+
   /**
    * Creates the specified directory.
    *
diff --git a/libs/client/MockClientAPITest.cpp b/libs/client/MockClientAPITest.cpp
index df7c20d9b5127792459766c49c179e4d609159e5..41ed704a07cee25db0190890df1712d6c4a806ea 100644
--- a/libs/client/MockClientAPITest.cpp
+++ b/libs/client/MockClientAPITest.cpp
@@ -599,6 +599,165 @@ TEST_F(cta_client_MockClientAPITest, deleteTapePool_non_existing) {
   }
 }
 
+TEST_F(cta_client_MockClientAPITest, createMigrationRoute_new) {
+  using namespace cta;
+
+  TestingMockClientAPI api;
+  const SecurityIdentity requester;
+
+  {
+    std::list<MigrationRoute> migrationRoutes;
+    ASSERT_NO_THROW(migrationRoutes = api.getMigrationRoutes(requester));
+    ASSERT_TRUE(migrationRoutes.empty());
+  }
+
+  const std::string storageClassName = "TestStorageClass";
+  const std::string comment = "Comment";
+  {
+    const uint8_t nbCopies = 2;
+    ASSERT_NO_THROW(api.createStorageClass(requester, storageClassName,
+      nbCopies, comment));
+  }
+
+  const std::string tapePoolName = "TestTapePool";
+  ASSERT_NO_THROW(api.createTapePool(requester, tapePoolName, comment));
+
+  const uint8_t copyNb = 1;
+  ASSERT_NO_THROW(api.createMigrationRoute(requester, storageClassName,
+    copyNb, tapePoolName, comment));
+
+  {
+    std::list<MigrationRoute> migrationRoutes;
+    ASSERT_NO_THROW(migrationRoutes = api.getMigrationRoutes(requester));
+    ASSERT_EQ(1, migrationRoutes.size());
+
+    MigrationRoute migrationRoute;
+    ASSERT_NO_THROW(migrationRoute = migrationRoutes.front());
+    ASSERT_EQ(storageClassName, migrationRoute.getStorageClassName());
+    ASSERT_EQ(copyNb, migrationRoute.getCopyNb());
+    ASSERT_EQ(tapePoolName, migrationRoute.getTapePoolName());
+  }
+}
+
+TEST_F(cta_client_MockClientAPITest, createMigrationRoute_already_existing) {
+  using namespace cta;
+
+  TestingMockClientAPI api;
+  const SecurityIdentity requester;
+
+  {
+    std::list<MigrationRoute> migrationRoutes;
+    ASSERT_NO_THROW(migrationRoutes = api.getMigrationRoutes(requester));
+    ASSERT_TRUE(migrationRoutes.empty());
+  }
+
+  const std::string storageClassName = "TestStorageClass";
+  const std::string comment = "Comment";
+  {
+    const uint8_t nbCopies = 2;
+    ASSERT_NO_THROW(api.createStorageClass(requester, storageClassName,
+      nbCopies, comment));
+  }
+
+  const std::string tapePoolName = "TestTapePool";
+  ASSERT_NO_THROW(api.createTapePool(requester, tapePoolName, comment));
+
+  const uint8_t copyNb = 1;
+  ASSERT_NO_THROW(api.createMigrationRoute(requester, storageClassName,
+    copyNb, tapePoolName, comment));
+
+  {
+    std::list<MigrationRoute> migrationRoutes;
+    ASSERT_NO_THROW(migrationRoutes = api.getMigrationRoutes(requester));
+    ASSERT_EQ(1, migrationRoutes.size());
+
+    MigrationRoute migrationRoute;
+    ASSERT_NO_THROW(migrationRoute = migrationRoutes.front());
+    ASSERT_EQ(storageClassName, migrationRoute.getStorageClassName());
+    ASSERT_EQ(copyNb, migrationRoute.getCopyNb());
+    ASSERT_EQ(tapePoolName, migrationRoute.getTapePoolName());
+  }
+
+  ASSERT_THROW(api.createMigrationRoute(requester, storageClassName,
+    copyNb, tapePoolName, comment), std::exception);
+}
+
+TEST_F(cta_client_MockClientAPITest, deleteMigrationRoute_existing) {
+  using namespace cta;
+
+  TestingMockClientAPI api;
+  const SecurityIdentity requester;
+
+  {
+    std::list<MigrationRoute> migrationRoutes;
+    ASSERT_NO_THROW(migrationRoutes = api.getMigrationRoutes(requester));
+    ASSERT_TRUE(migrationRoutes.empty());
+  }
+
+  const std::string storageClassName = "TestStorageClass";
+  const std::string comment = "Comment";
+  {
+    const uint8_t nbCopies = 2;
+    ASSERT_NO_THROW(api.createStorageClass(requester, storageClassName,
+      nbCopies, comment));
+  }
+
+  const std::string tapePoolName = "TestTapePool";
+  ASSERT_NO_THROW(api.createTapePool(requester, tapePoolName, comment));
+
+  const uint8_t copyNb = 1;
+  ASSERT_NO_THROW(api.createMigrationRoute(requester, storageClassName,
+    copyNb, tapePoolName, comment));
+
+  {
+    std::list<MigrationRoute> migrationRoutes;
+    ASSERT_NO_THROW(migrationRoutes = api.getMigrationRoutes(requester));
+    ASSERT_EQ(1, migrationRoutes.size());
+
+    MigrationRoute migrationRoute;
+    ASSERT_NO_THROW(migrationRoute = migrationRoutes.front());
+    ASSERT_EQ(storageClassName, migrationRoute.getStorageClassName());
+    ASSERT_EQ(copyNb, migrationRoute.getCopyNb());
+    ASSERT_EQ(tapePoolName, migrationRoute.getTapePoolName());
+  }
+
+  ASSERT_NO_THROW(api.deleteMigrationRoute(requester, storageClassName,
+    copyNb));
+
+  {
+    std::list<MigrationRoute> migrationRoutes;
+    ASSERT_NO_THROW(migrationRoutes = api.getMigrationRoutes(requester));
+    ASSERT_TRUE(migrationRoutes.empty());
+  } 
+}
+
+TEST_F(cta_client_MockClientAPITest, deleteMigrationRoute_non_existing) {
+  using namespace cta;
+
+  TestingMockClientAPI api;
+  const SecurityIdentity requester;
+
+  {
+    std::list<MigrationRoute> migrationRoutes;
+    ASSERT_NO_THROW(migrationRoutes = api.getMigrationRoutes(requester));
+    ASSERT_TRUE(migrationRoutes.empty());
+  }
+
+  const std::string storageClassName = "TestStorageClass";
+  const std::string comment = "Comment";
+  {
+    const uint8_t nbCopies = 2;
+    ASSERT_NO_THROW(api.createStorageClass(requester, storageClassName,
+      nbCopies, comment));
+  }
+
+  const std::string tapePoolName = "TestTapePool";
+  ASSERT_NO_THROW(api.createTapePool(requester, tapePoolName, comment));
+
+  const uint8_t copyNb = 1;
+  ASSERT_NO_THROW(api.deleteMigrationRoute(requester, tapePoolName, copyNb));
+}
+
 TEST_F(cta_client_MockClientAPITest, getDirectoryContents_root_dir_is_empty) {
   using namespace cta;