diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index 091b9e127e7c980d7c59f2b53780a24b35c0f267..04a85224c6c33e8cc3f896258d4fca726cba8a89 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -384,6 +384,14 @@ void linphone_core_cbs_set_reaction_removed(LinphoneCoreCbs *cbs, LinphoneCoreCb
 	cbs->vtable->reaction_removed = cb;
 }
 
+void linphone_core_cbs_set_reaction_removed_private(LinphoneCoreCbs *cbs, LinphoneCoreCbsReactionRemovedPrivateCb cb) {
+	cbs->vtable->reaction_removed_private = cb;
+}
+
+LinphoneCoreCbsReactionRemovedPrivateCb linphone_core_cbs_get_reaction_removed_private(LinphoneCoreCbs *cbs) {
+	return cbs->vtable->reaction_removed_private;
+}
+
 LinphoneCoreCbsMessagesReceivedCb linphone_core_cbs_get_messages_received(LinphoneCoreCbs *cbs) {
 	return cbs->vtable->messages_received;
 }
diff --git a/coreapi/private_functions.h b/coreapi/private_functions.h
index 89e2d905b7ddc3b6441e747e743c243618875314..9b30402546c418707dca4b665615fd02f29e597e 100644
--- a/coreapi/private_functions.h
+++ b/coreapi/private_functions.h
@@ -860,6 +860,11 @@ void linphone_core_notify_message_reaction_removed(LinphoneCore *lc,
                                                    LinphoneChatRoom *room,
                                                    LinphoneChatMessage *message,
                                                    const LinphoneAddress *address);
+void linphone_core_notify_message_reaction_removed_private(LinphoneCore *lc,
+                                                           LinphoneChatRoom *room,
+                                                           LinphoneChatMessage *message,
+                                                           const LinphoneAddress *address,
+                                                           const char *callId);
 void linphone_core_notify_messages_received(LinphoneCore *lc, LinphoneChatRoom *room, const bctbx_list_t *messages);
 void linphone_core_notify_message_sent(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message);
 void linphone_core_notify_message_received_unable_decrypt(LinphoneCore *lc,
diff --git a/coreapi/vtables.c b/coreapi/vtables.c
index 6247f3466c60201188a936993dfba532376bd894..f51b5798d0279d442ba97fd6782bea37405b5c12 100644
--- a/coreapi/vtables.c
+++ b/coreapi/vtables.c
@@ -260,6 +260,15 @@ void linphone_core_notify_message_reaction_removed(LinphoneCore *lc,
 	cleanup_dead_vtable_refs(lc);
 }
 
+void linphone_core_notify_message_reaction_removed_private(LinphoneCore *lc,
+                                                           LinphoneChatRoom *room,
+                                                           LinphoneChatMessage *message,
+                                                           const LinphoneAddress *address,
+                                                           const char *callId) {
+	NOTIFY_IF_EXIST(reaction_removed_private, lc, room, message, address, callId);
+	cleanup_dead_vtable_refs(lc);
+}
+
 void linphone_core_notify_messages_received(LinphoneCore *lc, LinphoneChatRoom *room, const bctbx_list_t *messages) {
 	NOTIFY_IF_EXIST(messages_received, lc, room, messages);
 	cleanup_dead_vtable_refs(lc);
diff --git a/include/linphone/api/c-chat-message-reaction.h b/include/linphone/api/c-chat-message-reaction.h
index 3c6865e392832a9dc734f71bb64b11586b41a477..1ceb3e258abafc922752a4e8e6c002ad473a5ca0 100644
--- a/include/linphone/api/c-chat-message-reaction.h
+++ b/include/linphone/api/c-chat-message-reaction.h
@@ -66,6 +66,13 @@ LINPHONE_PUBLIC void linphone_chat_message_reaction_unref(LinphoneChatMessageRea
  */
 LINPHONE_PUBLIC void linphone_chat_message_reaction_send(LinphoneChatMessageReaction *reaction);
 
+/**
+ * Allows to get the Call ID associated with a #LinphoneChatMessageReaction.
+ * @param reaction the #LinphoneChatMessageReaction. @notnil
+ * @return the Call ID associated with this reaction.
+ */
+LINPHONE_PUBLIC const char *linphone_chat_message_reaction_get_call_id(const LinphoneChatMessageReaction *reaction);
+
 /**
  * @}
  */
diff --git a/include/linphone/callbacks.h b/include/linphone/callbacks.h
index e9bddaa609b63ccbf25aaf3051662651d1affc98..bc16c28f670b836c6f1746a34954631c7d77debd 100644
--- a/include/linphone/callbacks.h
+++ b/include/linphone/callbacks.h
@@ -963,6 +963,21 @@ typedef void (*LinphoneCoreCbsChatRoomExhumedCb)(LinphoneCore *core, LinphoneCha
  **/
 typedef void (*LinphonePlayerCbsEofReachedCb)(LinphonePlayer *player);
 
+/**
+ * @}
+ **/
+
+/************ */
+/* PRIVATE */
+/* ********** */
+
+// Private: do not document or wrap
+typedef void (*LinphoneCoreCbsReactionRemovedPrivateCb)(LinphoneCore *core,
+                                                        LinphoneChatRoom *chat_room,
+                                                        LinphoneChatMessage *message,
+                                                        const LinphoneAddress *address,
+                                                        const char *callId);
+
 /************ */
 /* DEPRECATED */
 /* ********** */
@@ -996,8 +1011,4 @@ typedef void (*LinphoneCoreAuthInfoRequestedCb)(LinphoneCore *core,
                                                 const char *username,
                                                 const char *domain);
 
-/**
- * @}
- **/
-
 #endif /* LINPHONE_CALLBACKS_H_ */
diff --git a/include/linphone/core.h b/include/linphone/core.h
index 0cb1880079c2f392fb10b676c4afbad1e915b133..a25af79f56ff0dece0a889e8929a922a015469a0 100644
--- a/include/linphone/core.h
+++ b/include/linphone/core.h
@@ -303,6 +303,7 @@ typedef struct _LinphoneCoreVTable {
 	LinphoneCoreCbsPreviewDisplayErrorOccurredCb preview_display_error_occurred;
 	LinphoneCoreCbsNewMessageReactionCb new_message_reaction;
 	LinphoneCoreCbsReactionRemovedCb reaction_removed;
+	LinphoneCoreCbsReactionRemovedPrivateCb reaction_removed_private;
 	void *user_data; /**<User data associated with the above callbacks */
 } LinphoneCoreVTable;
 
diff --git a/src/c-wrapper/api/c-chat-message-reaction.cpp b/src/c-wrapper/api/c-chat-message-reaction.cpp
index 2b456cf4c4e1ce0b2e4c9eeb025e6830e8580418..6eb3c8aa55c184eecaffe829ddc3a56b4c7617bb 100644
--- a/src/c-wrapper/api/c-chat-message-reaction.cpp
+++ b/src/c-wrapper/api/c-chat-message-reaction.cpp
@@ -48,4 +48,8 @@ void linphone_chat_message_reaction_unref(LinphoneChatMessageReaction *reaction)
 
 void linphone_chat_message_reaction_send(LinphoneChatMessageReaction *reaction) {
 	ChatMessageReaction::toCpp(reaction)->send();
+}
+
+const char *linphone_chat_message_reaction_get_call_id(const LinphoneChatMessageReaction *reaction) {
+	return L_STRING_TO_C(ChatMessageReaction::toCpp(reaction)->getCallId());
 }
\ No newline at end of file
diff --git a/src/chat/chat-message/chat-message-reaction.cpp b/src/chat/chat-message/chat-message-reaction.cpp
index 9322fb72bdec2ac0a51b532cf4e51cfd59391a25..e2407c5da91ded13c901c3c6421bf2ed7c0a85b0 100644
--- a/src/chat/chat-message/chat-message-reaction.cpp
+++ b/src/chat/chat-message/chat-message-reaction.cpp
@@ -72,6 +72,8 @@ void ChatMessageReaction::onChatMessageStateChanged(const shared_ptr<ChatMessage
 			return;
 		}
 
+		setCallId(message->getPrivate()->getCallId());
+
 		LinphoneChatMessage *msg = L_GET_C_BACK_PTR(originalMessage);
 		const string &messageId = originalMessage->getImdnMessageId();
 		LinphoneChatRoom *cr = L_GET_C_BACK_PTR(message->getChatRoom());
@@ -85,6 +87,8 @@ void ChatMessageReaction::onChatMessageStateChanged(const shared_ptr<ChatMessage
 
 			_linphone_chat_message_notify_reaction_removed(msg, address);
 			linphone_core_notify_message_reaction_removed(message->getCore()->getCCore(), cr, msg, address);
+			linphone_core_notify_message_reaction_removed_private(message->getCore()->getCCore(), cr, msg, address,
+			                                                      message->getPrivate()->getCallId().c_str());
 		} else {
 			LinphoneChatMessageReaction *reaction = getSharedFromThis()->toC();
 			_linphone_chat_message_notify_new_message_reaction(msg, reaction);
diff --git a/src/chat/chat-message/chat-message-reaction.h b/src/chat/chat-message/chat-message-reaction.h
index 79fa9d87051395dd6461d2dafd65e254acfe3788..7893c6a53c19431de46a2a7566417e35a6a57cbc 100644
--- a/src/chat/chat-message/chat-message-reaction.h
+++ b/src/chat/chat-message/chat-message-reaction.h
@@ -55,6 +55,14 @@ public:
 	std::shared_ptr<const Address> getFromAddress() const;
 	void send();
 
+	void setCallId(const std::string &id) {
+		callId = id;
+	}
+
+	const std::string &getCallId() const {
+		return callId;
+	}
+
 	void setChatRoom(std::shared_ptr<AbstractChatRoom> cr) {
 		chatRoom = cr;
 	}
@@ -65,6 +73,7 @@ public:
 private:
 	std::string messageId;
 	std::string reaction;
+	std::string callId;
 	std::shared_ptr<const Address> fromAddress;
 	std::shared_ptr<ChatMessage> reactionMessage;
 	std::shared_ptr<AbstractChatRoom> chatRoom;
diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp
index 25a448ce310970ad6bf4506622f3235dfc0064ab..0a7cba237d6ecf68e0cc9f76af4b0306e783bfe5 100644
--- a/src/chat/chat-message/chat-message.cpp
+++ b/src/chat/chat-message/chat-message.cpp
@@ -951,6 +951,9 @@ LinphoneReason ChatMessagePrivate::receive() {
 			_linphone_chat_message_notify_reaction_removed(msg, address);
 			linphone_core_notify_message_reaction_removed(q->getCore()->getCCore(), cr, msg, address);
 
+			const char *call_id = getCallId().c_str();
+			linphone_core_notify_message_reaction_removed_private(q->getCore()->getCCore(), cr, msg, address, call_id);
+
 			return reason;
 		}
 
@@ -958,6 +961,8 @@ LinphoneReason ChatMessagePrivate::receive() {
 
 		LinphoneChatMessageReaction *reaction =
 		    ChatMessageReaction::createCObject(messageId, getUtf8Text(), q->getFromAddress());
+		ChatMessageReaction::toCpp(reaction)->setCallId(getCallId().c_str());
+
 		_linphone_chat_message_notify_new_message_reaction(msg, reaction);
 
 		linphone_core_notify_new_message_reaction(q->getCore()->getCCore(), cr, msg, reaction);
diff --git a/src/core/shared-core-helpers/ios-shared-core-helpers.mm b/src/core/shared-core-helpers/ios-shared-core-helpers.mm
index c822071527626d32a5abc0daec247e2eb356c6a4..062d0e3dc3606d2074899e95d807893ca88e2a9b 100644
--- a/src/core/shared-core-helpers/ios-shared-core-helpers.mm
+++ b/src/core/shared-core-helpers/ios-shared-core-helpers.mm
@@ -211,11 +211,22 @@ static void on_push_notification_message_received(LinphoneCore *lc, LinphoneChat
 	}
 }
 
+static void on_push_notification_reaction_to_message_received(LinphoneChatMessage *msg, const LinphoneChatMessageReaction *reaction) {
+	const char *callId = linphone_chat_message_reaction_get_call_id(reaction);
+	// TODO: do like in putMsgInUserDefaults
+}
+
+static void on_push_notification_reaction_to_message_removed(LinphoneChatMessage *message, const LinphoneAddress *address, const char *callId) {
+	// TODO: don't wait for chat message to arrive
+}
+
 void IosSharedCoreHelpers::registerSharedCoreMsgCallback() {
 	if (isCoreShared()) {
 		lInfo() << "[push] register shared core msg callback";
 		LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
 		linphone_core_cbs_set_message_received(cbs, on_push_notification_message_received);
+		linphone_chat_message_cbs_set_new_message_reaction(cbs, on_push_notification_reaction_to_message_received);
+		linphone_chat_message_cbs_set_reaction_removed_private(cbs, on_push_notification_reaction_to_message_removed);
 		linphone_core_add_callbacks(getCore()->getCCore(), cbs);
 		linphone_core_cbs_unref(cbs);
 	}
diff --git a/tester/message_tester.c b/tester/message_tester.c
index 786b5bf2d22bd9127efbaae7045b442c1b75c6eb..f45dee002b1c0f0a866fd30336920de9ab80bc13 100644
--- a/tester/message_tester.c
+++ b/tester/message_tester.c
@@ -438,6 +438,9 @@ void check_reactions(LinphoneChatMessage *message,
 			const char *reaction_body = linphone_chat_message_reaction_get_body(reaction);
 			BC_ASSERT_STRING_EQUAL(reaction_body, expected_reaction);
 
+			const char *reaction_call_id = linphone_chat_message_get_call_id(reaction);
+			BC_ASSERT_PTR_NOT_NULL(reaction_call_id);
+
 			const LinphoneAddress *from = linphone_chat_message_reaction_get_from_address(reaction);
 			BC_ASSERT_STRING_EQUAL(linphone_address_as_string_uri_only(from), expected_reaction_from);
 		}