diff --git a/lib/handlers/db-ops-handler.react.js b/lib/handlers/db-ops-handler.react.js
--- a/lib/handlers/db-ops-handler.react.js
+++ b/lib/handlers/db-ops-handler.react.js
@@ -31,7 +31,7 @@
     }
     prevQueueFront.current = queueFront;
 
-    const { ops, messageSourceMetadata, dmOpID } = queueFront;
+    const { ops, dispatchMetadata } = queueFront;
     void (async () => {
       if (ops) {
         await processDBStoreOperations(ops);
@@ -39,16 +39,19 @@
           const messageIDs = ops.outboundP2PMessages.map(
             message => message.messageID,
           );
-          processOutboundMessages(messageIDs, dmOpID);
+          processOutboundMessages(messageIDs, dispatchMetadata?.dmOpID);
         }
       }
       dispatch({
         type: opsProcessingFinishedActionType,
       });
-      if (messageSourceMetadata) {
+      if (dispatchMetadata) {
         try {
-          const { messageID, senderDeviceID } = messageSourceMetadata;
           const deviceID = await getContentSigningKey();
+          const { messageID, senderDeviceID } = dispatchMetadata;
+          if (!messageID || !senderDeviceID) {
+            return;
+          }
           const message: MessageProcessed = {
             type: peerToPeerMessageTypes.MESSAGE_PROCESSED,
             messageID,
diff --git a/lib/hooks/ops-hooks.js b/lib/hooks/ops-hooks.js
--- a/lib/hooks/ops-hooks.js
+++ b/lib/hooks/ops-hooks.js
@@ -2,19 +2,18 @@
 
 import * as React from 'react';
 
-import type { MessageSourceMetadata } from '../types/db-ops-types.js';
-import type { SuperAction } from '../types/redux-types.js';
+import type { DispatchMetadata, SuperAction } from '../types/redux-types.js';
 import { useDispatch } from '../utils/redux-utils.js';
 
-function useDispatchWithMessageSource(): (
+function useDispatchWithMetadata(): (
   action: SuperAction,
-  messageSourceMetadata: ?MessageSourceMetadata,
+  dispatchMetadata: ?DispatchMetadata,
 ) => mixed {
   const dispatch = useDispatch();
   return React.useCallback(
-    (action: SuperAction, messageSourceMetadata: ?MessageSourceMetadata) => {
-      if (messageSourceMetadata) {
-        dispatch({ ...action, messageSourceMetadata });
+    (action: SuperAction, dispatchMetadata: ?DispatchMetadata) => {
+      if (dispatchMetadata) {
+        dispatch({ ...action, dispatchMetadata });
       } else {
         dispatch(action);
       }
@@ -23,4 +22,4 @@
   );
 }
 
-export { useDispatchWithMessageSource };
+export { useDispatchWithMetadata };
diff --git a/lib/reducers/db-ops-reducer.js b/lib/reducers/db-ops-reducer.js
--- a/lib/reducers/db-ops-reducer.js
+++ b/lib/reducers/db-ops-reducer.js
@@ -4,13 +4,9 @@
 import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js';
 import type { MessageSearchStoreOperation } from '../message-search-types.js';
 import type { MessageStoreOperation } from '../ops/message-store-ops.js';
-import type {
-  MessageSourceMetadata,
-  DBOpsStore,
-} from '../types/db-ops-types.js';
-import { scheduleP2PMessagesActionType } from '../types/dm-ops.js';
+import type { DBOpsStore } from '../types/db-ops-types.js';
 import { messageTypes } from '../types/message-types-enum.js';
-import type { BaseAction } from '../types/redux-types.js';
+import type { BaseAction, DispatchMetadata } from '../types/redux-types.js';
 import type { StoreOperations } from '../types/store-ops-types.js';
 import { values } from '../utils/objects.js';
 
@@ -21,17 +17,6 @@
       ...store,
       queuedOps: rest,
     };
-  } else if (action.type === scheduleP2PMessagesActionType) {
-    const newEntry = {
-      ops: {
-        outboundP2PMessages: action.payload.messages,
-      },
-      dmOpID: action.payload.dmOpID,
-    };
-    return {
-      ...store,
-      queuedOps: [...store.queuedOps, newEntry],
-    };
   }
 
   return store;
@@ -82,7 +67,7 @@
 
 function queueDBOps(
   store: DBOpsStore,
-  messageSourceMetadata: ?MessageSourceMetadata,
+  dispatchMetadata: ?DispatchMetadata,
   inputOps: StoreOperations,
 ): DBOpsStore {
   const areNewOpsPresent = values(inputOps).some(
@@ -100,18 +85,18 @@
     messageSearchStoreOperations,
   };
 
-  if (messageSourceMetadata && areNewOpsPresent) {
+  if (dispatchMetadata && areNewOpsPresent) {
     newEntry = {
-      messageSourceMetadata,
+      dispatchMetadata,
       ops,
     };
   } else if (areNewOpsPresent) {
     newEntry = {
       ops,
     };
-  } else if (messageSourceMetadata) {
+  } else if (dispatchMetadata) {
     newEntry = {
-      messageSourceMetadata,
+      dispatchMetadata,
     };
   }
 
diff --git a/lib/reducers/db-ops-reducer.test.js b/lib/reducers/db-ops-reducer.test.js
--- a/lib/reducers/db-ops-reducer.test.js
+++ b/lib/reducers/db-ops-reducer.test.js
@@ -23,12 +23,12 @@
     queuedOps: [
       {
         ops: emptyOps,
-        messageSourceMetadata: { messageID: '5', senderDeviceID: '' },
+        dispatchMetadata: { messageID: '5', senderDeviceID: '' },
       },
       { ops: emptyOps },
       {
         ops: null,
-        messageSourceMetadata: { messageID: '7', senderDeviceID: '' },
+        dispatchMetadata: { messageID: '7', senderDeviceID: '' },
       },
     ],
   };
@@ -38,6 +38,6 @@
       type: opsProcessingFinishedActionType,
     });
     expect(newState.queuedOps.length).toEqual(2);
-    expect(newState.queuedOps[1].messageSourceMetadata?.messageID).toEqual('7');
+    expect(newState.queuedOps[1].dispatchMetadata?.messageID).toEqual('7');
   });
 });
diff --git a/lib/shared/dm-ops/dm-op-utils.js b/lib/shared/dm-ops/dm-op-utils.js
--- a/lib/shared/dm-ops/dm-op-utils.js
+++ b/lib/shared/dm-ops/dm-op-utils.js
@@ -2,8 +2,8 @@
 
 import uuid from 'uuid';
 
-import type { MessageSourceMetadata } from '../../types/db-ops-types.js';
 import type { DMOperation } from '../../types/dm-ops.js';
+import type { InboundActionMetadata } from '../../types/redux-types.js';
 import {
   outboundP2PMessageStatuses,
   type OutboundP2PMessage,
@@ -66,7 +66,7 @@
 export type InboundDMOperationSpecification = {
   +type: 'InboundDMOperationSpecification',
   +op: DMOperation,
-  +metadata: ?MessageSourceMetadata,
+  +metadata: ?InboundActionMetadata,
 };
 
 export type DMOperationSpecification =
diff --git a/lib/shared/dm-ops/process-dm-ops.js b/lib/shared/dm-ops/process-dm-ops.js
--- a/lib/shared/dm-ops/process-dm-ops.js
+++ b/lib/shared/dm-ops/process-dm-ops.js
@@ -15,7 +15,7 @@
 } from './dm-op-utils.js';
 import { useLoggedInUserInfo } from '../../hooks/account-hooks.js';
 import { useGetLatestMessageEdit } from '../../hooks/latest-message-edit.js';
-import { useDispatchWithMessageSource } from '../../hooks/ops-hooks.js';
+import { useDispatchWithMetadata } from '../../hooks/ops-hooks.js';
 import { mergeUpdatesWithMessageInfos } from '../../reducers/message-reducer.js';
 import { getAllPeerUserIDAndDeviceIDs } from '../../selectors/user-selectors.js';
 import {
@@ -45,7 +45,7 @@
     [fetchMessage, threadInfos],
   );
 
-  const dispatchWithMessageSource = useDispatchWithMessageSource();
+  const dispatchWithMetadata = useDispatchWithMetadata();
   const loggedInUserInfo = useLoggedInUserInfo();
   const viewerID = loggedInUserInfo?.id;
   const allPeerUserIDAndDeviceIDs = useSelector(getAllPeerUserIDAndDeviceIDs);
@@ -77,7 +77,7 @@
       );
       if (!processingCheckResult.isProcessingPossible) {
         if (processingCheckResult.reason.type === 'missing_thread') {
-          dispatchWithMessageSource(
+          dispatchWithMetadata(
             {
               type: queueDMOpsActionType,
               payload: {
@@ -161,7 +161,7 @@
         });
       }
 
-      dispatchWithMessageSource(
+      dispatchWithMetadata(
         {
           type: processDMOpsActionType,
           payload: {
@@ -176,7 +176,7 @@
     [
       viewerID,
       utilities,
-      dispatchWithMessageSource,
+      dispatchWithMetadata,
       allPeerUserIDAndDeviceIDs,
       currentUserInfo,
       threadInfos,
diff --git a/lib/types/db-ops-types.js b/lib/types/db-ops-types.js
--- a/lib/types/db-ops-types.js
+++ b/lib/types/db-ops-types.js
@@ -1,20 +1,15 @@
 // @flow
 
+import { type DispatchMetadata } from './redux-types.js';
 import type { StoreOperations } from './store-ops-types.js';
 
-export type MessageSourceMetadata = {
-  +messageID: string,
-  +senderDeviceID: string,
-};
-
 export type DBOpsEntry =
   | {
-      +messageSourceMetadata: MessageSourceMetadata,
+      +dispatchMetadata: DispatchMetadata,
       +ops?: ?StoreOperations,
     }
   | {
       +ops: StoreOperations,
-      +dmOpID?: string,
     };
 
 export type DBOpsStore = {
diff --git a/lib/types/dm-ops.js b/lib/types/dm-ops.js
--- a/lib/types/dm-ops.js
+++ b/lib/types/dm-ops.js
@@ -366,12 +366,6 @@
   +pruneMaxTimestamp: number,
 };
 
-export const scheduleP2PMessagesActionType = 'SCHEDULE_P2P_MESSAGES';
-export type ScheduleP2PMessagesPayload = {
-  +dmOpID: string,
-  +messages: $ReadOnlyArray<OutboundP2PMessage>,
-};
-
 export const clearQueuedThreadDMOpsActionType = 'CLEAR_QUEUED_THREAD_DM_OPS';
 export type ClearQueuedThreadDMOpsPayload = {
   +threadID: string,
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
@@ -36,13 +36,12 @@
   CreateOrUpdateFarcasterChannelTagResponse,
   DeleteFarcasterChannelTagPayload,
 } from './community-types.js';
-import type { MessageSourceMetadata, DBOpsStore } from './db-ops-types.js';
+import type { DBOpsStore } from './db-ops-types.js';
 import type {
   GetVersionActionPayload,
   LastCommunicatedPlatformDetails,
 } from './device-types.js';
 import type {
-  ScheduleP2PMessagesPayload,
   ProcessDMOpsPayload,
   QueuedDMOperations,
   QueueDMOpsPayload,
@@ -236,7 +235,7 @@
 };
 
 export type BaseAction = $ReadOnly<{
-  +messageSourceMetadata?: MessageSourceMetadata,
+  +dispatchMetadata?: DispatchMetadata,
   ...
     | {
         +type: '@@redux/INIT',
@@ -1579,7 +1578,6 @@
         +type: 'PROCESS_DM_OPS',
         +payload: ProcessDMOpsPayload,
       }
-    | { +type: 'SCHEDULE_P2P_MESSAGES', +payload: ScheduleP2PMessagesPayload }
     | {
         +type: 'INVALIDATE_TUNNELBROKER_DEVICE_TOKEN',
         +payload: {
@@ -1596,13 +1594,25 @@
 
 export type ActionPayload = ?(Object | Array<*> | $ReadOnlyArray<*> | string);
 export type DispatchSource = 'tunnelbroker' | 'tab-sync';
+// Data added when dispatching action as a result of message received
+// from other peer. It is used to send processing confirmation.
+export type InboundActionMetadata = {
+  +messageID: string,
+  +senderDeviceID: string,
+};
+// Data added when dispatching action triggered locally, used to resolve
+// promise associated with sending messages and track failed messages.
+export type OutboundActionMetadata = {
+  +dmOpID: string,
+};
+export type DispatchMetadata = InboundActionMetadata | OutboundActionMetadata;
 export type SuperAction = {
   +type: string,
   +payload?: ActionPayload,
   +loadingInfo?: LoadingInfo,
   +error?: boolean,
   +dispatchSource?: DispatchSource,
-  +messageSourceMetadata?: MessageSourceMetadata,
+  +dispatchMetadata?: DispatchMetadata,
 };
 type ThunkedAction = (dispatch: Dispatch) => void;
 export type PromisedAction = (dispatch: Dispatch) => Promise<void>;
diff --git a/lib/types/request-types.js b/lib/types/request-types.js
--- a/lib/types/request-types.js
+++ b/lib/types/request-types.js
@@ -9,7 +9,6 @@
 } from './activity-types.js';
 import type { SignedIdentityKeysBlob } from './crypto-types.js';
 import { signedIdentityKeysBlobValidator } from './crypto-types.js';
-import type { MessageSourceMetadata } from './db-ops-types.js';
 import type { Platform, PlatformDetails } from './device-types.js';
 import {
   type RawEntryInfo,
@@ -17,6 +16,7 @@
   rawEntryInfoValidator,
 } from './entry-types.js';
 import type { RawThreadInfo } from './minimally-encoded-thread-permissions-types';
+import type { DispatchMetadata } from './redux-types.js';
 import {
   type ThreadInconsistencyReportShape,
   type EntryInconsistencyReportShape,
@@ -320,7 +320,7 @@
   +keyserverID: string,
 };
 export type ProcessServerRequestAction = {
-  +messageSourceMetadata?: MessageSourceMetadata,
+  +dispatchMetadata?: DispatchMetadata,
   +type: 'PROCESS_SERVER_REQUESTS',
   +payload: ProcessServerRequestsPayload,
 };
diff --git a/native/redux/action-types.js b/native/redux/action-types.js
--- a/native/redux/action-types.js
+++ b/native/redux/action-types.js
@@ -3,8 +3,7 @@
 import type { Orientations } from 'react-native-orientation-locker';
 
 import { saveMessagesActionType } from 'lib/actions/message-actions.js';
-import type { MessageSourceMetadata } from 'lib/types/db-ops-types.js';
-import type { BaseAction } from 'lib/types/redux-types.js';
+import type { BaseAction, DispatchMetadata } from 'lib/types/redux-types.js';
 
 import type { DimensionsInfo } from './dimensions-updater.react.js';
 import type { AppState } from './state-types.js';
@@ -28,7 +27,7 @@
 export type Action = $ReadOnly<
   | BaseAction
   | {
-      +messageSourceMetadata?: MessageSourceMetadata,
+      +dispatchMetadata?: DispatchMetadata,
       ...
         | {
             +type: 'SET_REDUX_STATE',
diff --git a/native/redux/redux-setup.js b/native/redux/redux-setup.js
--- a/native/redux/redux-setup.js
+++ b/native/redux/redux-setup.js
@@ -314,7 +314,7 @@
   };
   state = {
     ...state,
-    dbOpsStore: queueDBOps(state.dbOpsStore, action.messageSourceMetadata, ops),
+    dbOpsStore: queueDBOps(state.dbOpsStore, action.dispatchMetadata, ops),
   };
 
   return state;
diff --git a/web/redux/redux-setup.js b/web/redux/redux-setup.js
--- a/web/redux/redux-setup.js
+++ b/web/redux/redux-setup.js
@@ -37,10 +37,7 @@
 import type { AlertStore } from 'lib/types/alert-types.js';
 import type { AuxUserStore } from 'lib/types/aux-user-types.js';
 import type { CommunityStore } from 'lib/types/community-types.js';
-import type {
-  MessageSourceMetadata,
-  DBOpsStore,
-} from 'lib/types/db-ops-types.js';
+import type { DBOpsStore } from 'lib/types/db-ops-types.js';
 import type { QueuedDMOperations } from 'lib/types/dm-ops.js';
 import type { DraftStore } from 'lib/types/draft-types.js';
 import type { EnabledApps } from 'lib/types/enabled-apps.js';
@@ -54,7 +51,7 @@
 import type { MessageStore } from 'lib/types/message-types.js';
 import type { WebNavInfo } from 'lib/types/nav-types.js';
 import type { UserPolicies } from 'lib/types/policy-types.js';
-import type { BaseAction } from 'lib/types/redux-types.js';
+import type { BaseAction, DispatchMetadata } from 'lib/types/redux-types.js';
 import type { ReportStore } from 'lib/types/report-types.js';
 import type { StoreOperations } from 'lib/types/store-ops-types.js';
 import type { SyncedMetadataStore } from 'lib/types/synced-metadata-types.js';
@@ -140,7 +137,7 @@
 export type Action = $ReadOnly<
   | BaseAction
   | {
-      +messageSourceMetadata?: MessageSourceMetadata,
+      +dispatchMetadata?: DispatchMetadata,
       ...
         | { +type: 'UPDATE_NAV_INFO', +payload: Partial<WebNavInfo> }
         | {
@@ -546,7 +543,7 @@
     ...state,
     dbOpsStore: queueDBOps(
       state.dbOpsStore,
-      action.messageSourceMetadata,
+      action.dispatchMetadata,
       storeOperations,
     ),
   };