diff --git a/bin/nodejs/callback.h b/bin/nodejs/callback.h
index 0d5cdebd5c3d1eb6851b62c0fa104f3f0360a561..29636fd95328dc51189b224c50e5cef21c3e0dc6 100644
--- a/bin/nodejs/callback.h
+++ b/bin/nodejs/callback.h
@@ -56,6 +56,11 @@ Persistent<Function> accountProfileReceivedCb;
 Persistent<Function> profileReceivedCb;
 Persistent<Function> userSearchEndedCb;
 Persistent<Function> deviceRevocationEndedCb;
+Persistent<Function> subscriptionStateChangedCb;
+Persistent<Function> nearbyPeerNotificationCb;
+Persistent<Function> newBuddyNotificationCb;
+Persistent<Function> serverErrorCb;
+Persistent<Function> newServerSubscriptionRequestCb;
 
 std::queue<std::function<void()>> pendingSignals;
 std::mutex pendingSignalsLock;
@@ -159,6 +164,16 @@ getPresistentCb(std::string_view signal)
         return &userSearchEndedCb;
     else if (signal == "DeviceRevocationEnded")
         return &deviceRevocationEndedCb;
+    else if (signal == "SubscriptionStateChanged")
+        return &subscriptionStateChangedCb;
+    else if (signal == "NearbyPeerNotification")
+        return &nearbyPeerNotificationCb;
+    else if (signal == "NewBuddyNotification")
+        return &newBuddyNotificationCb;
+    else if (signal == "ServerError")
+        return &serverErrorCb;
+    else if (signal == "NewServerSubscriptionRequest")
+        return &newServerSubscriptionRequestCb;
     else
         return nullptr;
 }
@@ -1163,3 +1178,78 @@ profileReceived(const std::string& accountId,
     uv_async_send(&signalAsync);
 }
 
+void
+subscriptionStateChanged(const std::string& accountId, const std::string& buddy_uri, int state)
+{
+    std::lock_guard lock(pendingSignalsLock);
+    pendingSignals.emplace([accountId, buddy_uri, state]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), subscriptionStateChangedCb);
+        if (!func.IsEmpty()) {
+            SWIGV8_VALUE callback_args[] = {V8_STRING_NEW_LOCAL(accountId),
+                                            V8_STRING_NEW_LOCAL(buddy_uri),
+                                            SWIGV8_INTEGER_NEW(state)};
+            func->Call(SWIGV8_CURRENT_CONTEXT(), SWIGV8_NULL(), 3, callback_args);
+        }
+    });
+    uv_async_send(&signalAsync);
+}
+
+void
+nearbyPeerNotification(const std::string& accountId, const std::string& buddy_uri, int state, const std::string& displayName){
+    std::lock_guard lock(pendingSignalsLock);
+    pendingSignals.emplace([accountId, buddy_uri, state, displayName]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), nearbyPeerNotificationCb);
+        if (!func.IsEmpty()) {
+            SWIGV8_VALUE callback_args[] = {V8_STRING_NEW_LOCAL(accountId),
+                                            V8_STRING_NEW_LOCAL(buddy_uri),
+                                            SWIGV8_INTEGER_NEW(state),
+                                            V8_STRING_NEW_LOCAL(displayName)};
+            func->Call(SWIGV8_CURRENT_CONTEXT(), SWIGV8_NULL(), 4, callback_args);
+        }
+    });
+    uv_async_send(&signalAsync);
+}
+
+void
+newBuddyNotification(const std::string& accountId, const std::string& buddy_uri, int status, const std::string& line_status){
+    std::lock_guard lock(pendingSignalsLock);
+    pendingSignals.emplace([accountId, buddy_uri, status, line_status]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), newBuddyNotificationCb);
+        if (!func.IsEmpty()) {
+            SWIGV8_VALUE callback_args[] = {V8_STRING_NEW_LOCAL(accountId),
+                                            V8_STRING_NEW_LOCAL(buddy_uri),
+                                            SWIGV8_INTEGER_NEW(status),
+                                            V8_STRING_NEW_LOCAL(line_status)};
+            func->Call(SWIGV8_CURRENT_CONTEXT(), SWIGV8_NULL(), 4, callback_args);
+        }
+    });
+    uv_async_send(&signalAsync);
+}
+
+void
+newServerSubscriptionRequest(const std::string& remote){
+    std::lock_guard lock(pendingSignalsLock);
+    pendingSignals.emplace([remote]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), newServerSubscriptionRequestCb);
+        if (!func.IsEmpty()) {
+            SWIGV8_VALUE callback_args[] = {V8_STRING_NEW_LOCAL(remote)};
+            func->Call(SWIGV8_CURRENT_CONTEXT(), SWIGV8_NULL(), 1, callback_args);
+        }
+    });
+    uv_async_send(&signalAsync);
+}
+
+void
+serverError(const std::string& accountId, const std::string& error, const std::string& msg){
+    std::lock_guard lock(pendingSignalsLock);
+    pendingSignals.emplace([accountId, error, msg]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), serverErrorCb);
+        if (!func.IsEmpty()) {
+            SWIGV8_VALUE callback_args[] = {V8_STRING_NEW_LOCAL(accountId),
+                                            V8_STRING_NEW_LOCAL(error),
+                                            V8_STRING_NEW_LOCAL(msg)};
+            func->Call(SWIGV8_CURRENT_CONTEXT(), SWIGV8_NULL(), 3, callback_args);
+        }
+    });
+    uv_async_send(&signalAsync);
+}
\ No newline at end of file
diff --git a/bin/nodejs/nodejs_interface.i b/bin/nodejs/nodejs_interface.i
index 04c605071d5841eec65006aeff91ed5b1ef88c6b..e188c262cee58a1a0b37619d6d87633ce8ee7fc9 100644
--- a/bin/nodejs/nodejs_interface.i
+++ b/bin/nodejs/nodejs_interface.i
@@ -115,6 +115,7 @@ void init(const SWIGV8_VALUE& funcMap){
     using libjami::ConfigurationSignal;
     using libjami::CallSignal;
     using libjami::ConversationSignal;
+    using libjami::PresenceSignal;
     using SharedCallback = std::shared_ptr<libjami::CallbackWrapperBase>;
     const std::map<std::string, SharedCallback> callEvHandlers = {
         exportable_callback<CallSignal::StateChange>(bind(&callStateChanged, _1, _2, _3, _4)),
@@ -171,6 +172,16 @@ void init(const SWIGV8_VALUE& funcMap){
         exportable_callback<ConversationSignal::ConversationPreferencesUpdated>(bind(&conversationPreferencesUpdated, _1, _2, _3))
     };
 
+    // Presence event handlers
+    const std::map<std::string, SharedCallback> presenceEvHandlers = {
+        exportable_callback<PresenceSignal::NewServerSubscriptionRequest>(bind(&newServerSubscriptionRequest, _1 )),
+        exportable_callback<PresenceSignal::ServerError>(bind(&serverError, _1, _2, _3 )),
+        exportable_callback<PresenceSignal::NewBuddyNotification>(bind(&newBuddyNotification, _1, _2, _3, _4 )),
+        exportable_callback<PresenceSignal::NearbyPeerNotification>(bind(&nearbyPeerNotification, _1, _2, _3, _4)),
+        exportable_callback<PresenceSignal::SubscriptionStateChanged>(bind(&subscriptionStateChanged, _1, _2, _3 ))
+    };
+    
+
     if (!libjami::init(static_cast<libjami::InitFlag>(libjami::LIBJAMI_FLAG_DEBUG)))
         return;
 
@@ -178,6 +189,7 @@ void init(const SWIGV8_VALUE& funcMap){
     registerSignalHandlers(callEvHandlers);
     registerSignalHandlers(conversationHandlers);
     registerSignalHandlers(dataTransferEvHandlers);
+    registerSignalHandlers(presenceEvHandlers);
     libjami::start();
 }
 %}