diff --git a/coreapi/friend.c b/coreapi/friend.c
index 3277d72c793af33f2daa6c8546942392c086cf39..c20949dbf346aa00caa9bc2046d1b3f69c0aed0d 100644
--- a/coreapi/friend.c
+++ b/coreapi/friend.c
@@ -58,6 +58,81 @@ using namespace std;
 
 using namespace LinphonePrivate;
 
+BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneFriendCbs);
+
+BELLE_SIP_INSTANCIATE_VPTR(LinphoneFriendCbs,
+                           belle_sip_object_t,
+                           NULL, // destroy
+                           NULL, // clone
+                           NULL, // Marshall
+                           FALSE);
+
+LinphoneFriendCbs *linphone_friend_cbs_new(void) {
+	return belle_sip_object_new(LinphoneFriendCbs);
+}
+
+void linphone_friend_add_callbacks(LinphoneFriend *linphone_friend, LinphoneFriendCbs *cbs) {
+	linphone_friend->callbacks = bctbx_list_append(linphone_friend->callbacks, linphone_friend_cbs_ref(cbs));
+}
+
+void linphone_friend_remove_callbacks(LinphoneFriend *linphone_friend, LinphoneFriendCbs *cbs) {
+	linphone_friend->callbacks = bctbx_list_remove(linphone_friend->callbacks, cbs);
+	linphone_friend_cbs_unref(cbs);
+}
+
+LinphoneFriendCbs *linphone_friend_get_current_callbacks(const LinphoneFriend *linphone_friend) {
+	return linphone_friend->currentCbs;
+}
+
+void linphone_friend_set_current_callbacks(LinphoneFriend *linphone_friend, LinphoneFriendCbs *cbs) {
+	linphone_friend->currentCbs = cbs;
+}
+
+const bctbx_list_t *linphone_friend_get_callbacks_list(const LinphoneFriend *linphone_friend) {
+	return linphone_friend->callbacks;
+}
+
+#define NOTIFY_IF_EXIST(cbName, functionName, ...)                                                                     \
+	bctbx_list_t *callbacksCopy = bctbx_list_copy(linphone_friend_get_callbacks_list(linphone_friend));                \
+	for (bctbx_list_t *it = callbacksCopy; it; it = bctbx_list_next(it)) {                                             \
+		linphone_friend_set_current_callbacks(linphone_friend,                                                         \
+		                                      reinterpret_cast<LinphoneFriendCbs *>(bctbx_list_get_data(it)));         \
+		LinphoneFriendCbs##cbName##Cb cb =                                                                             \
+		    linphone_friend_cbs_get_##functionName(linphone_friend_get_current_callbacks(linphone_friend));            \
+		if (cb) cb(__VA_ARGS__);                                                                                       \
+	}                                                                                                                  \
+	linphone_friend_set_current_callbacks(linphone_friend, nullptr);                                                   \
+	bctbx_list_free(callbacksCopy);
+
+LinphoneFriendCbs *linphone_friend_cbs_ref(LinphoneFriendCbs *cbs) {
+	belle_sip_object_ref(cbs);
+	return cbs;
+}
+
+void linphone_friend_cbs_unref(LinphoneFriendCbs *cbs) {
+	belle_sip_object_unref(cbs);
+}
+
+void *linphone_friend_cbs_get_user_data(const LinphoneFriendCbs *cbs) {
+	return cbs->user_data;
+}
+
+void linphone_friend_cbs_set_user_data(LinphoneFriendCbs *cbs, void *ud) {
+	cbs->user_data = ud;
+}
+
+LinphoneFriendCbsPresenceReceivedCb linphone_friend_cbs_get_presence_received(const LinphoneFriendCbs *cbs) {
+	return cbs->presence_received_cb;
+}
+
+void linphone_friend_cbs_set_presence_received(LinphoneFriendCbs *cbs, LinphoneFriendCbsPresenceReceivedCb cb) {
+	cbs->presence_received_cb = cb;
+}
+
+void linphone_friend_notify_presence_received(LinphoneFriend *linphone_friend) {
+	NOTIFY_IF_EXIST(PresenceReceived, presence_received, linphone_friend)
+}
+
 const char *linphone_online_status_to_string(LinphoneOnlineStatus ss) {
 	const char *str = NULL;
 	switch (ss) {
@@ -701,6 +776,9 @@ static void _linphone_friend_destroy(LinphoneFriend *lf) {
 	if (lf->vcard != NULL) linphone_vcard_unref(lf->vcard);
 	if (lf->refkey != NULL) ms_free(lf->refkey);
 	if (lf->native_uri != NULL) ms_free(lf->native_uri);
+
+	bctbx_list_free_with_data(lf->callbacks, (bctbx_list_free_func)linphone_friend_cbs_unref);
+	lf->callbacks = nullptr;
 }
 
 static belle_sip_error_code
diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c
index f20cc0c6d8e35599979512229df55d492528fe09..1854671f21c5056eb07557471d87326eb20359d0 100644
--- a/coreapi/friendlist.c
+++ b/coreapi/friendlist.c
@@ -277,6 +277,9 @@ static void linphone_friend_presence_received(LinphoneFriendList *list,
 		linphone_friend_set_presence_model_for_uri_or_tel(lf, uri, presence);
 		linphone_core_notify_notify_presence_received_for_uri_or_tel(list->lc, lf, uri, presence);
 	}
+
+	linphone_friend_notify_presence_received(lf);
+
 	// Deprecated
 	linphone_core_notify_notify_presence_received(list->lc, lf);
 }
diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index d8af0b56faf765edfecb437c10de5f9fffb06b4e..ad82ccbb15ca9f10b14372b1fb29cb346c654343 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -5447,14 +5447,15 @@ void linphone_core_set_consolidated_presence(LinphoneCore *lc, LinphoneConsolida
 	LinphonePresenceActivity *activity = NULL;
 
 	cfg_list = linphone_core_get_proxy_config_list(lc);
-	for (item = cfg_list; item != NULL; item = bctbx_list_next(item)) {
-		cfg = (LinphoneProxyConfig *)bctbx_list_get_data(item);
-		if ((cfg != NULL) && (presence == LinphoneConsolidatedPresenceOffline) &&
-		    linphone_proxy_config_publish_enabled(cfg)) {
-			/* Unpublish when going offline before changing the presence model. */
-			linphone_proxy_config_edit(cfg);
-			linphone_proxy_config_enable_publish(cfg, FALSE);
-			linphone_proxy_config_done(cfg);
+	if (presence == LinphoneConsolidatedPresenceOffline) {
+		for (item = cfg_list; item != NULL; item = bctbx_list_next(item)) {
+			cfg = (LinphoneProxyConfig *)bctbx_list_get_data(item);
+			if ((cfg != NULL) && linphone_proxy_config_publish_enabled(cfg)) {
+				/* Unpublish when going offline before changing the presence model. */
+				linphone_proxy_config_edit(cfg);
+				linphone_proxy_config_enable_publish(cfg, FALSE);
+				linphone_proxy_config_done(cfg);
+			}
 		}
 	}
 	model = linphone_presence_model_new();
@@ -5475,17 +5476,20 @@ void linphone_core_set_consolidated_presence(LinphoneCore *lc, LinphoneConsolida
 			linphone_presence_model_set_basic_status(model, LinphonePresenceBasicStatusClosed);
 			break;
 	}
+
 	if (activity != NULL) linphone_presence_model_add_activity(model, activity);
 	linphone_core_set_presence_model(lc, model);
 	linphone_presence_model_unref(model);
-	for (item = cfg_list; item != NULL; item = bctbx_list_next(item)) {
-		cfg = (LinphoneProxyConfig *)bctbx_list_get_data(item);
-		if ((cfg != NULL) && (presence != LinphoneConsolidatedPresenceOffline) &&
-		    !linphone_proxy_config_publish_enabled(cfg)) {
-			/* When going online or busy, publish after changing the presence model. */
-			linphone_proxy_config_edit(cfg);
-			linphone_proxy_config_enable_publish(cfg, TRUE);
-			linphone_proxy_config_done(cfg);
+
+	if (presence != LinphoneConsolidatedPresenceOffline) {
+		for (item = cfg_list; item != NULL; item = bctbx_list_next(item)) {
+			cfg = (LinphoneProxyConfig *)bctbx_list_get_data(item);
+			if ((cfg != NULL) && !linphone_proxy_config_publish_enabled(cfg)) {
+				/* When going online or busy, publish after changing the presence model. */
+				linphone_proxy_config_edit(cfg);
+				linphone_proxy_config_enable_publish(cfg, TRUE);
+				linphone_proxy_config_done(cfg);
+			}
 		}
 	}
 }
diff --git a/coreapi/presence.c b/coreapi/presence.c
index aeeff21a69fc5ff4393306459bd3ff4097b717ae..32d5bb151fcbaa3fe735f9dfd08d5b92addcda3a 100644
--- a/coreapi/presence.c
+++ b/coreapi/presence.c
@@ -2163,6 +2163,7 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa
 		lf->subscribe_active = TRUE;
 		lf->presence_received = TRUE;
 		lf->out_sub_state = linphone_subscription_state_from_sal(ss);
+		linphone_friend_notify_presence_received(lf);
 		linphone_core_notify_notify_presence_received(lc, (LinphoneFriend *)lf);
 		if (op != lf->outsub) {
 			/*case of a NOTIFY received out of any dialog*/
diff --git a/coreapi/private_functions.h b/coreapi/private_functions.h
index 8d8ef133547b066c23861fd75b7bb929eac92faa..b413f3a0fd75cf449131a190dd5be9409f18ac81 100644
--- a/coreapi/private_functions.h
+++ b/coreapi/private_functions.h
@@ -253,9 +253,11 @@ LINPHONE_PUBLIC MSList *linphone_core_fetch_friends_lists_from_db(LinphoneCore *
 LINPHONE_PUBLIC LinphoneFriendListStatus linphone_friend_list_import_friend(LinphoneFriendList *list,
                                                                             LinphoneFriend *lf,
                                                                             bool_t synchronize);
+LinphoneFriendCbs *linphone_friend_cbs_new(void);
 LinphoneFriendListCbs *linphone_friend_list_cbs_new(void);
 void linphone_friend_list_set_current_callbacks(LinphoneFriendList *friend_list, LinphoneFriendListCbs *cbs);
 void linphone_friend_add_addresses_and_numbers_into_maps(LinphoneFriend *lf, LinphoneFriendList *list);
+void linphone_friend_notify_presence_received(LinphoneFriend *lf);
 
 int linphone_parse_host_port(const char *input, char *host, size_t hostlen, int *port);
 int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port);
diff --git a/coreapi/private_structs.h b/coreapi/private_structs.h
index f56e28af1ee2f45024af1c031e4e4f941c813c8d..c3fdbeb4279647763a7b1e7e3fb2080c8725ccc4 100644
--- a/coreapi/private_structs.h
+++ b/coreapi/private_structs.h
@@ -72,6 +72,14 @@ struct _LinphoneFriendPhoneNumberSipUri {
 	char *uri;
 };
 
+struct _LinphoneFriendCbs {
+	belle_sip_object_t base;
+	void *user_data;
+	LinphoneFriendCbsPresenceReceivedCb presence_received_cb;
+};
+
+BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneFriendCbs);
+
 struct _LinphoneFriend {
 	belle_sip_object_t base;
 	void *user_data;
@@ -100,6 +108,8 @@ struct _LinphoneFriend {
 	int rc_index;
 	bool_t is_starred;
 	char *native_uri;
+	bctbx_list_t *callbacks;
+	_LinphoneFriendCbs *currentCbs;
 };
 
 BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneFriend);
diff --git a/include/linphone/api/c-factory.h b/include/linphone/api/c-factory.h
index 2417aeb5a4f54c35d7e013a7e9aeb64af8e2b081..f9506326585993265455a751ad589866248304e0 100644
--- a/include/linphone/api/c-factory.h
+++ b/include/linphone/api/c-factory.h
@@ -694,6 +694,13 @@ LINPHONE_PUBLIC LinphoneEventCbs *linphone_factory_create_event_cbs(LinphoneFact
  */
 LINPHONE_PUBLIC LinphoneFriendListCbs *linphone_factory_create_friend_list_cbs(LinphoneFactory *factory);
 
+/**
+ * Creates an object #LinphoneFriendCbs
+ * @param factory the #LinphoneFactory @notnil
+ * @return a #LinphoneFriendCbs @notnil
+ */
+LINPHONE_PUBLIC LinphoneFriendCbs *linphone_factory_create_friend_cbs(LinphoneFactory *factory);
+
 /**
  * Creates an object #LinphoneAccountCreatorCbs
  * @param factory the #LinphoneFactory @notnil
diff --git a/include/linphone/callbacks.h b/include/linphone/callbacks.h
index 98eed98512ee8c3a4544022a1cf22bfabb7989df..35680d2ab2332547b6ba306f8c51ea6d6e1b63d7 100644
--- a/include/linphone/callbacks.h
+++ b/include/linphone/callbacks.h
@@ -752,6 +752,12 @@ typedef void (*LinphoneFriendListCbsSyncStateChangedCb)(LinphoneFriendList *frie
  **/
 typedef void (*LinphoneFriendListCbsPresenceReceivedCb)(LinphoneFriendList *friend_list, const bctbx_list_t *friends);
 
+/**
+ * Callback used to notify a friend that it has received presence information.
+ * @param linphone_friend The #LinphoneFriend object for which the status has changed @notnil
+ **/
+typedef void (*LinphoneFriendCbsPresenceReceivedCb)(LinphoneFriend *linphone_friend);
+
 /**
  * @}
  **/
diff --git a/include/linphone/core_utils.h b/include/linphone/core_utils.h
index 1976bb051d8a774afccc912d2d82b96ad7090156..a4d572cf07eefe4ef9be987ca88143be454c2b55 100644
--- a/include/linphone/core_utils.h
+++ b/include/linphone/core_utils.h
@@ -200,6 +200,7 @@ LINPHONE_PUBLIC void linphone_core_remove_iterate_hook(LinphoneCore *lc, Linphon
 
 LINPHONE_PUBLIC const bctbx_list_t *linphone_player_get_callbacks_list(const LinphonePlayer *player);
 LINPHONE_PUBLIC const bctbx_list_t *linphone_event_get_callbacks_list(const LinphoneEvent *ev);
+LINPHONE_PUBLIC const bctbx_list_t *linphone_friend_get_callbacks_list(const LinphoneFriend *linphone_friend);
 LINPHONE_PUBLIC const bctbx_list_t *linphone_friend_list_get_callbacks_list(const LinphoneFriendList *friend_list);
 LINPHONE_PUBLIC const bctbx_list_t *
 linphone_logging_service_get_callbacks_list(const LinphoneLoggingService *log_service);
diff --git a/include/linphone/friend.h b/include/linphone/friend.h
index 53fa3f229b37d43ed47bb95464ff826d67ab5103..93115b5b9915a6e31cf1f0dd71afc2a53321c9f9 100644
--- a/include/linphone/friend.h
+++ b/include/linphone/friend.h
@@ -21,6 +21,7 @@
 #ifndef LINPHONE_FRIEND_H_
 #define LINPHONE_FRIEND_H_
 
+#include "linphone/callbacks.h"
 #include "linphone/sipsetup.h"
 #include "linphone/types.h"
 
@@ -455,6 +456,74 @@ LINPHONE_PUBLIC void linphone_friend_set_organization(LinphoneFriend *linphone_f
  */
 LINPHONE_PUBLIC const char *linphone_friend_get_organization(const LinphoneFriend *linphone_friend);
 
+/************ */
+/* Friend CBS */
+/* ********** */
+
+/**
+ * Adds the #LinphoneFriendCbs object associated with a LinphoneFriend.
+ * @param linphone_friend #LinphoneFriend object @notnil
+ * @param cbs The current #LinphoneFriendCbs object to be added to the LinphoneFriend. @notnil
+ **/
+LINPHONE_PUBLIC void linphone_friend_add_callbacks(LinphoneFriend *linphone_friend, LinphoneFriendCbs *cbs);
+
+/**
+ * Removes the #LinphoneFriendCbs object associated with a LinphoneFriend.
+ * @param linphone_friend #LinphoneFriend object @notnil
+ * @param cbs The current #LinphoneFriendCbs object to be remove from the LinphoneFriend. @notnil
+ **/
+LINPHONE_PUBLIC void linphone_friend_remove_callbacks(LinphoneFriend *linphone_friend, LinphoneFriendCbs *cbs);
+
+/**
+ * Get the current #LinphoneFriendCbs object associated with a LinphoneFriend.
+ * @param linphone_friend #LinphoneFriend object @notnil
+ * @return The current #LinphoneFriendCbs object associated with the LinphoneFriend. @maybenil
+ **/
+LINPHONE_PUBLIC LinphoneFriendCbs *linphone_friend_get_current_callbacks(const LinphoneFriend *linphone_friend);
+
+/**
+ * Acquire a reference to a #LinphoneFriendCbs object.
+ * @param cbs #LinphoneFriendCbs object. @notnil
+ * @return The same #LinphoneFriendCbs object.
+ **/
+LINPHONE_PUBLIC LinphoneFriendCbs *linphone_friend_cbs_ref(LinphoneFriendCbs *cbs);
+
+/**
+ * Release a reference to a #LinphoneFriendCbs object.
+ * @param cbs #LinphoneFriendCbs object. @notnil
+ **/
+LINPHONE_PUBLIC void linphone_friend_cbs_unref(LinphoneFriendCbs *cbs);
+
+/**
+ * Retrieve the user pointer associated with a #LinphoneFriendCbs object.
+ * @param cbs #LinphoneFriendCbs object. @notnil
+ * @return The user pointer associated with the #LinphoneFriendCbs object. @maybenil
+ **/
+LINPHONE_PUBLIC void *linphone_friend_cbs_get_user_data(const LinphoneFriendCbs *cbs);
+
+/**
+ * Assign a user pointer to a #LinphoneFriendCbs object.
+ * @param cbs #LinphoneFriendCbs object. @notnil
+ * @param user_data The user pointer to associate with the #LinphoneFriendCbs object. @maybenil
+ **/
+LINPHONE_PUBLIC void linphone_friend_cbs_set_user_data(LinphoneFriendCbs *cbs, void *user_data);
+
+/**
+ * Get the presence received callback.
+ * @param cbs #LinphoneFriendCbs object. @notnil
+ * @return The current presence received callback.
+ **/
+LINPHONE_PUBLIC LinphoneFriendCbsPresenceReceivedCb
+linphone_friend_cbs_get_presence_received(const LinphoneFriendCbs *cbs);
+
+/**
+ * Set the presence received callback.
+ * @param cbs #LinphoneFriendCbs object. @notnil
+ * @param cb The presence received callback to be used.
+ **/
+LINPHONE_PUBLIC void linphone_friend_cbs_set_presence_received(LinphoneFriendCbs *cbs,
+                                                               LinphoneFriendCbsPresenceReceivedCb cb);
+
 /************ */
 /* DEPRECATED */
 /* ********** */
diff --git a/include/linphone/types.h b/include/linphone/types.h
index 82c4e3cfee7b60a167d7ebe697345912077f5ffc..906774da0229bdce007430afdb92f1def63f48b8 100644
--- a/include/linphone/types.h
+++ b/include/linphone/types.h
@@ -320,6 +320,12 @@ typedef enum _LinphoneVideoSourceType {
  */
 typedef struct _LinphoneFriend LinphoneFriend;
 
+/**
+ * @brief An object to handle the callbacks for #LinphoneFriend.
+ * @ingroup buddy_list
+ **/
+typedef struct _LinphoneFriendCbs LinphoneFriendCbs;
+
 /**
  * @brief Enum describing the capabilities of a #LinphoneFriend, populated through presence subscribe/notify process.
  * @ingroup buddy_list
diff --git a/src/c-wrapper/api/c-factory.cpp b/src/c-wrapper/api/c-factory.cpp
index 4bf46ebb371a76729655a4fc8c987b2438aeb587..c54005a8a9c6bcb7616614f6e2799780d85170f3 100644
--- a/src/c-wrapper/api/c-factory.cpp
+++ b/src/c-wrapper/api/c-factory.cpp
@@ -389,6 +389,10 @@ LinphoneFriendListCbs *linphone_factory_create_friend_list_cbs(LinphoneFactory *
 	return Factory::toCpp(factory)->createFriendListCbs();
 }
 
+LinphoneFriendCbs *linphone_factory_create_friend_cbs(LinphoneFactory *factory) {
+	return Factory::toCpp(factory)->createFriendCbs();
+}
+
 LinphoneAccountCreatorCbs *linphone_factory_create_account_creator_cbs(LinphoneFactory *factory) {
 	return Factory::toCpp(factory)->createAccountCreatorCbs();
 }
diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h
index 86ab0725f75b3981c27be1aa7a74196baa27ba8d..183c84221b686940cecdfe7d60e71f3e10db7978 100644
--- a/src/c-wrapper/c-wrapper.h
+++ b/src/c-wrapper/c-wrapper.h
@@ -263,13 +263,14 @@ BELLE_SIP_TYPE_ID(LinphoneAccountCreator), BELLE_SIP_TYPE_ID(LinphoneAccountCrea
     BELLE_SIP_TYPE_ID(LinphoneContactProvider), BELLE_SIP_TYPE_ID(LinphoneContactSearch),
     BELLE_SIP_TYPE_ID(LinphoneCoreCbs), BELLE_SIP_TYPE_ID(LinphoneErrorInfo), BELLE_SIP_TYPE_ID(LinphoneEvent),
     BELLE_SIP_TYPE_ID(LinphoneEventCbs), BELLE_SIP_TYPE_ID(LinphoneFactory), BELLE_SIP_TYPE_ID(LinphoneFriend),
-    BELLE_SIP_TYPE_ID(LinphoneFriendList), BELLE_SIP_TYPE_ID(LinphoneFriendListCbs),
-    BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngine), BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngineCbs),
-    BELLE_SIP_TYPE_ID(LinphoneImNotifPolicy), BELLE_SIP_TYPE_ID(LinphoneInfoMessage),
-    BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch),
-    BELLE_SIP_TYPE_ID(LinphoneLoggingService), BELLE_SIP_TYPE_ID(LinphoneLoggingServiceCbs),
-    BELLE_SIP_TYPE_ID(LinphoneMagicSearchCbs), BELLE_SIP_TYPE_ID(LinphoneParticipant),
-    BELLE_SIP_TYPE_ID(LinphoneParticipantDevice), BELLE_SIP_TYPE_ID(LinphoneParticipantDeviceCbs),
+    BELLE_SIP_TYPE_ID(LinphoneFriendCbs), BELLE_SIP_TYPE_ID(LinphoneFriendList),
+    BELLE_SIP_TYPE_ID(LinphoneFriendListCbs), BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngine),
+    BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngineCbs), BELLE_SIP_TYPE_ID(LinphoneImNotifPolicy),
+    BELLE_SIP_TYPE_ID(LinphoneInfoMessage), BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider),
+    BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch), BELLE_SIP_TYPE_ID(LinphoneLoggingService),
+    BELLE_SIP_TYPE_ID(LinphoneLoggingServiceCbs), BELLE_SIP_TYPE_ID(LinphoneMagicSearchCbs),
+    BELLE_SIP_TYPE_ID(LinphoneParticipant), BELLE_SIP_TYPE_ID(LinphoneParticipantDevice),
+    BELLE_SIP_TYPE_ID(LinphoneParticipantDeviceCbs), BELLE_SIP_TYPE_ID(LinphonePayloadType),
     BELLE_SIP_TYPE_ID(LinphonePlayer), BELLE_SIP_TYPE_ID(LinphonePlayerCbs),
     BELLE_SIP_TYPE_ID(LinphonePresenceActivity), BELLE_SIP_TYPE_ID(LinphonePresenceModel),
     BELLE_SIP_TYPE_ID(LinphonePresenceNote), BELLE_SIP_TYPE_ID(LinphonePresencePerson),
diff --git a/src/factory/factory.cpp b/src/factory/factory.cpp
index 3ef545c16fd3976e9f4ec57c188971fb12d808c5..739eaa0ffc8e047f9fc7a0450c11c63c37ac09fc 100644
--- a/src/factory/factory.cpp
+++ b/src/factory/factory.cpp
@@ -610,6 +610,10 @@ LinphoneEventCbs *Factory::createEventCbs() const {
 	return linphone_event_cbs_new();
 }
 
+LinphoneFriendCbs *Factory::createFriendCbs() const {
+	return linphone_friend_cbs_new();
+}
+
 LinphoneFriendListCbs *Factory::createFriendListCbs() const {
 	return linphone_friend_list_cbs_new();
 }
diff --git a/src/factory/factory.h b/src/factory/factory.h
index b647717759327e70936b35b737fc0bc0afdcac69..1eb3b31b1936cbc35d9e853edaee05907e020e86 100644
--- a/src/factory/factory.h
+++ b/src/factory/factory.h
@@ -179,6 +179,7 @@ public:
 
 	LinphoneEventCbs *createEventCbs() const;
 
+	LinphoneFriendCbs *createFriendCbs() const;
 	LinphoneFriendListCbs *createFriendListCbs() const;
 
 	LinphoneAccountCreatorCbs *createAccountCreatorCbs() const;
diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h
index 051543c3ef6d99eb1beab73d43547d9c074888dc..f49160c96c24359f237567699f7bdc19e6ecd178 100644
--- a/tester/liblinphone_tester.h
+++ b/tester/liblinphone_tester.h
@@ -316,6 +316,7 @@ typedef struct _stats {
 	int number_of_NotifyReceived;
 	int number_of_NotifyPresenceReceived;
 	int number_of_NotifyPresenceReceivedForUriOrTel;
+	int number_of_NotifyFriendPresenceReceived;
 	int number_of_LinphonePresenceActivityOffline;
 	int number_of_LinphonePresenceActivityOnline;
 	int number_of_LinphonePresenceActivityAppointment;
@@ -558,6 +559,7 @@ void registration_state_changed(struct _LinphoneCore *lc,
 void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg);
 void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state);
 void notify_presence_received(LinphoneCore *lc, LinphoneFriend *lf);
+void notify_friend_presence_received(LinphoneFriend *lf);
 void notify_presence_received_for_uri_or_tel(LinphoneCore *lc,
                                              LinphoneFriend *lf,
                                              const char *uri_or_tel,
diff --git a/tester/presence_tester.c b/tester/presence_tester.c
index 543fe610858ab430369e67bf5c1bdbf3dd8c9654..63587bb4f058820f6e142cf6978d937b2967b1ad 100644
--- a/tester/presence_tester.c
+++ b/tester/presence_tester.c
@@ -53,8 +53,12 @@ static bool_t subscribe_to_callee_presence(LinphoneCoreManager *caller_mgr, Linp
 	linphone_friend_enable_subscribes(friend, TRUE);
 	linphone_friend_done(friend);
 
+	LinphoneFriendCbs *cbs = linphone_factory_create_friend_cbs(linphone_factory_get());
+	linphone_friend_cbs_set_presence_received(cbs, notify_friend_presence_received);
+	linphone_friend_add_callbacks(friend, cbs);
+	linphone_friend_cbs_unref(cbs);
+
 	linphone_core_add_friend(caller_mgr->lc, friend);
-	linphone_friend_unref(friend);
 
 	result = wait_for(caller_mgr->lc, callee_mgr->lc, &caller_mgr->stat.number_of_LinphonePresenceActivityOnline,
 	                  initial_caller.number_of_LinphonePresenceActivityOnline + 1);
@@ -71,6 +75,10 @@ static bool_t subscribe_to_callee_presence(LinphoneCoreManager *caller_mgr, Linp
 	BC_ASSERT_EQUAL(caller_mgr->stat.number_of_NotifyPresenceReceived,
 	                initial_caller.number_of_NotifyPresenceReceived + 1, int, "%d");
 
+	BC_ASSERT_EQUAL(caller_mgr->stat.number_of_NotifyFriendPresenceReceived,
+	                initial_caller.number_of_NotifyFriendPresenceReceived + 1, int, "%d");
+	linphone_friend_unref(friend);
+
 	ms_free(identity);
 	return result;
 }
diff --git a/tester/tester.c b/tester/tester.c
index 8da28cffd47534f4b947dd835aa3f8a624760490..3580080af0d9a47e14ecd13b9943f9732529ac56 100644
--- a/tester/tester.c
+++ b/tester/tester.c
@@ -61,7 +61,7 @@
 #endif
 #endif
 
-//#define SKIP_PULSEAUDIO 1
+// #define SKIP_PULSEAUDIO 1
 
 #if _WIN32
 #define unlink _unlink
@@ -3208,6 +3208,13 @@ void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char
 	linphone_core_add_friend(lc, lf); /*accept subscription*/
 }
 
+void notify_friend_presence_received(LinphoneFriend *lf) {
+	ms_message("Presence received for friend [%p (%s)]", lf, linphone_friend_get_name(lf));
+	LinphoneCore *lc = linphone_friend_get_core(lf);
+	stats *counters = get_stats(lc);
+	counters->number_of_NotifyFriendPresenceReceived++;
+}
+
 void notify_presence_received(LinphoneCore *lc, LinphoneFriend *lf) {
 	stats *counters;
 	unsigned int i;