diff --git a/bin/nodejs/callback.h b/bin/nodejs/callback.h
index e0b05847879692a4f9170a5dd7e9edc551b37c51..9b4788f5014fb2be58819a73bc78909d66d34966 100644
--- a/bin/nodejs/callback.h
+++ b/bin/nodejs/callback.h
@@ -30,6 +30,7 @@ Persistent<Function> mediaChangeRequestedCb;
 Persistent<Function> incomingMessageCb;
 Persistent<Function> incomingCallCb;
 Persistent<Function> incomingCallWithMediaCb;
+Persistent<Function> dataTransferEventCb;
 Persistent<Function> conversationLoadedCb;
 Persistent<Function> swarmLoadedCb;
 Persistent<Function> messagesFoundCb;
@@ -102,6 +103,8 @@ getPresistentCb(std::string_view signal)
         return &incomingCallCb;
     else if (signal == "IncomingCallWithMedia")
         return &incomingCallWithMediaCb;
+    else if (signal == "DataTransferEvent")
+        return &dataTransferEventCb;
     else if (signal == "ConversationLoaded")
         return &conversationLoadedCb;
     else if (signal == "SwarmLoaded")
@@ -667,6 +670,30 @@ incomingCallWithMedia(const std::string& accountId,
     uv_async_send(&signalAsync);
 }
 
+/** Data Transfer */
+
+void
+dataTransferEvent(const std::string& accountId,
+                  const std::string& conversationId,
+                  const std::string& interactionId,
+                  const std::string& fileId,
+                  int eventCode)
+{
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([accountId, conversationId, interactionId, fileId, eventCode]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), dataTransferEventCb);
+        if (!func.IsEmpty()) {
+            SWIGV8_VALUE callback_args[] = {V8_STRING_NEW_LOCAL(accountId),
+                                            V8_STRING_NEW_LOCAL(conversationId),
+                                            V8_STRING_NEW_LOCAL(interactionId),
+                                            V8_STRING_NEW_LOCAL(fileId),
+                                            SWIGV8_INTEGER_NEW(eventCode)};
+            func->Call(SWIGV8_CURRENT_CONTEXT(), SWIGV8_NULL(), 5, callback_args);
+        }
+    });
+    uv_async_send(&signalAsync);
+}
+
 /** Conversations */
 
 void
diff --git a/bin/nodejs/datatransfer.i b/bin/nodejs/datatransfer.i
new file mode 100644
index 0000000000000000000000000000000000000000..9baa45c8bdbc689e6fef9093b146901514fd3216
--- /dev/null
+++ b/bin/nodejs/datatransfer.i
@@ -0,0 +1,89 @@
+/*
+ *  Copyright (C) 2004-2022 Savoir-faire Linux Inc.
+ *
+ *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *  Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *  Author: Pierre Duchemin <pierre.duchemin@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+%apply uint32_t { libjami::DataTransferEventCode };
+%apply uint32_t { libjami::DataTransferError };
+%apply uint64_t { libjami::DataTransferId };
+%apply uint64_t { const libjami::DataTransferId };
+%apply int64_t& INOUT { libjami::DataTransferId& id };
+
+%header %{
+#include "jami/jami.h"
+#include "jami/datatransfer_interface.h"
+
+class DataTransferCallback {
+public:
+    virtual ~DataTransferCallback(){}
+    virtual void dataTransferEvent(const std::string& accountId, const std::string& conversationId, const std::string& interactionId, const std::string& fileId, int eventCode){}
+};
+%}
+
+%feature("director") DataTransferCallback;
+
+%typemap(in) std::string& OUTPUT (std::string temp) {
+  if (!$input.IsEmpty()) {
+    SWIGV8_THROW_EXCEPTION(SWIGV8_STRING_NEW("array null"));
+    return;
+  }
+  if (SWIGV8_ARRAY::Cast($input)->Length()) {
+    SWIGV8_THROW_EXCEPTION(SWIGV8_STRING_NEW("Array must contain at least 1 element"));
+  }
+  $1 = &temp;
+}
+%typemap(argout) std::string& OUTPUT {
+  auto value = SWIGV8_STRING_NEW(temp$argnum.c_str());
+  SWIGV8_ARRAY_SET(SWIGV8_ARRAY::Cast($input), 0, value);
+}
+%apply std::string& OUTPUT { std::string& path_out }
+%apply int64_t& OUTPUT { int64_t& total_out }
+%apply int64_t& OUTPUT { int64_t& progress_out }
+
+
+namespace libjami {
+
+  struct DataTransferInfo
+  {
+    std::string accountId;
+    libjami::DataTransferEventCode lastEvent;
+    uint32_t flags;
+    int64_t totalSize;
+    int64_t bytesProgress;
+    std::string author;
+    std::string peer;
+    std::string conversationId;
+    std::string displayName;
+    std::string path;
+    std::string mimetype;
+  };
+
+  // Files Management 
+  void sendFile(const std::string& accountId, const std::string& conversationId, const std::string& path, const std::string& displayName, const std::string& replyTo);
+  uint64_t downloadFile(const std::string& accountId, const std::string& conversationId, const std::string& interactionId,const std::string& fileId, const std::string& path);
+  libjami::DataTransferError cancelDataTransfer(const std::string& accountId, const std::string& conversationId, const std::string& fileId);
+  libjami::DataTransferError fileTransferInfo(const std::string& accountId, const std::string& conversationId, const std::string& fileId, std::string &path_out, int64_t &total_out, int64_t &progress_out);
+}
+
+
+class DataTransferCallback {
+public:
+    virtual ~DataTransferCallback(){}
+    virtual void dataTransferEvent(const std::string& accountId, const std::string& conversationId, const std::string& interactionId, const std::string& fileId, int eventCode){}
+};
diff --git a/bin/nodejs/nodejs_interface.i b/bin/nodejs/nodejs_interface.i
index d4ba33bf877fa1cb13f7b42d263d36457475ae79..6f3ddb62ddc41e739151482df3ad8057fd2aa089 100644
--- a/bin/nodejs/nodejs_interface.i
+++ b/bin/nodejs/nodejs_interface.i
@@ -78,6 +78,7 @@ namespace std {
 %include "callmanager.i"
 %include "videomanager.i"
 %include "conversation.i"
+%include "datatransfer.i"
 
 %header %{
 #include "callback.h"
@@ -148,6 +149,10 @@ void init(const SWIGV8_VALUE& funcMap){
         //exportable_callback<ConfigurationSignal::IncomingTrustRequest>(bind(&incomingTrustRequest, _1, _2, _3, _4, _5 )),
     };
 
+    const std::map<std::string, SharedCallback> dataTransferEvHandlers = {
+        exportable_callback<libjami::DataTransferSignal::DataTransferEvent>(bind(&dataTransferEvent, _1, _2, _3, _4, _5)),
+    };
+
     const std::map<std::string, SharedCallback> conversationHandlers = {
         exportable_callback<ConversationSignal::ConversationLoaded>(bind(&conversationLoaded, _1, _2, _3, _4)),
         exportable_callback<ConversationSignal::SwarmLoaded>(bind(&swarmLoaded, _1, _2, _3, _4)),
@@ -173,7 +178,7 @@ void init(const SWIGV8_VALUE& funcMap){
     registerSignalHandlers(configEvHandlers);
     registerSignalHandlers(callEvHandlers);
     registerSignalHandlers(conversationHandlers);
-
+    registerSignalHandlers(dataTransferEvHandlers);
     libjami::start();
 }
 %}