diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts
index 99e360c6ffb7..c8b6e06fd46a 100644
--- a/src/libs/IOUUtils.ts
+++ b/src/libs/IOUUtils.ts
@@ -11,7 +11,7 @@ import {getCurrencyUnit} from './CurrencyUtils';
 import Navigation from './Navigation/Navigation';
 import {isPaidGroupPolicy} from './PolicyUtils';
 import {getOriginalMessage, isMoneyRequestAction} from './ReportActionsUtils';
-import {isSelfDM} from './ReportUtils';
+import {generateReportID, getChatByParticipants, isSelfDM} from './ReportUtils';
 import {endSpan, getSpan, startSpan} from './telemetry/activeSpans';
 import {getTagArrayFromName} from './TransactionUtils';
 
@@ -449,6 +449,16 @@ function getInitialPerDiemTargetReport(
     return {targetReport, targetIouType, transactionReportID};
 }
 
+/**
+ * Resolves the chat report ID for navigation, generating an optimistic ID if no existing chat is found.
+ */
+function resolveOptimisticChatReportID(participantAccountIDs: number[], existingReport?: OnyxInputOrEntry<Report>) {
+    const existingChat = existingReport?.reportID ? existingReport : getChatByParticipants(participantAccountIDs);
+    const optimisticChatReportID = existingChat?.reportID ? undefined : generateReportID();
+    const chatReportID = existingChat?.reportID ?? optimisticChatReportID;
+    return {optimisticChatReportID, chatReportID};
+}
+
 export {
     calculateAmount,
     calculateSplitAmountFromPercentage,
@@ -466,4 +476,5 @@ export {
     navigateToConfirmationPage,
     calculateDefaultReimbursable,
     getInitialPerDiemTargetReport,
+    resolveOptimisticChatReportID,
 };
diff --git a/src/libs/Navigation/helpers/dismissModalAndOpenReportInInboxTab.ts b/src/libs/Navigation/helpers/dismissModalAndOpenReportInInboxTab.ts
new file mode 100644
index 000000000000..5159b7cd865f
--- /dev/null
+++ b/src/libs/Navigation/helpers/dismissModalAndOpenReportInInboxTab.ts
@@ -0,0 +1,87 @@
+import {InteractionManager} from 'react-native';
+import getIsNarrowLayout from '@libs/getIsNarrowLayout';
+import Navigation, {navigationRef} from '@libs/Navigation/Navigation';
+import {getSpan} from '@libs/telemetry/activeSpans';
+import {endSubmitFollowUpActionSpan, setPendingSubmitFollowUpAction} from '@libs/telemetry/submitFollowUpAction';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
+import isReportOpenInRHP from './isReportOpenInRHP';
+import isReportOpenInSuperWideRHP from './isReportOpenInSuperWideRHP';
+import isSearchTopmostFullScreenRoute from './isSearchTopmostFullScreenRoute';
+import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue';
+
+/**
+ * After finishing the action in RHP from the Inbox tab, besides dismissing the modal, we should open the report.
+ * If the action is done from the report RHP, then we just want to dismiss the money request flow screens.
+ */
+function dismissModalAndOpenReportInInboxTab(reportID: string | undefined, isInvoice: boolean | undefined, hasMultipleTransactions: boolean) {
+    const rootState = navigationRef.getRootState();
+    const hasSubmitToDestinationVisibleSpan = !!getSpan(CONST.TELEMETRY.SPAN_SUBMIT_TO_DESTINATION_VISIBLE);
+
+    if (!isInvoice && isReportOpenInRHP(rootState)) {
+        const rhpKey = rootState.routes.at(-1)?.state?.key;
+        if (rhpKey) {
+            const isSuperWideRHP = isReportOpenInSuperWideRHP(rootState);
+
+            // submit_follow_up_action: only set when the span was started.
+            if (hasSubmitToDestinationVisibleSpan) {
+                if (isSuperWideRHP) {
+                    setPendingSubmitFollowUpAction(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY, reportID);
+                } else if (hasMultipleTransactions && reportID) {
+                    setPendingSubmitFollowUpAction(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_AND_OPEN_REPORT, reportID);
+                } else {
+                    setPendingSubmitFollowUpAction(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY, reportID);
+                }
+            }
+            // When a report is opened in the super wide RHP, we need to dismiss to the first RHP to show the same report with new expense.
+            if (isSuperWideRHP) {
+                Navigation.dismissToPreviousRHP();
+                return;
+            }
+            // When a report with one expense is opened in the wide RHP and the user adds another expense, RHP should be dismissed and ROUTES.SEARCH_MONEY_REQUEST_REPORT should be displayed.
+            if (hasMultipleTransactions && reportID) {
+                // On small screens, dismiss all modals and then navigate to the right report.
+                // On large screens, dismiss to the previous RHP first, then replace the current route with the new report.
+                const isNarrowLayout = getIsNarrowLayout();
+                if (isNarrowLayout) {
+                    Navigation.dismissModal();
+                } else {
+                    Navigation.dismissToPreviousRHP();
+                }
+                setNavigationActionToMicrotaskQueue(() => {
+                    Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID}), {forceReplace: !isNarrowLayout});
+                });
+                return;
+            }
+            Navigation.pop(rhpKey);
+            return;
+        }
+    }
+    if (isSearchTopmostFullScreenRoute() || !reportID) {
+        if (hasSubmitToDestinationVisibleSpan) {
+            setPendingSubmitFollowUpAction(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY);
+        }
+        Navigation.dismissModal();
+        if (hasSubmitToDestinationVisibleSpan) {
+            // eslint-disable-next-line @typescript-eslint/no-deprecated -- we need to wait for the modal to be dismissed before marking the span
+            InteractionManager.runAfterInteractions(() => {
+                endSubmitFollowUpActionSpan(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY);
+            });
+        }
+        return;
+    }
+    if (hasSubmitToDestinationVisibleSpan) {
+        Navigation.dismissModalWithReport({reportID}, undefined, {
+            onBeforeNavigate: (willOpenReport) => {
+                setPendingSubmitFollowUpAction(
+                    willOpenReport ? CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_AND_OPEN_REPORT : CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY,
+                    reportID,
+                );
+            },
+        });
+    } else {
+        Navigation.dismissModalWithReport({reportID});
+    }
+}
+
+export default dismissModalAndOpenReportInInboxTab;
diff --git a/src/libs/Navigation/helpers/navigateAfterExpenseCreate.ts b/src/libs/Navigation/helpers/navigateAfterExpenseCreate.ts
new file mode 100644
index 000000000000..8d53a052f9ec
--- /dev/null
+++ b/src/libs/Navigation/helpers/navigateAfterExpenseCreate.ts
@@ -0,0 +1,81 @@
+import getIsNarrowLayout from '@libs/getIsNarrowLayout';
+import Log from '@libs/Log';
+import Navigation, {navigationRef} from '@libs/Navigation/Navigation';
+import {buildCannedSearchQuery, getCurrentSearchQueryJSON} from '@libs/SearchQueryUtils';
+import {setPendingSubmitFollowUpAction} from '@libs/telemetry/submitFollowUpAction';
+import CONST from '@src/CONST';
+import NAVIGATORS from '@src/NAVIGATORS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
+import dismissModalAndOpenReportInInboxTab from './dismissModalAndOpenReportInInboxTab';
+import isReportTopmostSplitNavigator from './isReportTopmostSplitNavigator';
+import isSearchTopmostFullScreenRoute from './isSearchTopmostFullScreenRoute';
+
+type NavigateAfterExpenseCreateParams = {
+    activeReportID?: string;
+    transactionID?: string;
+    isFromGlobalCreate?: boolean;
+    isInvoice?: boolean;
+    hasMultipleTransactions: boolean;
+};
+
+/**
+ * Helper to navigate after an expense is created in order to standardize the post‑creation experience
+ * when creating an expense from the global create button.
+ * If the expense is created from the global create button then:
+ * - If it is created on the inbox tab, it will open the chat report containing that expense.
+ * - If it is created elsewhere, it will navigate to Reports > Expense and highlight the newly created expense.
+ */
+function navigateAfterExpenseCreate({activeReportID, transactionID, isFromGlobalCreate, isInvoice, hasMultipleTransactions}: NavigateAfterExpenseCreateParams) {
+    const isUserOnInbox = isReportTopmostSplitNavigator();
+
+    // If the expense is not created from global create or is currently on the inbox tab,
+    // we just need to dismiss the money request flow screens
+    // and open the report chat containing the IOU report
+    if (!isFromGlobalCreate || isUserOnInbox || !transactionID) {
+        dismissModalAndOpenReportInInboxTab(activeReportID, isInvoice, hasMultipleTransactions);
+        return;
+    }
+
+    const type = isInvoice ? CONST.SEARCH.DATA_TYPES.INVOICE : CONST.SEARCH.DATA_TYPES.EXPENSE;
+
+    // When already on Search ROOT with the same type (expense vs invoice), we navigate to the same screen (no-op or refresh); record as dismiss_modal_only.
+    // When on another Search sub-tab (e.g. Chats), or on Search with a different type (e.g. on Invoice, submitting expense), record as navigate_to_search.
+    const rootState = navigationRef.getRootState();
+    const searchNavigatorRoute = rootState?.routes?.findLast((route) => route.name === NAVIGATORS.SEARCH_FULLSCREEN_NAVIGATOR);
+    const lastSearchRoute = searchNavigatorRoute?.state?.routes?.at(-1);
+    const alreadyOnSearchRoot = isSearchTopmostFullScreenRoute() && lastSearchRoute?.name === SCREENS.SEARCH.ROOT;
+    const currentSearchQueryJSON = alreadyOnSearchRoot ? getCurrentSearchQueryJSON() : undefined;
+    const isSameSearchType = currentSearchQueryJSON?.type === type;
+    setPendingSubmitFollowUpAction(
+        alreadyOnSearchRoot && isSameSearchType ? CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY : CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.NAVIGATE_TO_SEARCH,
+    );
+
+    const queryString = buildCannedSearchQuery({type});
+    const navigateToSearch = () => {
+        // On the fast path, onConfirm already cleared the flag and dismissed the modal,
+        // so this branch is only reached on the slow path (user submitted before the
+        // 300ms pre-insert timer fired).
+        if (getIsNarrowLayout() && Navigation.getIsFullscreenPreInsertedUnderRHP()) {
+            Navigation.clearFullscreenPreInsertedFlag();
+            Navigation.dismissModal();
+        } else if (getIsNarrowLayout()) {
+            const isRHPStillOnTop = navigationRef.getRootState()?.routes?.at(-1)?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR;
+            if (!alreadyOnSearchRoot || !isSameSearchType || isRHPStillOnTop) {
+                Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query: queryString}), {forceReplace: true});
+            } else {
+                Log.info('[IOU] navigateToSearch: already on matching Search root with RHP dismissed — no-op');
+            }
+        } else {
+            Navigation.revealRouteBeforeDismissingModal(ROUTES.SEARCH_ROOT.getRoute({query: queryString}));
+        }
+    };
+
+    if (navigationRef.isReady()) {
+        navigateToSearch();
+    } else {
+        Navigation.isNavigationReady().then(navigateToSearch);
+    }
+}
+
+export default navigateAfterExpenseCreate;
diff --git a/src/libs/actions/IOU/PerDiem.ts b/src/libs/actions/IOU/PerDiem.ts
index 7a6d4d86c264..347884a50751 100644
--- a/src/libs/actions/IOU/PerDiem.ts
+++ b/src/libs/actions/IOU/PerDiem.ts
@@ -58,7 +58,6 @@ import {
     getPolicyTags,
     getReportPreviewAction,
     getUserAccountID,
-    handleNavigateAfterExpenseCreate,
     highlightTransactionOnSearchRouteIfNeeded,
     mergePolicyRecentlyUsedCategories,
     mergePolicyRecentlyUsedCurrencies,
@@ -232,10 +231,10 @@ type PerDiemExpenseInformation = {
     betas: OnyxEntry<OnyxTypes.Beta[]>;
     customUnitPolicyID?: string;
     personalDetails: OnyxEntry<OnyxTypes.PersonalDetailsList>;
-    shouldHandleNavigation?: boolean;
     shouldPlaySound?: boolean;
     optimisticReportPreviewActionID?: string;
     shouldDeferAutoSubmit?: boolean;
+    optimisticChatReportID?: string;
 };
 
 type PerDiemExpenseInformationParams = {
@@ -255,6 +254,7 @@ type PerDiemExpenseInformationParams = {
     betas: OnyxEntry<OnyxTypes.Beta[]>;
     optimisticReportPreviewActionID?: string;
     personalDetails: OnyxEntry<OnyxTypes.PersonalDetailsList>;
+    optimisticChatReportID?: string;
 };
 
 type PerDiemExpenseInformationForSelfDM = {
@@ -303,6 +303,7 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI
         betas,
         optimisticReportPreviewActionID,
         personalDetails,
+        optimisticChatReportID,
     } = perDiemExpenseInformation;
     const {payeeAccountID = getUserAccountID(), payeeEmail = getCurrentUserEmail(), participant} = participantParams;
     const {policy, policyCategories, policyTagList, policyRecentlyUsedCategories, policyRecentlyUsedTags} = policyParams;
@@ -340,6 +341,7 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI
         isNewChatReport = true;
         chatReport = buildOptimisticChatReport({
             participantList: [payerAccountID, payeeAccountID],
+            optimisticReportID: optimisticChatReportID,
             currentUserAccountID: currentUserAccountIDParam,
         });
     }
@@ -890,12 +892,11 @@ function submitPerDiemExpense(submitPerDiemExpenseInformation: PerDiemExpenseInf
         betas,
         customUnitPolicyID,
         personalDetails,
-        shouldHandleNavigation = true,
         shouldPlaySound: shouldPlaySoundParam = true,
         optimisticReportPreviewActionID,
         shouldDeferAutoSubmit,
+        optimisticChatReportID,
     } = submitPerDiemExpenseInformation;
-    const {payeeAccountID} = participantParams;
     const {currency, comment = '', category, tag, created, customUnit, attendees, isFromGlobalCreate} = transactionParams;
 
     if (
@@ -944,6 +945,7 @@ function submitPerDiemExpense(submitPerDiemExpenseInformation: PerDiemExpenseInf
         betas,
         optimisticReportPreviewActionID,
         personalDetails,
+        optimisticChatReportID,
     });
 
     const activeReportID = isMoneyRequestReport && Navigation.getTopmostReportId() === report?.reportID ? report?.reportID : chatReport.reportID;
@@ -988,7 +990,7 @@ function submitPerDiemExpense(submitPerDiemExpenseInformation: PerDiemExpenseInf
         playSound(SOUNDS.DONE);
     }
 
-    const shouldDeferWrite = shouldHandleNavigation && isFromGlobalCreate && !isReportTopmostSplitNavigator();
+    const shouldDeferWrite = isFromGlobalCreate && !isReportTopmostSplitNavigator();
     const apiWrite = () => {
         API.write(WRITE_COMMANDS.CREATE_PER_DIEM_REQUEST, parameters, onyxData);
     };
@@ -1006,10 +1008,8 @@ function submitPerDiemExpense(submitPerDiemExpenseInformation: PerDiemExpenseInf
 
     highlightTransactionOnSearchRouteIfNeeded(isFromGlobalCreate, transaction.transactionID, CONST.SEARCH.DATA_TYPES.EXPENSE);
 
-    handleNavigateAfterExpenseCreate({activeReportID, transactionID: transaction.transactionID, isFromGlobalCreate, shouldHandleNavigation});
-
     if (activeReportID) {
-        notifyNewAction(activeReportID, undefined, payeeAccountID === currentUserAccountIDParam);
+        notifyNewAction(activeReportID, undefined, participantParams.payeeAccountID === currentUserAccountIDParam);
     }
 
     return {iouReport};
diff --git a/src/libs/actions/IOU/SendMoney.ts b/src/libs/actions/IOU/SendMoney.ts
index 590d3cc088fd..c3c6c55bf3f1 100644
--- a/src/libs/actions/IOU/SendMoney.ts
+++ b/src/libs/actions/IOU/SendMoney.ts
@@ -28,7 +28,6 @@ import type * as OnyxTypes from '@src/types/onyx';
 import type {Participant} from '@src/types/onyx/IOU';
 import type {Receipt} from '@src/types/onyx/Transaction';
 import {isEmptyObject} from '@src/types/utils/EmptyObject';
-import {dismissModalAndOpenReportInInboxTab} from '.';
 
 type SendMoneyParamsData = {
     params: SendMoneyParams;
@@ -72,6 +71,7 @@ function getSendMoneyParams({
     created,
     merchant,
     receipt,
+    optimisticChatReportID,
     currentUserAccountID,
 }: {
     report: OnyxEntry<OnyxTypes.Report>;
@@ -85,6 +85,7 @@ function getSendMoneyParams({
     created?: string;
     merchant?: string;
     receipt?: Receipt;
+    optimisticChatReportID?: string;
     currentUserAccountID: number;
 }): SendMoneyParamsData {
     const recipientEmail = addSMSDomainIfPhoneNumber(recipient.login ?? '');
@@ -106,6 +107,7 @@ function getSendMoneyParams({
     if (!chatReport) {
         chatReport = buildOptimisticChatReport({
             participantList: [recipientAccountID, managerID],
+            optimisticReportID: optimisticChatReportID,
             currentUserAccountID,
         });
         isNewChat = true;
@@ -478,22 +480,21 @@ function getSendMoneyParams({
     };
 }
 
-/**
- * @param currentUserAccountID - Account ID of the person sending the money
- * @param recipient - The user receiving the money
- */
-function sendMoneyElsewhere(
-    report: OnyxEntry<OnyxTypes.Report>,
-    quickAction: OnyxEntry<OnyxTypes.QuickAction>,
-    amount: number,
-    currency: string,
-    comment: string,
-    currentUserAccountID: number,
-    recipient: Participant,
-    created?: string,
-    merchant?: string,
-    receipt?: Receipt,
-) {
+type SendMoneyActionParams = {
+    report: OnyxEntry<OnyxTypes.Report>;
+    quickAction: OnyxEntry<OnyxTypes.QuickAction>;
+    amount: number;
+    currency: string;
+    comment: string;
+    currentUserAccountID: number;
+    recipient: Participant | OptionData;
+    created?: string;
+    merchant?: string;
+    receipt?: Receipt;
+    optimisticChatReportID?: string;
+};
+
+function sendMoneyElsewhere({report, quickAction, amount, currency, comment, currentUserAccountID, recipient, created, merchant, receipt, optimisticChatReportID}: SendMoneyActionParams) {
     const {params, optimisticData, successData, failureData} = getSendMoneyParams({
         report,
         quickAction,
@@ -506,6 +507,7 @@ function sendMoneyElsewhere(
         created,
         merchant,
         receipt,
+        optimisticChatReportID,
         currentUserAccountID,
     });
     startSpan(CONST.TELEMETRY.SPAN_SUBMIT_TO_DESTINATION_VISIBLE, {
@@ -522,26 +524,10 @@ function sendMoneyElsewhere(
     playSound(SOUNDS.DONE);
     API.write(WRITE_COMMANDS.SEND_MONEY_ELSEWHERE, params, {optimisticData, successData, failureData});
 
-    dismissModalAndOpenReportInInboxTab(params.chatReportID);
     notifyNewAction(params.chatReportID, undefined, true);
 }
 
-/**
- * @param currentUserAccountID - Account ID of the person sending the money
- * @param recipient - The user receiving the money
- */
-function sendMoneyWithWallet(
-    report: OnyxEntry<OnyxTypes.Report>,
-    quickAction: OnyxEntry<OnyxTypes.QuickAction>,
-    amount: number,
-    currency: string,
-    comment: string,
-    currentUserAccountID: number,
-    recipient: Participant | OptionData,
-    created?: string,
-    merchant?: string,
-    receipt?: Receipt,
-) {
+function sendMoneyWithWallet({report, quickAction, amount, currency, comment, currentUserAccountID, recipient, created, merchant, receipt, optimisticChatReportID}: SendMoneyActionParams) {
     const {params, optimisticData, successData, failureData} = getSendMoneyParams({
         report,
         quickAction,
@@ -554,6 +540,7 @@ function sendMoneyWithWallet(
         created,
         merchant,
         receipt,
+        optimisticChatReportID,
         currentUserAccountID,
     });
     startSpan(CONST.TELEMETRY.SPAN_SUBMIT_TO_DESTINATION_VISIBLE, {
@@ -570,7 +557,6 @@ function sendMoneyWithWallet(
     playSound(SOUNDS.DONE);
     API.write(WRITE_COMMANDS.SEND_MONEY_WITH_WALLET, params, {optimisticData, successData, failureData});
 
-    dismissModalAndOpenReportInInboxTab(params.chatReportID);
     notifyNewAction(params.chatReportID, undefined, true);
 }
 
diff --git a/src/pages/iou/request/step/IOURequestStepAmount.tsx b/src/pages/iou/request/step/IOURequestStepAmount.tsx
index 98734084d42c..a31f6ceb5113 100644
--- a/src/pages/iou/request/step/IOURequestStepAmount.tsx
+++ b/src/pages/iou/request/step/IOURequestStepAmount.tsx
@@ -17,13 +17,22 @@ import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses';
 import usePrivateIsArchivedMap from '@hooks/usePrivateIsArchivedMap';
 import useReportAttributes from '@hooks/useReportAttributes';
 import useReportIsArchived from '@hooks/useReportIsArchived';
+import useReportTransactions from '@hooks/useReportTransactions';
 import useSelfDMReport from '@hooks/useSelfDMReport';
 import useShowNotFoundPageInIOUStep from '@hooks/useShowNotFoundPageInIOUStep';
 import {requestMoney} from '@libs/actions/IOU/TrackExpense';
 import {setTransactionReport} from '@libs/actions/Transaction';
 import {convertToBackendAmount} from '@libs/CurrencyUtils';
 import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
-import {calculateDefaultReimbursable, getExistingTransactionID, isMovingTransactionFromTrackExpense, navigateToConfirmationPage, navigateToParticipantPage} from '@libs/IOUUtils';
+import {
+    calculateDefaultReimbursable,
+    getExistingTransactionID,
+    isMovingTransactionFromTrackExpense,
+    navigateToConfirmationPage,
+    navigateToParticipantPage,
+    resolveOptimisticChatReportID,
+} from '@libs/IOUUtils';
+import dismissModalAndOpenReportInInboxTabHelper from '@libs/Navigation/helpers/dismissModalAndOpenReportInInboxTab';
 import Navigation from '@libs/Navigation/Navigation';
 import {getParticipantsOption, getReportOption} from '@libs/OptionsListUtils';
 import {getPolicyExpenseChat, getReportOrDraftReport, getTransactionDetails, isMoneyRequestReport, isPolicyExpenseChat, isSelfDM, shouldEnableNegative} from '@libs/ReportUtils';
@@ -85,6 +94,7 @@ function IOURequestStepAmount({
 
     const selfDMReport = useSelfDMReport();
     const isReportArchived = useReportIsArchived(report?.reportID);
+    const reportTransactions = useReportTransactions(report?.reportID);
     const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
     const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`);
     const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(report?.parentReportID)}`);
@@ -239,11 +249,26 @@ function IOURequestStepAmount({
                     transactionReportID: report?.reportID,
                 });
                 if (iouType === CONST.IOU.TYPE.PAY || iouType === CONST.IOU.TYPE.SEND) {
+                    const {optimisticChatReportID, chatReportID} = resolveOptimisticChatReportID(
+                        [participants.at(0)?.accountID ?? CONST.DEFAULT_NUMBER_ID, currentUserAccountIDParam],
+                        report,
+                    );
+                    const sendMoneyParams = {
+                        report,
+                        quickAction,
+                        amount: backendAmount,
+                        currency: selectedCurrency,
+                        comment: '',
+                        currentUserAccountID: currentUserAccountIDParam,
+                        recipient: participants.at(0) ?? {},
+                        optimisticChatReportID,
+                    };
                     if (paymentMethod && paymentMethod === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) {
-                        sendMoneyWithWallet(report, quickAction, backendAmount, selectedCurrency, '', currentUserAccountIDParam, participants.at(0) ?? {});
-                        return;
+                        sendMoneyWithWallet(sendMoneyParams);
+                    } else {
+                        sendMoneyElsewhere(sendMoneyParams);
                     }
-                    sendMoneyElsewhere(report, quickAction, backendAmount, selectedCurrency, '', currentUserAccountIDParam, participants.at(0) ?? {});
+                    dismissModalAndOpenReportInInboxTabHelper(chatReportID, undefined, reportTransactions.length > 0);
                     return;
                 }
                 if (iouType === CONST.IOU.TYPE.SUBMIT || iouType === CONST.IOU.TYPE.REQUEST) {
diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx
index 377dc47496a4..d0b7a3c10d7c 100644
--- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx
+++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx
@@ -31,6 +31,7 @@ import usePermissions from '@hooks/usePermissions';
 import usePolicyForTransaction from '@hooks/usePolicyForTransaction';
 import usePrivateIsArchivedMap from '@hooks/usePrivateIsArchivedMap';
 import useReportAttributes from '@hooks/useReportAttributes';
+import useReportTransactions from '@hooks/useReportTransactions';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
 import {completeTestDriveTask} from '@libs/actions/Task';
@@ -48,12 +49,15 @@ import {
     getExistingTransactionID,
     isMovingTransactionFromTrackExpense as isMovingTransactionFromTrackExpenseIOUUtils,
     navigateToStartMoneyRequestStep,
+    resolveOptimisticChatReportID,
     shouldShowReceiptEmptyState,
     shouldUseTransactionDraft,
 } from '@libs/IOUUtils';
 import Log from '@libs/Log';
+import dismissModalAndOpenReportInInboxTabHelper from '@libs/Navigation/helpers/dismissModalAndOpenReportInInboxTab';
 import isReportTopmostSplitNavigator from '@libs/Navigation/helpers/isReportTopmostSplitNavigator';
 import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute';
+import navigateAfterExpenseCreate from '@libs/Navigation/helpers/navigateAfterExpenseCreate';
 import navigateAfterInteraction from '@libs/Navigation/navigateAfterInteraction';
 import Navigation from '@libs/Navigation/Navigation';
 import {rand64, roundToTwoDecimalPlaces} from '@libs/NumberUtils';
@@ -256,6 +260,7 @@ function IOURequestStepConfirmation({
     const [draftTransactionIDs] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_DRAFT, {selector: validTransactionDraftIDsSelector});
 
     const reportAttributesDerived = useReportAttributes();
+    const reportTransactions = useReportTransactions(report?.reportID);
     const [recentlyUsedDestinations] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_DESTINATIONS}${policyID}`);
     const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
     const transactionViolationsRef = useRef(transactionViolations);
@@ -689,7 +694,20 @@ function IOURequestStepConfirmation({
                     quickAction,
                 });
             } else {
-                submitPerDiemExpenseIOUActions({
+                const isExpenseReport = isMoneyRequestReport(report);
+                let existingChatReport = report;
+                if (isExpenseReport) {
+                    existingChatReport = getReportOrDraftReport(report?.chatReportID);
+                } else if (!report?.reportID && participant.isPolicyExpenseChat && participant.reportID) {
+                    existingChatReport = getReportOrDraftReport(participant.reportID);
+                }
+                const {optimisticChatReportID, chatReportID} = resolveOptimisticChatReportID(
+                    [participant.accountID ?? CONST.DEFAULT_NUMBER_ID, currentUserPersonalDetails.accountID],
+                    existingChatReport,
+                );
+                const activeReportID = isExpenseReport && Navigation.getTopmostReportId() === report?.reportID ? report?.reportID : chatReportID;
+
+                const result = submitPerDiemExpenseIOUActions({
                     report,
                     participantParams: {
                         payeeEmail: currentUserPersonalDetails.login,
@@ -726,7 +744,16 @@ function IOURequestStepConfirmation({
                     quickAction,
                     betas,
                     personalDetails,
+                    optimisticChatReportID,
                 });
+                if (result && activeReportID) {
+                    navigateAfterExpenseCreate({
+                        activeReportID,
+                        transactionID: transaction.transactionID,
+                        isFromGlobalCreate: transaction.isFromFloatingActionButton ?? transaction.isFromGlobalCreate,
+                        hasMultipleTransactions: reportTransactions.length > 0,
+                    });
+                }
             }
         },
         [
@@ -747,6 +774,7 @@ function IOURequestStepConfirmation({
             quickAction,
             betas,
             personalDetails,
+            reportTransactions.length,
         ],
     );
 
@@ -1226,38 +1254,31 @@ function IOURequestStepConfirmation({
                 return;
             }
 
+            const {optimisticChatReportID, chatReportID} = resolveOptimisticChatReportID([participant.accountID ?? CONST.DEFAULT_NUMBER_ID, currentUserPersonalDetails.accountID], report);
+            const sendMoneyParams = {
+                report,
+                quickAction,
+                amount: transaction.amount,
+                currency,
+                comment: trimmedComment,
+                currentUserAccountID: currentUserPersonalDetails.accountID,
+                recipient: participant,
+                created: transaction.created,
+                merchant: transaction.merchant,
+                receipt: receiptFiles[transaction.transactionID],
+                optimisticChatReportID,
+            };
+
             if (paymentMethod === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) {
                 setIsConfirmed(true);
-                sendMoneyElsewhere(
-                    report,
-                    quickAction,
-                    transaction.amount,
-                    currency,
-                    trimmedComment,
-                    currentUserPersonalDetails.accountID,
-                    participant,
-                    transaction.created,
-                    transaction.merchant,
-                    receiptFiles[transaction.transactionID],
-                );
-                return;
-            }
-
-            if (paymentMethod === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) {
+                sendMoneyElsewhere(sendMoneyParams);
+            } else if (paymentMethod === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) {
                 setIsConfirmed(true);
-                sendMoneyWithWallet(
-                    report,
-                    quickAction,
-                    transaction.amount,
-                    currency,
-                    trimmedComment,
-                    currentUserPersonalDetails.accountID,
-                    participant,
-                    transaction.created,
-                    transaction.merchant,
-                    receiptFiles[transaction.transactionID],
-                );
+                sendMoneyWithWallet(sendMoneyParams);
+            } else {
+                return;
             }
+            dismissModalAndOpenReportInInboxTabHelper(chatReportID, undefined, reportTransactions.length > 0);
         },
         [
             transaction?.currency,
@@ -1271,6 +1292,7 @@ function IOURequestStepConfirmation({
             currentUserPersonalDetails.accountID,
             receiptFiles,
             quickAction,
+            reportTransactions.length,
         ],
     );
 
diff --git a/tests/unit/IOUUtilsTest.ts b/tests/unit/IOUUtilsTest.ts
index 7588d2375d72..543aed6ba2fa 100644
--- a/tests/unit/IOUUtilsTest.ts
+++ b/tests/unit/IOUUtilsTest.ts
@@ -824,4 +824,37 @@ describe('getExistingTransactionID', () => {
 
         expect(IOUUtils.getExistingTransactionID(moneyRequestAction)).toBe('txn123');
     });
+
+    describe('resolveOptimisticChatReportID', () => {
+        it('should return existing report ID when report has a reportID', () => {
+            const existingReport = {reportID: 'existing-123'} as Report;
+            const result = IOUUtils.resolveOptimisticChatReportID([1, 2], existingReport);
+
+            expect(result.chatReportID).toBe('existing-123');
+            expect(result.optimisticChatReportID).toBeUndefined();
+        });
+
+        it('should generate optimistic ID when no existing report is provided', () => {
+            const result = IOUUtils.resolveOptimisticChatReportID([1, 2]);
+
+            expect(result.optimisticChatReportID).toBeDefined();
+            expect(result.chatReportID).toBe(result.optimisticChatReportID);
+        });
+
+        it('should generate optimistic ID when existing report has no reportID', () => {
+            const emptyReport = {} as Report;
+            const result = IOUUtils.resolveOptimisticChatReportID([1, 2], emptyReport);
+
+            expect(result.optimisticChatReportID).toBeDefined();
+            expect(result.chatReportID).toBe(result.optimisticChatReportID);
+        });
+
+        it('should return consistent chatReportID that is always defined', () => {
+            const result1 = IOUUtils.resolveOptimisticChatReportID([1, 2], {reportID: 'report-1'} as Report);
+            const result2 = IOUUtils.resolveOptimisticChatReportID([1, 2]);
+
+            expect(result1.chatReportID).toBeDefined();
+            expect(result2.chatReportID).toBeDefined();
+        });
+    });
 });
diff --git a/tests/unit/dismissModalAndOpenReportInInboxTabTest.ts b/tests/unit/dismissModalAndOpenReportInInboxTabTest.ts
new file mode 100644
index 000000000000..3b8f78f8aa42
--- /dev/null
+++ b/tests/unit/dismissModalAndOpenReportInInboxTabTest.ts
@@ -0,0 +1,76 @@
+import dismissModalAndOpenReportInInboxTab from '@libs/Navigation/helpers/dismissModalAndOpenReportInInboxTab';
+import Navigation from '@libs/Navigation/Navigation';
+
+const mockIsSearchTopmostFullScreenRoute = jest.fn();
+const mockIsReportOpenInRHP = jest.fn();
+const mockGetSpan = jest.fn();
+
+jest.mock('@libs/Navigation/helpers/isSearchTopmostFullScreenRoute', () => () => mockIsSearchTopmostFullScreenRoute() as boolean);
+jest.mock('@libs/Navigation/helpers/isReportOpenInRHP', () => () => mockIsReportOpenInRHP() as boolean);
+jest.mock('@libs/Navigation/helpers/isReportOpenInSuperWideRHP', () => () => false as boolean);
+jest.mock('@libs/Navigation/helpers/setNavigationActionToMicrotaskQueue', () => (callback: () => void) => {
+    callback();
+});
+jest.mock('@libs/getIsNarrowLayout', () => () => false as boolean);
+jest.mock('@libs/telemetry/activeSpans', () => ({
+    getSpan: (...args: unknown[]) => mockGetSpan(...args) as boolean,
+}));
+jest.mock('@libs/telemetry/submitFollowUpAction', () => ({
+    setPendingSubmitFollowUpAction: jest.fn(),
+    endSubmitFollowUpActionSpan: jest.fn(),
+}));
+
+jest.mock('@libs/Navigation/Navigation', () => ({
+    dismissModal: jest.fn(),
+    dismissToPreviousRHP: jest.fn(),
+    dismissModalWithReport: jest.fn(),
+    pop: jest.fn(),
+    navigate: jest.fn(),
+    navigationRef: {
+        getRootState: jest.fn(() => ({
+            routes: [],
+        })),
+    },
+}));
+
+jest.mock('@react-navigation/native');
+
+describe('dismissModalAndOpenReportInInboxTab', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+        mockGetSpan.mockReturnValue(false);
+        mockIsReportOpenInRHP.mockReturnValue(false);
+        mockIsSearchTopmostFullScreenRoute.mockReturnValue(false);
+    });
+
+    it('should call dismissModalWithReport when report is not in RHP and not on search', () => {
+        const reportID = 'report-123';
+        dismissModalAndOpenReportInInboxTab(reportID, undefined, false);
+
+        expect(Navigation.dismissModalWithReport).toHaveBeenCalledWith({reportID});
+    });
+
+    it('should call dismissModal when on search page', () => {
+        mockIsSearchTopmostFullScreenRoute.mockReturnValue(true);
+        dismissModalAndOpenReportInInboxTab('report-123', undefined, false);
+
+        expect(Navigation.dismissModal).toHaveBeenCalled();
+        expect(Navigation.dismissModalWithReport).not.toHaveBeenCalled();
+    });
+
+    it('should call dismissModal when reportID is undefined', () => {
+        dismissModalAndOpenReportInInboxTab(undefined, undefined, false);
+
+        expect(Navigation.dismissModal).toHaveBeenCalled();
+    });
+
+    it('should skip RHP logic for invoices', () => {
+        mockIsReportOpenInRHP.mockReturnValue(true);
+        const reportID = 'report-123';
+        dismissModalAndOpenReportInInboxTab(reportID, true, false);
+
+        // Should fall through to dismissModalWithReport, not use RHP logic
+        expect(Navigation.dismissToPreviousRHP).not.toHaveBeenCalled();
+        expect(Navigation.dismissModalWithReport).toHaveBeenCalledWith({reportID});
+    });
+});
diff --git a/tests/unit/navigateAfterExpenseCreateTest.ts b/tests/unit/navigateAfterExpenseCreateTest.ts
new file mode 100644
index 000000000000..4bdecf1d2d02
--- /dev/null
+++ b/tests/unit/navigateAfterExpenseCreateTest.ts
@@ -0,0 +1,163 @@
+import navigateAfterExpenseCreate from '@libs/Navigation/helpers/navigateAfterExpenseCreate';
+import Navigation from '@libs/Navigation/Navigation';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
+
+const mockIsReportTopmostSplitNavigator = jest.fn();
+const mockIsSearchTopmostFullScreenRoute = jest.fn();
+const mockIsReportOpenInRHP = jest.fn();
+const mockGetIsNarrowLayout = jest.fn();
+const mockGetSpan = jest.fn();
+// Declared but assigned after jest.mock hoisting — use require() to access the mock in tests
+let mockSetPendingSubmitFollowUpAction: jest.Mock;
+const mockGetCurrentSearchQueryJSON = jest.fn();
+
+jest.mock('@libs/Navigation/helpers/isReportTopmostSplitNavigator', () => () => mockIsReportTopmostSplitNavigator() as boolean);
+jest.mock('@libs/Navigation/helpers/isSearchTopmostFullScreenRoute', () => () => mockIsSearchTopmostFullScreenRoute() as boolean);
+jest.mock('@libs/Navigation/helpers/isReportOpenInRHP', () => () => mockIsReportOpenInRHP() as boolean);
+jest.mock('@libs/Navigation/helpers/isReportOpenInSuperWideRHP', () => () => false as boolean);
+jest.mock('@libs/Navigation/helpers/setNavigationActionToMicrotaskQueue', () => (callback: () => void) => {
+    callback();
+});
+jest.mock('@libs/getIsNarrowLayout', () => () => mockGetIsNarrowLayout() as boolean);
+jest.mock('@libs/telemetry/activeSpans', () => ({
+    getSpan: (...args: unknown[]) => mockGetSpan(...args) as boolean,
+}));
+jest.mock('@libs/telemetry/submitFollowUpAction', () => ({
+    setPendingSubmitFollowUpAction: jest.fn(),
+    endSubmitFollowUpActionSpan: jest.fn(),
+}));
+jest.mock('@libs/SearchQueryUtils', () => ({
+    buildCannedSearchQuery: jest.fn(({type}: {type: string}) => `type:${type}`),
+    getCurrentSearchQueryJSON: () => mockGetCurrentSearchQueryJSON() as undefined,
+}));
+
+jest.mock('@libs/Navigation/Navigation', () => ({
+    dismissModal: jest.fn(),
+    dismissToPreviousRHP: jest.fn(),
+    dismissModalWithReport: jest.fn(),
+    pop: jest.fn(),
+    navigate: jest.fn(),
+    revealRouteBeforeDismissingModal: jest.fn(),
+    isNavigationReady: jest.fn(() => Promise.resolve()),
+    getIsFullscreenPreInsertedUnderRHP: jest.fn(() => false),
+    clearFullscreenPreInsertedFlag: jest.fn(),
+    navigationRef: {
+        getRootState: jest.fn(() => ({
+            routes: [],
+        })),
+        isReady: jest.fn(() => true),
+    },
+}));
+
+jest.mock('@react-navigation/native');
+
+describe('navigateAfterExpenseCreate', () => {
+    beforeAll(() => {
+        // eslint-disable-next-line @typescript-eslint/no-require-imports
+        const telemetryMock = require('@libs/telemetry/submitFollowUpAction') as {setPendingSubmitFollowUpAction: jest.Mock};
+        mockSetPendingSubmitFollowUpAction = telemetryMock.setPendingSubmitFollowUpAction;
+    });
+
+    beforeEach(() => {
+        jest.clearAllMocks();
+        mockIsReportTopmostSplitNavigator.mockReturnValue(false);
+        mockIsSearchTopmostFullScreenRoute.mockReturnValue(false);
+        mockIsReportOpenInRHP.mockReturnValue(false);
+        mockGetSpan.mockReturnValue(false);
+        mockGetCurrentSearchQueryJSON.mockReturnValue(undefined);
+    });
+
+    it('should dismiss to report when not from global create', () => {
+        navigateAfterExpenseCreate({
+            activeReportID: 'report-123',
+            transactionID: 'txn-1',
+            isFromGlobalCreate: false,
+            hasMultipleTransactions: false,
+        });
+
+        expect(Navigation.dismissModalWithReport).toHaveBeenCalledWith({reportID: 'report-123'});
+        expect(Navigation.navigate).not.toHaveBeenCalled();
+    });
+
+    it('should dismiss to report when user is on inbox tab', () => {
+        mockIsReportTopmostSplitNavigator.mockReturnValue(true);
+
+        navigateAfterExpenseCreate({
+            activeReportID: 'report-123',
+            transactionID: 'txn-1',
+            isFromGlobalCreate: true,
+            hasMultipleTransactions: false,
+        });
+
+        expect(Navigation.dismissModalWithReport).toHaveBeenCalledWith({reportID: 'report-123'});
+        expect(Navigation.navigate).not.toHaveBeenCalled();
+    });
+
+    it('should dismiss to report when transactionID is missing', () => {
+        navigateAfterExpenseCreate({
+            activeReportID: 'report-123',
+            isFromGlobalCreate: true,
+            hasMultipleTransactions: false,
+        });
+
+        expect(Navigation.dismissModalWithReport).toHaveBeenCalledWith({reportID: 'report-123'});
+    });
+
+    it('should navigate to search on narrow layout when from global create and not on inbox', () => {
+        mockGetIsNarrowLayout.mockReturnValue(true);
+
+        navigateAfterExpenseCreate({
+            activeReportID: 'report-123',
+            transactionID: 'txn-1',
+            isFromGlobalCreate: true,
+            hasMultipleTransactions: false,
+        });
+
+        expect(mockSetPendingSubmitFollowUpAction).toHaveBeenCalledWith(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.NAVIGATE_TO_SEARCH);
+        expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.SEARCH_ROOT.getRoute({query: 'type:expense'}), {forceReplace: true});
+    });
+
+    it('should reveal route before dismissing modal on wide layout when from global create', () => {
+        mockGetIsNarrowLayout.mockReturnValue(false);
+
+        navigateAfterExpenseCreate({
+            activeReportID: 'report-123',
+            transactionID: 'txn-1',
+            isFromGlobalCreate: true,
+            hasMultipleTransactions: false,
+        });
+
+        expect(Navigation.revealRouteBeforeDismissingModal).toHaveBeenCalledWith(ROUTES.SEARCH_ROOT.getRoute({query: 'type:expense'}));
+    });
+
+    it('should use invoice data type when isInvoice is true', () => {
+        mockGetIsNarrowLayout.mockReturnValue(true);
+
+        navigateAfterExpenseCreate({
+            activeReportID: 'report-123',
+            transactionID: 'txn-1',
+            isFromGlobalCreate: true,
+            isInvoice: true,
+            hasMultipleTransactions: false,
+        });
+
+        expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.SEARCH_ROOT.getRoute({query: 'type:invoice'}), {forceReplace: true});
+    });
+
+    it('should use pre-insert fast path on narrow layout when fullscreen is pre-inserted', () => {
+        mockGetIsNarrowLayout.mockReturnValue(true);
+        (Navigation.getIsFullscreenPreInsertedUnderRHP as jest.Mock).mockReturnValueOnce(true);
+
+        navigateAfterExpenseCreate({
+            activeReportID: 'report-123',
+            transactionID: 'txn-1',
+            isFromGlobalCreate: true,
+            hasMultipleTransactions: false,
+        });
+
+        expect(Navigation.clearFullscreenPreInsertedFlag).toHaveBeenCalled();
+        expect(Navigation.dismissModal).toHaveBeenCalled();
+        expect(Navigation.navigate).not.toHaveBeenCalled();
+    });
+});
