diff --git a/lib/actions/message-report-actions.js b/lib/actions/message-report-actions.js
new file mode 100644
--- /dev/null
+++ b/lib/actions/message-report-actions.js
@@ -0,0 +1,22 @@
+// @flow
+
+import type {
+  MessageReportCreationRequest,
+  MessageReportCreationResult,
+} from '../types/message-report-types';
+import type { CallServerEndpoint } from '../utils/call-server-endpoint';
+
+const sendMessageReportActionTypes = Object.freeze({
+  started: 'SEND_MESSAGE_REPORT_STARTED',
+  success: 'SEND_MESSAGE_REPORT_SUCCESS',
+  failed: 'SEND_MESSAGE_REPORT_FAILED',
+});
+const sendMessageReport = (
+  callServerEndpoint: CallServerEndpoint,
+): ((
+  request: MessageReportCreationRequest,
+) => Promise<MessageReportCreationResult>) => async request => {
+  return await callServerEndpoint('create_message_report', request);
+};
+
+export { sendMessageReportActionTypes, sendMessageReport };
diff --git a/lib/reducers/message-reducer.js b/lib/reducers/message-reducer.js
--- a/lib/reducers/message-reducer.js
+++ b/lib/reducers/message-reducer.js
@@ -32,6 +32,7 @@
   fetchSingleMostRecentMessagesFromThreadsActionTypes,
   setMessageStoreMessages,
 } from '../actions/message-actions';
+import { sendMessageReportActionTypes } from '../actions/message-report-actions';
 import {
   changeThreadSettingsActionTypes,
   deleteThreadActionTypes,
@@ -823,6 +824,16 @@
       messagesResult.truncationStatuses,
       newThreadInfos,
     );
+  } else if (action.type === sendMessageReportActionTypes.success) {
+    return mergeNewMessages(
+      messageStore,
+      [action.payload.messageInfo],
+      {
+        [action.payload.messageInfo.threadID]:
+          messageTruncationStatus.UNCHANGED,
+      },
+      newThreadInfos,
+    );
   } else if (action.type === registerActionTypes.success) {
     const truncationStatuses = {};
     for (const messageInfo of action.payload.rawMessageInfos) {
diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js
--- a/lib/types/redux-types.js
+++ b/lib/types/redux-types.js
@@ -33,6 +33,7 @@
 import type { LifecycleState } from './lifecycle-state-types';
 import type { LoadingStatus, LoadingInfo } from './loading-types';
 import type { UpdateMultimediaMessageMediaPayload } from './media-types';
+import type { MessageReportCreationResult } from './message-report-types';
 import type {
   MessageStore,
   RawMultimediaMessageInfo,
@@ -801,6 +802,22 @@
       +type: 'SET_USER_SETTINGS_FAILED',
       +payload: Error,
       +loadingInfo: LoadingInfo,
+    }
+  | {
+      +type: 'SEND_MESSAGE_REPORT_STARTED',
+      +payload?: void,
+      +loadingInfo: LoadingInfo,
+    }
+  | {
+      +type: 'SEND_MESSAGE_REPORT_SUCCESS',
+      +payload: MessageReportCreationResult,
+      +loadingInfo: LoadingInfo,
+    }
+  | {
+      +type: 'SEND_MESSAGE_REPORT_FAILED',
+      +error: true,
+      +payload: Error,
+      +loadingInfo: LoadingInfo,
     };
 
 export type ActionPayload = ?(Object | Array<*> | $ReadOnlyArray<*> | string);
diff --git a/native/chat/message-report-utils.js b/native/chat/message-report-utils.js
new file mode 100644
--- /dev/null
+++ b/native/chat/message-report-utils.js
@@ -0,0 +1,68 @@
+// @flow
+
+import Alert from 'react-native/Libraries/Alert/Alert';
+
+import {
+  sendMessageReport,
+  sendMessageReportActionTypes,
+} from 'lib/actions/message-report-actions';
+import type { BindServerCall, DispatchFunctions } from 'lib/utils/action-utils';
+
+import { displayActionResultModal } from '../navigation/action-result-modal';
+import type { TooltipRoute } from '../navigation/tooltip.react';
+
+const confirmReport = () => displayActionResultModal('reported to admin');
+
+function onPressReport(
+  route:
+    | TooltipRoute<'TextMessageTooltipModal'>
+    | TooltipRoute<'MultimediaMessageTooltipModal'>,
+  dispatchFunctions: DispatchFunctions,
+  bindServerCall: BindServerCall,
+) {
+  const messageID = route.params.item.messageInfo.id;
+  if (!messageID) {
+    Alert.alert(
+      'Couldn’t send the report',
+      'Uhh... try again?',
+      [{ text: 'OK' }],
+      {
+        cancelable: false,
+      },
+    );
+    return;
+  }
+  reportMessage(messageID, dispatchFunctions, bindServerCall);
+}
+
+function reportMessage(
+  messageID: string,
+  dispatchFunctions: DispatchFunctions,
+  bindServerCall: BindServerCall,
+) {
+  const callSendMessageReport = bindServerCall(sendMessageReport);
+  const messageReportPromise = (async () => {
+    try {
+      const result = await callSendMessageReport({ messageID });
+      confirmReport();
+      return result;
+    } catch (e) {
+      Alert.alert(
+        'Couldn’t send the report',
+        'Uhh... try again?',
+        [{ text: 'OK' }],
+        {
+          cancelable: false,
+        },
+      );
+      throw e;
+    }
+  })();
+
+  dispatchFunctions.dispatchActionPromise(
+    sendMessageReportActionTypes,
+    messageReportPromise,
+  );
+}
+
+export { onPressReport };
diff --git a/native/chat/multimedia-message-tooltip-modal.react.js b/native/chat/multimedia-message-tooltip-modal.react.js
--- a/native/chat/multimedia-message-tooltip-modal.react.js
+++ b/native/chat/multimedia-message-tooltip-modal.react.js
@@ -2,7 +2,6 @@
 
 import * as React from 'react';
 
-import { displayActionResultModal } from '../navigation/action-result-modal';
 import {
   createTooltip,
   tooltipHeight,
@@ -11,6 +10,7 @@
 } from '../navigation/tooltip.react';
 import type { ChatMultimediaMessageInfoItem } from '../types/chat-types';
 import type { VerticalBounds } from '../types/layout-types';
+import { onPressReport } from './message-report-utils';
 import MultimediaMessageTooltipButton from './multimedia-message-tooltip-button.react';
 import { navigateToSidebar } from './sidebar-navigation';
 
@@ -19,7 +19,6 @@
   +verticalBounds: VerticalBounds,
 }>;
 
-const confirmReport = () => displayActionResultModal('reported to admin');
 const spec = {
   entries: [
     {
@@ -35,7 +34,7 @@
     {
       id: 'report',
       text: 'Report',
-      onPress: confirmReport,
+      onPress: onPressReport,
     },
   ],
 };
diff --git a/native/chat/text-message-tooltip-modal.react.js b/native/chat/text-message-tooltip-modal.react.js
--- a/native/chat/text-message-tooltip-modal.react.js
+++ b/native/chat/text-message-tooltip-modal.react.js
@@ -17,6 +17,7 @@
   type BaseTooltipProps,
 } from '../navigation/tooltip.react';
 import type { ChatTextMessageInfoItemWithHeight } from '../types/chat-types';
+import { onPressReport } from './message-report-utils';
 import { navigateToSidebar } from './sidebar-navigation';
 import TextMessageTooltipButton from './text-message-tooltip-button.react';
 
@@ -25,7 +26,6 @@
 }>;
 
 const confirmCopy = () => displayActionResultModal('copied!');
-const confirmReport = () => displayActionResultModal('reported to admin');
 
 function onPressCopy(route: TooltipRoute<'TextMessageTooltipModal'>) {
   Clipboard.setString(route.params.item.messageInfo.text);
@@ -52,7 +52,7 @@
     {
       id: 'report',
       text: 'Report',
-      onPress: confirmReport,
+      onPress: onPressReport,
     },
     {
       id: 'create_sidebar',