diff --git a/src/CONST.ts b/src/CONST.ts
index 268657bf35b3..dce070a7480b 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -5964,6 +5964,9 @@ const CONST = {
         ACTION_TYPES: {
             VIEW: 'view',
             REVIEW: 'review',
+            SUBMIT: 'submit',
+            APPROVE: 'approve',
+            PAY: 'pay',
             DONE: 'done',
             PAID: 'paid',
         },
diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx
index 1c3370cd72d5..d7b679f21891 100644
--- a/src/components/Search/SearchPageHeader.tsx
+++ b/src/components/Search/SearchPageHeader.tsx
@@ -182,7 +182,7 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) {
                     return;
                 }
 
-                const reportIDList = (selectedReports?.filter((report) => !!report) as string[]) ?? [];
+                const reportIDList = selectedReports?.filter((report) => !!report) ?? [];
                 SearchActions.exportSearchItemsToCSV(
                     {query: status, jsonQuery: JSON.stringify(queryJSON), reportIDList, transactionIDList: selectedTransactionsKeys, policyIDs: [activeWorkspaceID ?? '']},
                     () => {
diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts
index 74bf7b16d020..130ad7ae6f6e 100644
--- a/src/components/Search/types.ts
+++ b/src/components/Search/types.ts
@@ -24,6 +24,13 @@ type SelectedTransactionInfo = {
 /** Model of selected results */
 type SelectedTransactions = Record<string, SelectedTransactionInfo>;
 
+/** Model of payment data used by Search bulk actions */
+type PaymentData = {
+    reportID: string;
+    amount: number;
+    paymentType: ValueOf<typeof CONST.IOU.PAYMENT_TYPE>;
+};
+
 type SortOrder = ValueOf<typeof CONST.SEARCH.SORT_ORDER>;
 type SearchColumnType = ValueOf<typeof CONST.SEARCH.TABLE_COLUMNS>;
 type ExpenseSearchStatus = ValueOf<typeof CONST.SEARCH.STATUS.EXPENSE>;
@@ -117,5 +124,6 @@ export type {
     TripSearchStatus,
     ChatSearchStatus,
     SearchAutocompleteResult,
+    PaymentData,
     SearchAutocompleteQueryRange,
 };
diff --git a/src/components/SelectionList/Search/ActionCell.tsx b/src/components/SelectionList/Search/ActionCell.tsx
index faafa6159dc1..0a360a96e7c7 100644
--- a/src/components/SelectionList/Search/ActionCell.tsx
+++ b/src/components/SelectionList/Search/ActionCell.tsx
@@ -4,6 +4,7 @@ import Badge from '@components/Badge';
 import Button from '@components/Button';
 import * as Expensicons from '@components/Icon/Expensicons';
 import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
 import useStyleUtils from '@hooks/useStyleUtils';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
@@ -15,6 +16,9 @@ import type {SearchTransactionAction} from '@src/types/onyx/SearchResults';
 const actionTranslationsMap: Record<SearchTransactionAction, TranslationPaths> = {
     view: 'common.view',
     review: 'common.review',
+    submit: 'common.submit',
+    approve: 'iou.approve',
+    pay: 'iou.pay',
     done: 'common.done',
     paid: 'iou.settledExpensify',
 };
@@ -26,13 +30,23 @@ type ActionCellProps = {
     goToItem: () => void;
     isChildListItem?: boolean;
     parentAction?: string;
+    isLoading?: boolean;
 };
 
-function ActionCell({action = CONST.SEARCH.ACTION_TYPES.VIEW, isLargeScreenWidth = true, isSelected = false, goToItem, isChildListItem = false, parentAction = ''}: ActionCellProps) {
+function ActionCell({
+    action = CONST.SEARCH.ACTION_TYPES.VIEW,
+    isLargeScreenWidth = true,
+    isSelected = false,
+    goToItem,
+    isChildListItem = false,
+    parentAction = '',
+    isLoading = false,
+}: ActionCellProps) {
     const {translate} = useLocalize();
     const theme = useTheme();
     const styles = useThemeStyles();
     const StyleUtils = useStyleUtils();
+    const {isOffline} = useNetwork();
 
     const text = translate(actionTranslationsMap[action]);
 
@@ -61,9 +75,8 @@ function ActionCell({action = CONST.SEARCH.ACTION_TYPES.VIEW, isLargeScreenWidth
         );
     }
 
-    const buttonInnerStyles = isSelected ? styles.buttonDefaultHovered : {};
-
     if (action === CONST.SEARCH.ACTION_TYPES.VIEW || shouldUseViewAction) {
+        const buttonInnerStyles = isSelected ? styles.buttonDefaultHovered : {};
         return isLargeScreenWidth ? (
             <Button
                 text={translate(actionTranslationsMap[CONST.SEARCH.ACTION_TYPES.VIEW])}
@@ -77,17 +90,19 @@ function ActionCell({action = CONST.SEARCH.ACTION_TYPES.VIEW, isLargeScreenWidth
         ) : null;
     }
 
-    if (action === CONST.SEARCH.ACTION_TYPES.REVIEW) {
-        return (
-            <Button
-                text={text}
-                onPress={goToItem}
-                small
-                style={[styles.w100]}
-                innerStyles={buttonInnerStyles}
-            />
-        );
-    }
+    const buttonInnerStyles = isSelected ? styles.buttonSuccessHovered : {};
+    return (
+        <Button
+            text={text}
+            onPress={goToItem}
+            small
+            style={[styles.w100]}
+            innerStyles={buttonInnerStyles}
+            isLoading={isLoading}
+            success
+            isDisabled={isOffline}
+        />
+    );
 }
 
 ActionCell.displayName = 'ActionCell';
diff --git a/src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx b/src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx
index 185b9991e0a6..384262a78b15 100644
--- a/src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx
+++ b/src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx
@@ -28,6 +28,7 @@ type ExpenseItemHeaderNarrowProps = {
     isDisabled?: boolean | null;
     isDisabledCheckbox?: boolean;
     handleCheckboxPress?: () => void;
+    isLoading?: boolean;
 };
 
 function ExpenseItemHeaderNarrow({
@@ -44,6 +45,7 @@ function ExpenseItemHeaderNarrow({
     isDisabled,
     handleCheckboxPress,
     text,
+    isLoading = false,
 }: ExpenseItemHeaderNarrowProps) {
     const styles = useThemeStyles();
     const StyleUtils = useStyleUtils();
@@ -102,6 +104,7 @@ function ExpenseItemHeaderNarrow({
                     goToItem={onButtonPress}
                     isLargeScreenWidth={false}
                     isSelected={isSelected}
+                    isLoading={isLoading}
                 />
             </View>
         </View>
diff --git a/src/components/SelectionList/Search/ReportListItem.tsx b/src/components/SelectionList/Search/ReportListItem.tsx
index 7add6be940d2..b03932db2532 100644
--- a/src/components/SelectionList/Search/ReportListItem.tsx
+++ b/src/components/SelectionList/Search/ReportListItem.tsx
@@ -1,6 +1,7 @@
 import React from 'react';
 import {View} from 'react-native';
 import Checkbox from '@components/Checkbox';
+import {useSearchContext} from '@components/Search/SearchContext';
 import BaseListItem from '@components/SelectionList/BaseListItem';
 import type {ListItem, ReportListItemProps, ReportListItemType, TransactionListItemType} from '@components/SelectionList/types';
 import Text from '@components/Text';
@@ -10,6 +11,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout';
 import useStyleUtils from '@hooks/useStyleUtils';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
+import {handleActionButtonPress} from '@libs/actions/Search';
 import * as CurrencyUtils from '@libs/CurrencyUtils';
 import Navigation from '@libs/Navigation/Navigation';
 import variables from '@styles/variables';
@@ -69,6 +71,7 @@ function ReportListItem<TItem extends ListItem>({
     const styles = useThemeStyles();
     const {isLargeScreenWidth} = useResponsiveLayout();
     const StyleUtils = useStyleUtils();
+    const {currentSearchHash} = useSearchContext();
 
     const animatedHighlightStyle = useAnimatedHighlightStyle({
         borderRadius: variables.componentBorderRadius,
@@ -93,7 +96,7 @@ function ReportListItem<TItem extends ListItem>({
     ];
 
     const handleOnButtonPress = () => {
-        onSelectRow(item);
+        handleActionButtonPress(currentSearchHash, reportItem, () => onSelectRow(item));
     };
 
     const openReportInRHP = (transactionItem: TransactionListItemType) => {
@@ -165,6 +168,7 @@ function ReportListItem<TItem extends ListItem>({
                         action={reportItem.action}
                         onButtonPress={handleOnButtonPress}
                         containerStyle={[styles.ph3, styles.pt1half, styles.mb1half]}
+                        isLoading={reportItem.isActionLoading}
                     />
                 )}
                 <View style={[styles.flex1, styles.flexRow, styles.alignItemsCenter, styles.gap3, styles.ph3, styles.pv1half]}>
@@ -199,6 +203,7 @@ function ReportListItem<TItem extends ListItem>({
                                 action={reportItem.action}
                                 goToItem={handleOnButtonPress}
                                 isSelected={item.isSelected}
+                                isLoading={reportItem.isActionLoading}
                             />
                         </View>
                     )}
diff --git a/src/components/SelectionList/Search/TransactionListItem.tsx b/src/components/SelectionList/Search/TransactionListItem.tsx
index 1a27599ed0bd..a23a7048644e 100644
--- a/src/components/SelectionList/Search/TransactionListItem.tsx
+++ b/src/components/SelectionList/Search/TransactionListItem.tsx
@@ -1,10 +1,12 @@
 import React from 'react';
+import {useSearchContext} from '@components/Search/SearchContext';
 import BaseListItem from '@components/SelectionList/BaseListItem';
 import type {ListItem, TransactionListItemProps, TransactionListItemType} from '@components/SelectionList/types';
 import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
+import {handleActionButtonPress} from '@libs/actions/Search';
 import variables from '@styles/variables';
 import TransactionListItemRow from './TransactionListItemRow';
 
@@ -26,6 +28,7 @@ function TransactionListItem<TItem extends ListItem>({
     const theme = useTheme();
 
     const {isLargeScreenWidth} = useResponsiveLayout();
+    const {currentSearchHash} = useSearchContext();
 
     const listItemPressableStyle = [
         styles.selectionListPressableItemWrapper,
@@ -75,13 +78,14 @@ function TransactionListItem<TItem extends ListItem>({
                 item={transactionItem}
                 showTooltip={showTooltip}
                 onButtonPress={() => {
-                    onSelectRow(item);
+                    handleActionButtonPress(currentSearchHash, transactionItem, () => onSelectRow(item));
                 }}
                 onCheckboxPress={() => onCheckboxPress?.(item)}
                 isDisabled={!!isDisabled}
                 canSelectMultiple={!!canSelectMultiple}
                 isButtonSelected={item.isSelected}
                 shouldShowTransactionCheckbox={false}
+                isLoading={transactionItem.isActionLoading}
             />
         </BaseListItem>
     );
diff --git a/src/components/SelectionList/Search/TransactionListItemRow.tsx b/src/components/SelectionList/Search/TransactionListItemRow.tsx
index 37b0429b7caa..6bd071fa5ded 100644
--- a/src/components/SelectionList/Search/TransactionListItemRow.tsx
+++ b/src/components/SelectionList/Search/TransactionListItemRow.tsx
@@ -59,6 +59,7 @@ type TransactionListItemRowProps = {
     isButtonSelected?: boolean;
     parentAction?: string;
     shouldShowTransactionCheckbox?: boolean;
+    isLoading?: boolean;
 };
 
 const getTypeIcon = (type?: SearchTransactionType) => {
@@ -257,6 +258,7 @@ function TransactionListItemRow({
     isButtonSelected = false,
     parentAction = '',
     shouldShowTransactionCheckbox,
+    isLoading = false,
 }: TransactionListItemRowProps) {
     const styles = useThemeStyles();
     const {isLargeScreenWidth} = useResponsiveLayout();
@@ -280,6 +282,7 @@ function TransactionListItemRow({
                         isDisabled={item.isDisabled}
                         isDisabledCheckbox={item.isDisabledCheckbox}
                         handleCheckboxPress={onCheckboxPress}
+                        isLoading={isLoading}
                     />
                 )}
 
@@ -445,6 +448,7 @@ function TransactionListItemRow({
                         isChildListItem={isChildListItem}
                         parentAction={parentAction}
                         goToItem={onButtonPress}
+                        isLoading={isLoading}
                     />
                 </View>
             </View>
diff --git a/src/components/SelectionList/SearchTableHeaderColumn.tsx b/src/components/SelectionList/SearchTableHeaderColumn.tsx
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/src/libs/API/parameters/PayMoneyRequestOnSearchParams.ts b/src/libs/API/parameters/PayMoneyRequestOnSearchParams.ts
index 10174f0baa37..a12c0fdc32f2 100644
--- a/src/libs/API/parameters/PayMoneyRequestOnSearchParams.ts
+++ b/src/libs/API/parameters/PayMoneyRequestOnSearchParams.ts
@@ -1,11 +1,10 @@
 type PayMoneyRequestOnSearchParams = {
     hash: number;
-    paymentType: string;
     /**
      * Stringified JSON object with type of following structure:
-     * Array<{reportID: string, amount: number}>
+     * Array<{reportID: string, amount: number, paymentType: string}>
      */
-    reportsAndAmounts: string;
+    paymentData: string;
 };
 
 export default PayMoneyRequestOnSearchParams;
diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts
index bdf760728576..dc1c07388293 100644
--- a/src/libs/PolicyUtils.ts
+++ b/src/libs/PolicyUtils.ts
@@ -29,6 +29,7 @@ import type {
     Tenant,
 } from '@src/types/onyx/Policy';
 import type PolicyEmployee from '@src/types/onyx/PolicyEmployee';
+import type {SearchPolicy} from '@src/types/onyx/SearchResults';
 import {isEmptyObject} from '@src/types/utils/EmptyObject';
 import {hasSynchronizationErrorMessage} from './actions/connections';
 import {getCategoryApproverRule} from './CategoryUtils';
@@ -184,7 +185,7 @@ function getPolicyBrickRoadIndicatorStatus(policy: OnyxEntry<Policy>, isConnecti
     return undefined;
 }
 
-function getPolicyRole(policy: OnyxInputOrEntry<Policy>, currentUserLogin: string | undefined) {
+function getPolicyRole(policy: OnyxInputOrEntry<Policy> | SearchPolicy, currentUserLogin: string | undefined) {
     return policy?.role ?? policy?.employeeList?.[currentUserLogin ?? '-1']?.role;
 }
 
@@ -218,7 +219,7 @@ const isUserPolicyAdmin = (policy: OnyxInputOrEntry<Policy>, login?: string) =>
 /**
  * Checks if the current user is an admin of the policy.
  */
-const isPolicyAdmin = (policy: OnyxInputOrEntry<Policy>, currentUserLogin?: string): boolean => getPolicyRole(policy, currentUserLogin) === CONST.POLICY.ROLE.ADMIN;
+const isPolicyAdmin = (policy: OnyxInputOrEntry<Policy> | SearchPolicy, currentUserLogin?: string): boolean => getPolicyRole(policy, currentUserLogin) === CONST.POLICY.ROLE.ADMIN;
 
 /**
  * Checks if the current user is of the role "user" on the policy.
@@ -379,7 +380,7 @@ function isPendingDeletePolicy(policy: OnyxEntry<Policy>): boolean {
     return policy?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
 }
 
-function isPaidGroupPolicy(policy: OnyxEntry<Policy>): boolean {
+function isPaidGroupPolicy(policy: OnyxEntry<Policy> | SearchPolicy): boolean {
     return policy?.type === CONST.POLICY.TYPE.TEAM || policy?.type === CONST.POLICY.TYPE.CORPORATE;
 }
 
@@ -404,7 +405,7 @@ function isTaxTrackingEnabled(isPolicyExpenseChat: boolean, policy: OnyxEntry<Po
  * Checks if policy's scheduled submit / auto reporting frequency is "instant".
  * Note: Free policies have "instant" submit always enabled.
  */
-function isInstantSubmitEnabled(policy: OnyxInputOrEntry<Policy>): boolean {
+function isInstantSubmitEnabled(policy: OnyxInputOrEntry<Policy> | SearchPolicy): boolean {
     return policy?.autoReporting === true && policy?.autoReportingFrequency === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.INSTANT;
 }
 
@@ -434,7 +435,7 @@ function getCorrectedAutoReportingFrequency(policy: OnyxInputOrEntry<Policy>): V
 /**
  * Checks if policy's approval mode is "optional", a.k.a. "Submit & Close"
  */
-function isSubmitAndClose(policy: OnyxInputOrEntry<Policy>): boolean {
+function isSubmitAndClose(policy: OnyxInputOrEntry<Policy> | SearchPolicy): boolean {
     return policy?.approvalMode === CONST.POLICY.APPROVAL_MODE.OPTIONAL;
 }
 
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 2acfde557d5d..6bde694fc980 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -54,6 +54,7 @@ import type {Status} from '@src/types/onyx/PersonalDetails';
 import type {ConnectionName} from '@src/types/onyx/Policy';
 import type {NotificationPreference, Participants, PendingChatMember, Participant as ReportParticipant} from '@src/types/onyx/Report';
 import type {Message, OldDotReportAction, ReportActions} from '@src/types/onyx/ReportAction';
+import type {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults';
 import type {Comment, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction';
 import {isEmptyObject} from '@src/types/utils/EmptyObject';
 import type IconAsset from '@src/types/utils/IconAsset';
@@ -854,21 +855,21 @@ function isChatReport(report: OnyxEntry<Report>): boolean {
     return report?.type === CONST.REPORT.TYPE.CHAT;
 }
 
-function isInvoiceReport(report: OnyxInputOrEntry<Report>): boolean {
+function isInvoiceReport(report: OnyxInputOrEntry<Report> | SearchReport): boolean {
     return report?.type === CONST.REPORT.TYPE.INVOICE;
 }
 
 /**
  * Checks if a report is an Expense report.
  */
-function isExpenseReport(report: OnyxInputOrEntry<Report>): boolean {
+function isExpenseReport(report: OnyxInputOrEntry<Report> | SearchReport): boolean {
     return report?.type === CONST.REPORT.TYPE.EXPENSE;
 }
 
 /**
  * Checks if a report is an IOU report using report or reportID
  */
-function isIOUReport(reportOrID: OnyxInputOrEntry<Report> | string): boolean {
+function isIOUReport(reportOrID: OnyxInputOrEntry<Report> | SearchReport | string): boolean {
     const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID;
     return report?.type === CONST.REPORT.TYPE.IOU;
 }
@@ -977,12 +978,15 @@ function hasParticipantInArray(report: OnyxEntry<Report>, memberAccountIDs: numb
 /**
  * Whether the Money Request report is settled
  */
-function isSettled(reportID: string | undefined): boolean {
-    const allReports = ReportConnection.getAllReports();
-    if (!allReports || !reportID) {
+function isSettled(reportOrID: OnyxInputOrEntry<Report> | SearchReport | string | undefined): boolean {
+    if (!reportOrID) {
+        return false;
+    }
+    const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID;
+    if (!report) {
         return false;
     }
-    const report = allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] ?? null;
+
     if (isEmptyObject(report) || report.isWaitingOnBankAccount) {
         return false;
     }
@@ -1459,7 +1463,7 @@ function isClosedExpenseReportWithNoExpenses(report: OnyxEntry<Report>): boolean
  * Whether the provided report is an archived room
  */
 // eslint-disable-next-line @typescript-eslint/no-unused-vars
-function isArchivedRoom(report: OnyxInputOrEntry<Report>, reportNameValuePairs?: OnyxInputOrEntry<ReportNameValuePairs>): boolean {
+function isArchivedRoom(report: OnyxInputOrEntry<Report> | SearchReport, reportNameValuePairs?: OnyxInputOrEntry<ReportNameValuePairs>): boolean {
     return !!report?.private_isArchived;
 }
 
@@ -1475,7 +1479,7 @@ function isArchivedRoomWithID(reportID?: string) {
 /**
  * Whether the provided report is a closed report
  */
-function isClosedReport(report: OnyxEntry<Report>): boolean {
+function isClosedReport(report: OnyxEntry<Report> | SearchReport): boolean {
     return report?.statusNum === CONST.REPORT.STATUS_NUM.CLOSED;
 }
 
@@ -1663,7 +1667,7 @@ function isMoneyRequest(reportOrID: OnyxEntry<Report> | string): boolean {
 /**
  * Checks if a report is an IOU or expense report.
  */
-function isMoneyRequestReport(reportOrID: OnyxInputOrEntry<Report> | string): boolean {
+function isMoneyRequestReport(reportOrID: OnyxInputOrEntry<Report> | SearchReport | string): boolean {
     const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID;
     return isIOUReport(report) || isExpenseReport(report);
 }
@@ -1740,9 +1744,9 @@ function isOneOnOneChat(report: OnyxEntry<Report>): boolean {
  * Checks if the current user is a payer of the expense
  */
 
-function isPayer(session: OnyxEntry<Session>, iouReport: OnyxEntry<Report>, onlyShowPayElsewhere = false) {
+function isPayer(session: OnyxEntry<Session>, iouReport: OnyxEntry<Report>, onlyShowPayElsewhere = false, reportPolicy?: OnyxInputOrEntry<Policy> | SearchPolicy) {
     const isApproved = isReportApproved(iouReport);
-    const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${iouReport?.policyID}`] ?? null;
+    const policy = reportPolicy ?? allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${iouReport?.policyID}`] ?? null;
     const policyType = policy?.type;
     const isAdmin = policyType !== CONST.POLICY.TYPE.PERSONAL && policy?.role === CONST.POLICY.ROLE.ADMIN;
     const isManager = iouReport?.managerID === session?.accountID;
@@ -7725,16 +7729,16 @@ function getAllHeldTransactions(iouReportID?: string): Transaction[] {
 /**
  * Check if Report has any held expenses
  */
-function hasHeldExpenses(iouReportID?: string): boolean {
-    const transactions = reportsTransactions[iouReportID ?? ''] ?? [];
+function hasHeldExpenses(iouReportID?: string, allReportTransactions?: SearchTransaction[]): boolean {
+    const transactions = allReportTransactions ?? reportsTransactions[iouReportID ?? ''] ?? [];
     return transactions.some((transaction) => TransactionUtils.isOnHold(transaction));
 }
 
 /**
  * Check if all expenses in the Report are on hold
  */
-function hasOnlyHeldExpenses(iouReportID: string): boolean {
-    const reportTransactions = reportsTransactions[iouReportID ?? ''] ?? [];
+function hasOnlyHeldExpenses(iouReportID: string, allReportTransactions?: SearchTransaction[]): boolean {
+    const reportTransactions = allReportTransactions ?? reportsTransactions[iouReportID ?? ''] ?? [];
     return reportTransactions.length > 0 && !reportTransactions.some((transaction) => !TransactionUtils.isOnHold(transaction));
 }
 
@@ -7960,7 +7964,7 @@ function getQuickActionDetails(
     };
 }
 
-function canBeAutoReimbursed(report: OnyxInputOrEntry<Report>, policy: OnyxInputOrEntry<Policy>): boolean {
+function canBeAutoReimbursed(report: OnyxInputOrEntry<Report>, policy: OnyxInputOrEntry<Policy> | SearchPolicy): boolean {
     if (isEmptyObject(policy)) {
         return false;
     }
@@ -7981,8 +7985,8 @@ function isReportOwner(report: OnyxInputOrEntry<Report>): boolean {
     return report?.ownerAccountID === currentUserPersonalDetails?.accountID;
 }
 
-function isAllowedToApproveExpenseReport(report: OnyxEntry<Report>, approverAccountID?: number): boolean {
-    const policy = getPolicy(report?.policyID);
+function isAllowedToApproveExpenseReport(report: OnyxEntry<Report>, approverAccountID?: number, reportPolicy?: OnyxEntry<Policy> | SearchPolicy): boolean {
+    const policy = reportPolicy ?? getPolicy(report?.policyID);
     const isOwner = (approverAccountID ?? currentUserAccountID) === report?.ownerAccountID;
     return !(policy?.preventSelfApproval && isOwner);
 }
diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts
index a7ce065a6d23..d9f63a0c1094 100644
--- a/src/libs/SearchUIUtils.ts
+++ b/src/libs/SearchUIUtils.ts
@@ -11,12 +11,14 @@ import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
 import type * as OnyxTypes from '@src/types/onyx';
 import type SearchResults from '@src/types/onyx/SearchResults';
-import type {ListItemDataType, ListItemType, SearchDataTypes, SearchPersonalDetails, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults';
+import type {ListItemDataType, ListItemType, SearchDataTypes, SearchPersonalDetails, SearchReport, SearchTransaction, SearchTransactionAction} from '@src/types/onyx/SearchResults';
+import * as IOU from './actions/IOU';
 import * as CurrencyUtils from './CurrencyUtils';
 import DateUtils from './DateUtils';
 import {translateLocal} from './Localize';
 import Navigation from './Navigation/Navigation';
 import * as ReportActionsUtils from './ReportActionsUtils';
+import * as ReportUtils from './ReportUtils';
 import * as TransactionUtils from './TransactionUtils';
 
 const columnNamesToSortingProperty = {
@@ -209,7 +211,6 @@ function getIOUReportName(data: OnyxTypes.SearchResults['data'], reportItem: Sea
  */
 function getTransactionsSections(data: OnyxTypes.SearchResults['data'], metadata: OnyxTypes.SearchResults['search']): TransactionListItemType[] {
     const shouldShowMerchant = getShouldShowMerchant(data);
-
     const doesDataContainAPastYearTransaction = shouldShowYear(data);
 
     return Object.keys(data)
@@ -223,6 +224,7 @@ function getTransactionsSections(data: OnyxTypes.SearchResults['data'], metadata
 
             return {
                 ...transactionItem,
+                action: getAction(data, key),
                 from,
                 to,
                 formattedFrom,
@@ -240,6 +242,66 @@ function getTransactionsSections(data: OnyxTypes.SearchResults['data'], metadata
         });
 }
 
+/**
+ * @private
+ * Returns the action that can be taken on a given transaction or report
+ *
+ * Do not use directly, use only via `getSections()` facade.
+ */
+function getAction(data: OnyxTypes.SearchResults['data'], key: string): SearchTransactionAction {
+    const isTransaction = isTransactionEntry(key);
+    if (!isTransaction && !isReportEntry(key)) {
+        return CONST.SEARCH.ACTION_TYPES.VIEW;
+    }
+
+    const transaction = isTransaction ? data[key] : undefined;
+    const report = isTransaction ? data[`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`] : data[key];
+
+    if (ReportUtils.isSettled(report)) {
+        return CONST.SEARCH.ACTION_TYPES.PAID;
+    }
+
+    if (ReportUtils.isClosedReport(report)) {
+        return CONST.SEARCH.ACTION_TYPES.DONE;
+    }
+
+    // We don't need to run the logic if this is not a transaction or iou/expense report, so let's shortcircuit the logic for performance reasons
+    if (!ReportUtils.isMoneyRequestReport(report) || (isTransaction && !data[key].isFromOneTransactionReport)) {
+        return CONST.SEARCH.ACTION_TYPES.VIEW;
+    }
+
+    const policy = data[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`] ?? {};
+
+    const invoiceReceiverPolicy =
+        ReportUtils.isInvoiceReport(report) && report?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS
+            ? data[`${ONYXKEYS.COLLECTION.POLICY}${report?.invoiceReceiver?.policyID}`]
+            : undefined;
+
+    const allReportTransactions = (
+        isReportEntry(key)
+            ? Object.entries(data)
+                  .filter(([itemKey, value]) => isTransactionEntry(itemKey) && (value as SearchTransaction)?.reportID === report.reportID)
+                  .map((item) => item[1])
+            : [transaction]
+    ) as SearchTransaction[];
+
+    const chatReport = data[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`] ?? {};
+    const chatReportRNVP = data[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.chatReportID}`] ?? undefined;
+
+    if (
+        IOU.canIOUBePaid(report, chatReport, policy, allReportTransactions, false, chatReportRNVP, invoiceReceiverPolicy) &&
+        !ReportUtils.hasOnlyHeldExpenses(report.reportID, allReportTransactions)
+    ) {
+        return CONST.SEARCH.ACTION_TYPES.PAY;
+    }
+
+    if (IOU.canApproveIOU(report, policy) && ReportUtils.isAllowedToApproveExpenseReport(report, undefined, policy)) {
+        return CONST.SEARCH.ACTION_TYPES.APPROVE;
+    }
+
+    return CONST.SEARCH.ACTION_TYPES.VIEW;
+}
+
 /**
  * @private
  * Organizes data into List Sections for display, for the ReportActionListItemType of Search Results.
@@ -291,6 +353,7 @@ function getReportSections(data: OnyxTypes.SearchResults['data'], metadata: Onyx
 
             reportIDToTransactions[reportKey] = {
                 ...reportItem,
+                action: getAction(data, key),
                 keyForList: reportItem.reportID,
                 from: data.personalDetailsList?.[reportItem.accountID ?? -1],
                 to: reportItem.managerID ? data.personalDetailsList?.[reportItem.managerID] : emptyPersonalDetails,
@@ -308,6 +371,7 @@ function getReportSections(data: OnyxTypes.SearchResults['data'], metadata: Onyx
 
             const transaction = {
                 ...transactionItem,
+                action: getAction(data, key),
                 from,
                 to,
                 formattedFrom,
diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts
index cb2c1a52e2d2..1fc7cad2f456 100644
--- a/src/libs/TransactionUtils/index.ts
+++ b/src/libs/TransactionUtils/index.ts
@@ -27,6 +27,7 @@ import type {IOUType} from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import type {Beta, OnyxInputOrEntry, Policy, RecentWaypoint, Report, ReviewDuplicates, TaxRate, TaxRates, Transaction, TransactionViolation, TransactionViolations} from '@src/types/onyx';
 import type {Attendee} from '@src/types/onyx/IOU';
+import type {SearchPolicy, SearchReport} from '@src/types/onyx/SearchResults';
 import type {Comment, Receipt, TransactionChanges, TransactionPendingFieldsKey, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction';
 import type DeepValueOf from '@src/types/utils/DeepValueOf';
 import {isEmptyObject} from '@src/types/utils/EmptyObject';
@@ -715,7 +716,7 @@ function hasBrokenConnectionViolation(transactionID: string): boolean {
 /**
  * Check if user should see broken connection violation warning.
  */
-function shouldShowBrokenConnectionViolation(transactionID: string, report: OnyxEntry<Report>, policy: OnyxEntry<Policy>): boolean {
+function shouldShowBrokenConnectionViolation(transactionID: string, report: OnyxEntry<Report> | SearchReport, policy: OnyxEntry<Policy> | SearchPolicy): boolean {
     return (
         hasBrokenConnectionViolation(transactionID) &&
         (!PolicyUtils.isPolicyAdmin(policy) || ReportUtils.isOpenExpenseReport(report) || (ReportUtils.isProcessingReport(report) && PolicyUtils.isInstantSubmitEnabled(policy)))
diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts
index dd6686b9ff7d..73dfcd4f26b5 100644
--- a/src/libs/actions/IOU.ts
+++ b/src/libs/actions/IOU.ts
@@ -66,7 +66,7 @@ import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon';
 import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
 import type ReportAction from '@src/types/onyx/ReportAction';
 import type {OnyxData} from '@src/types/onyx/Request';
-import type {SearchTransaction} from '@src/types/onyx/SearchResults';
+import type {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults';
 import type {Comment, Receipt, ReceiptSource, Routes, SplitShares, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction';
 import {isEmptyObject} from '@src/types/utils/EmptyObject';
 import * as CachedPDFPaths from './CachedPDFPaths';
@@ -6746,7 +6746,11 @@ function sendMoneyWithWallet(report: OnyxEntry<OnyxTypes.Report>, amount: number
     Report.notifyNewAction(params.chatReportID, managerID);
 }
 
-function canApproveIOU(iouReport: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Report>, policy: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Policy>) {
+function canApproveIOU(
+    iouReport: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Report> | SearchReport,
+    policy: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Policy> | SearchPolicy,
+    chatReportRNVP?: OnyxTypes.ReportNameValuePairs,
+) {
     // Only expense reports can be approved
     const isPaidGroupPolicy = policy && PolicyUtils.isPaidGroupPolicy(policy);
     if (!isPaidGroupPolicy) {
@@ -6763,7 +6767,7 @@ function canApproveIOU(iouReport: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Report>,
     const isOpenExpenseReport = ReportUtils.isOpenExpenseReport(iouReport);
     const isApproved = ReportUtils.isReportApproved(iouReport);
     const iouSettled = ReportUtils.isSettled(iouReport?.reportID);
-    const reportNameValuePairs = ReportUtils.getReportNameValuePairs(iouReport?.reportID);
+    const reportNameValuePairs = chatReportRNVP ?? ReportUtils.getReportNameValuePairs(iouReport?.reportID);
     const isArchivedReport = ReportUtils.isArchivedRoom(iouReport, reportNameValuePairs);
     let isTransactionBeingScanned = false;
     const reportTransactions = TransactionUtils.getAllReportTransactions(iouReport?.reportID);
@@ -6781,16 +6785,18 @@ function canApproveIOU(iouReport: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Report>,
 }
 
 function canIOUBePaid(
-    iouReport: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Report>,
-    chatReport: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Report>,
-    policy: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Policy>,
-    transactions?: OnyxTypes.Transaction[],
+    iouReport: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Report> | SearchReport,
+    chatReport: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Report> | SearchReport,
+    policy: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Policy> | SearchPolicy,
+    transactions?: OnyxTypes.Transaction[] | SearchTransaction[],
     onlyShowPayElsewhere = false,
+    chatReportRNVP?: OnyxTypes.ReportNameValuePairs,
+    invoiceReceiverPolicy?: SearchPolicy,
 ) {
     const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(chatReport);
-    const reportNameValuePairs = ReportUtils.getReportNameValuePairs(chatReport?.reportID);
+    const reportNameValuePairs = chatReportRNVP ?? ReportUtils.getReportNameValuePairs(chatReport?.reportID);
     const isChatReportArchived = ReportUtils.isArchivedRoom(chatReport, reportNameValuePairs);
-    const iouSettled = ReportUtils.isSettled(iouReport?.reportID);
+    const iouSettled = ReportUtils.isSettled(iouReport);
 
     if (isEmptyObject(iouReport)) {
         return false;
@@ -6812,7 +6818,7 @@ function canIOUBePaid(
         if (chatReport?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL) {
             return chatReport?.invoiceReceiver?.accountID === userAccountID;
         }
-        return PolicyUtils.getPolicy(chatReport?.invoiceReceiver?.policyID)?.role === CONST.POLICY.ROLE.ADMIN;
+        return (invoiceReceiverPolicy ?? PolicyUtils.getPolicy(chatReport?.invoiceReceiver?.policyID))?.role === CONST.POLICY.ROLE.ADMIN;
     }
 
     const isPayer = ReportUtils.isPayer(
@@ -6822,6 +6828,7 @@ function canIOUBePaid(
         },
         iouReport,
         onlyShowPayElsewhere,
+        policy,
     );
 
     const isOpenExpenseReport = isPolicyExpenseChat && ReportUtils.isOpenExpenseReport(iouReport);
diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts
index caef871571ed..44b5bb7f7ce9 100644
--- a/src/libs/actions/Search.ts
+++ b/src/libs/actions/Search.ts
@@ -1,18 +1,22 @@
 import Onyx from 'react-native-onyx';
-import type {OnyxUpdate} from 'react-native-onyx';
+import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx';
 import type {ValueOf} from 'type-fest';
 import type {FormOnyxValues} from '@components/Form/types';
-import type {SearchQueryJSON} from '@components/Search/types';
+import type {PaymentData, SearchQueryJSON} from '@components/Search/types';
+import type {ReportListItemType, TransactionListItemType} from '@components/SelectionList/types';
 import * as API from '@libs/API';
 import type {ExportSearchItemsToCSVParams} from '@libs/API/parameters';
 import {WRITE_COMMANDS} from '@libs/API/types';
 import * as ApiUtils from '@libs/ApiUtils';
 import fileDownload from '@libs/fileDownload';
 import enhanceParameters from '@libs/Network/enhanceParameters';
+import * as ReportUtils from '@libs/ReportUtils';
+import {isReportListItemType, isTransactionListItemType} from '@libs/SearchUIUtils';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import FILTER_KEYS from '@src/types/form/SearchAdvancedFiltersForm';
-import type {SearchTransaction} from '@src/types/onyx/SearchResults';
+import type {LastPaymentMethod, SearchResults} from '@src/types/onyx';
+import type {SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults';
 import * as Report from './Report';
 
 let currentUserEmail: string;
@@ -23,6 +27,80 @@ Onyx.connect({
     },
 });
 
+let lastPaymentMethod: OnyxEntry<LastPaymentMethod>;
+Onyx.connect({
+    key: ONYXKEYS.NVP_LAST_PAYMENT_METHOD,
+    callback: (val) => {
+        lastPaymentMethod = val;
+    },
+});
+
+let allSnapshots: OnyxCollection<SearchResults>;
+Onyx.connect({
+    key: ONYXKEYS.COLLECTION.SNAPSHOT,
+    callback: (val) => {
+        allSnapshots = val;
+    },
+    waitForCollectionCallback: true,
+});
+
+function handleActionButtonPress(hash: number, item: TransactionListItemType | ReportListItemType, goToItem: () => void) {
+    // The transactionID is needed to handle actions taken on `status:all` where transactions on single expense reports can be approved/paid.
+    // We need the transactionID to display the loading indicator for that list item's action.
+    const transactionID = isTransactionListItemType(item) ? item.transactionID : undefined;
+    const data = (allSnapshots?.[`${ONYXKEYS.COLLECTION.SNAPSHOT}${hash}`]?.data ?? {}) as SearchResults['data'];
+    const allReportTransactions = (
+        isReportListItemType(item)
+            ? Object.entries(data)
+                  .filter(([itemKey, value]) => itemKey.startsWith(ONYXKEYS.COLLECTION.REPORT) && (value as SearchTransaction)?.reportID === item.reportID)
+                  .map((report) => report[1])
+            : [data[`${ONYXKEYS.COLLECTION.TRANSACTION}${item.transactionID}`]]
+    ) as SearchTransaction[];
+
+    const hasHeldExpense = ReportUtils.hasHeldExpenses('', allReportTransactions);
+    if (hasHeldExpense) {
+        goToItem();
+        return;
+    }
+
+    switch (item.action) {
+        case CONST.SEARCH.ACTION_TYPES.PAY:
+            getPayActionCallback(hash, item, goToItem);
+            return;
+        case CONST.SEARCH.ACTION_TYPES.APPROVE:
+            approveMoneyRequestOnSearch(hash, [item.reportID], transactionID);
+            return;
+        default:
+            goToItem();
+    }
+}
+
+function getPayActionCallback(hash: number, item: TransactionListItemType | ReportListItemType, goToItem: () => void) {
+    const lastPolicyPaymentMethod = item.policyID ? (lastPaymentMethod?.[item.policyID] as ValueOf<typeof CONST.IOU.PAYMENT_TYPE>) : null;
+
+    if (!lastPolicyPaymentMethod) {
+        goToItem();
+        return;
+    }
+
+    const report = (allSnapshots?.[`${ONYXKEYS.COLLECTION.SNAPSHOT}${hash}`]?.data?.[`${ONYXKEYS.COLLECTION.REPORT}${item.reportID}`] ?? {}) as SearchReport;
+    const amount = Math.abs((report?.total ?? 0) - (report?.nonReimbursableTotal ?? 0));
+    const transactionID = isTransactionListItemType(item) ? item.transactionID : undefined;
+
+    if (lastPolicyPaymentMethod === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) {
+        payMoneyRequestOnSearch(hash, [{reportID: item.reportID, amount, paymentType: lastPolicyPaymentMethod}], transactionID);
+        return;
+    }
+
+    const hasVBBA = !!allSnapshots?.[`${ONYXKEYS.COLLECTION.SNAPSHOT}${hash}`]?.data?.[`${ONYXKEYS.COLLECTION.POLICY}${item.policyID}`]?.achAccount?.bankAccountID;
+    if (hasVBBA) {
+        payMoneyRequestOnSearch(hash, [{reportID: item.reportID, amount, paymentType: lastPolicyPaymentMethod}], transactionID);
+        return;
+    }
+
+    goToItem();
+}
+
 function getOnyxLoadingData(hash: number): {optimisticData: OnyxUpdate[]; finallyData: OnyxUpdate[]} {
     const optimisticData: OnyxUpdate[] = [
         {
@@ -164,20 +242,42 @@ function holdMoneyRequestOnSearch(hash: number, transactionIDList: string[], com
     API.write(WRITE_COMMANDS.HOLD_MONEY_REQUEST_ON_SEARCH, {hash, transactionIDList, comment}, {optimisticData, finallyData});
 }
 
-// this function will be used once https://github.com/Expensify/App/pull/51445 is merged
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-function approveMoneyRequestOnSearch(hash: number, reportIDList: string[]) {
-    const {optimisticData, finallyData} = getOnyxLoadingData(hash);
+function approveMoneyRequestOnSearch(hash: number, reportIDList: string[], transactionID?: string) {
+    const createActionLoadingData = (isLoading: boolean): OnyxUpdate[] => [
+        {
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.SNAPSHOT}${hash}`,
+            value: {
+                data: transactionID
+                    ? {[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]: {isActionLoading: isLoading}}
+                    : (Object.fromEntries(reportIDList.map((reportID) => [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {isActionLoading: isLoading}])) as Partial<SearchReport>),
+            },
+        },
+    ];
+
+    const optimisticData: OnyxUpdate[] = createActionLoadingData(true);
+    const finallyData: OnyxUpdate[] = createActionLoadingData(false);
 
     API.write(WRITE_COMMANDS.APPROVE_MONEY_REQUEST_ON_SEARCH, {hash, reportIDList}, {optimisticData, finallyData});
 }
 
-// this function will be used once https://github.com/Expensify/App/pull/51445 is merged
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-function payMoneyRequestOnSearch(hash: number, paymentType: string, reportsAndAmounts: string) {
-    const {optimisticData, finallyData} = getOnyxLoadingData(hash);
+function payMoneyRequestOnSearch(hash: number, paymentData: PaymentData[], transactionID?: string) {
+    const createActionLoadingData = (isLoading: boolean): OnyxUpdate[] => [
+        {
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.SNAPSHOT}${hash}`,
+            value: {
+                data: transactionID
+                    ? {[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]: {isActionLoading: isLoading}}
+                    : (Object.fromEntries(paymentData.map((item) => [`${ONYXKEYS.COLLECTION.REPORT}${item.reportID}`, {isActionLoading: isLoading}])) as Partial<SearchReport>),
+            },
+        },
+    ];
+
+    const optimisticData: OnyxUpdate[] = createActionLoadingData(true);
+    const finallyData: OnyxUpdate[] = createActionLoadingData(false);
 
-    API.write(WRITE_COMMANDS.PAY_MONEY_REQUEST_ON_SEARCH, {hash, paymentType, reportsAndAmounts}, {optimisticData, finallyData});
+    API.write(WRITE_COMMANDS.PAY_MONEY_REQUEST_ON_SEARCH, {hash, paymentData: JSON.stringify(paymentData)}, {optimisticData, finallyData});
 }
 
 function unholdMoneyRequestOnSearch(hash: number, transactionIDList: string[]) {
@@ -261,4 +361,7 @@ export {
     deleteSavedSearch,
     dismissSavedSearchRenameTooltip,
     showSavedSearchRenameTooltip,
+    payMoneyRequestOnSearch,
+    approveMoneyRequestOnSearch,
+    handleActionButtonPress,
 };
diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts
index 6c62b54dafd4..48b87502089a 100644
--- a/src/types/onyx/Report.ts
+++ b/src/types/onyx/Report.ts
@@ -250,4 +250,4 @@ type ReportCollectionDataSet = CollectionDataSet<typeof ONYXKEYS.COLLECTION.REPO
 
 export default Report;
 
-export type {NotificationPreference, RoomVisibility, WriteCapability, Note, ReportCollectionDataSet, PendingChatMember, Participant, Participants};
+export type {NotificationPreference, RoomVisibility, WriteCapability, Note, ReportCollectionDataSet, PendingChatMember, Participant, Participants, InvoiceReceiver};
diff --git a/src/types/onyx/SearchResults.ts b/src/types/onyx/SearchResults.ts
index 98e3aa66fa00..bd5502e76a5f 100644
--- a/src/types/onyx/SearchResults.ts
+++ b/src/types/onyx/SearchResults.ts
@@ -6,7 +6,10 @@ import type TransactionListItem from '@components/SelectionList/Search/Transacti
 import type {ReportActionListItemType, ReportListItemType, TransactionListItemType} from '@components/SelectionList/types';
 import type CONST from '@src/CONST';
 import type ONYXKEYS from '@src/ONYXKEYS';
+import type {ACHAccount} from './Policy';
+import type {InvoiceReceiver} from './Report';
 import type ReportActionName from './ReportActionName';
+import type ReportNameValuePairs from './ReportNameValuePairs';
 
 /** Types of search data */
 type SearchDataTypes = ValueOf<typeof CONST.SEARCH.DATA_TYPES>;
@@ -79,7 +82,10 @@ type SearchTransactionAction = ValueOf<typeof CONST.SEARCH.ACTION_TYPES>;
 /** Model of report search result */
 type SearchReport = {
     /** The ID of the report */
-    reportID?: string;
+    reportID: string;
+
+    /** ID of the chat report */
+    chatReportID?: string;
 
     /** The name of the report */
     reportName?: string;
@@ -107,6 +113,43 @@ type SearchReport = {
 
     /** The action that can be performed for the report */
     action?: SearchTransactionAction;
+
+    /** The type of chat if this is a chat report */
+    chatType?: ValueOf<typeof CONST.REPORT.CHAT_TYPE>;
+
+    /** Invoice room receiver data */
+    invoiceReceiver?: InvoiceReceiver;
+
+    /** Whether the report has a single transaction */
+    isOneTransactionReport?: boolean;
+
+    /** Whether the report is policyExpenseChat */
+    isPolicyExpenseChat?: boolean;
+
+    /** Whether the report is waiting on a bank account */
+    isWaitingOnBankAccount?: boolean;
+
+    /** If the report contains nonreimbursable expenses, send the nonreimbursable total */
+    nonReimbursableTotal?: number;
+
+    /** Account ID of the report owner */
+    ownerAccountID?: number;
+
+    /** The state that the report is currently in */
+    stateNum?: ValueOf<typeof CONST.REPORT.STATE_NUM>;
+
+    /** The status of the current report */
+    statusNum?: ValueOf<typeof CONST.REPORT.STATUS_NUM>;
+
+    /** For expense reports, this is the total amount requested */
+    unheldTotal?: number;
+
+    /** Whether the report is archived */
+    // eslint-disable-next-line @typescript-eslint/naming-convention
+    private_isArchived?: string;
+
+    /** Whether the action is loading */
+    isActionLoading?: boolean;
 };
 
 /** Model of report action search result */
@@ -142,6 +185,49 @@ type SearchReportAction = {
     reportID: string;
 };
 
+/** Model of policy search result */
+type SearchPolicy = {
+    /** The policy type */
+    type: ValueOf<typeof CONST.POLICY.TYPE>;
+
+    /** Whether the auto reporting is enabled */
+    autoReporting?: boolean;
+
+    /**
+     * The scheduled submit frequency set up on this policy.
+     * Note that manual does not exist in the DB and thus should not exist in Onyx, only as a param for the API.
+     * "manual" really means "immediate" (aka "daily") && harvesting.enabled === false
+     */
+    autoReportingFrequency?: Exclude<ValueOf<typeof CONST.POLICY.AUTO_REPORTING_FREQUENCIES>, typeof CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL>;
+
+    /** The approval mode set up on this policy */
+    approvalMode?: ValueOf<typeof CONST.POLICY.APPROVAL_MODE>;
+
+    /** The reimbursement choice for policy */
+    reimbursementChoice?: ValueOf<typeof CONST.POLICY.REIMBURSEMENT_CHOICES>;
+
+    /** The maximum report total allowed to trigger auto reimbursement */
+    autoReimbursementLimit?: number;
+
+    /** The verified bank account linked to the policy */
+    achAccount?: ACHAccount;
+
+    /** The current user's role in the policy */
+    role: ValueOf<typeof CONST.POLICY.ROLE>;
+
+    /** The employee list of the policy */
+    employeeList?: Record<string, Record<string, string>>;
+
+    /** Detailed settings for the autoReimbursement */
+    autoReimbursement?: {
+        /** The auto reimbursement limit */
+        limit: number;
+    };
+
+    /** Whether the self approval or submitting is enabled */
+    preventSelfApproval?: boolean;
+};
+
 /** Model of transaction search result */
 type SearchTransaction = {
     /** The ID of the transaction */
@@ -251,6 +337,9 @@ type SearchTransaction = {
 
     /** Whether the transaction report has only a single transaction */
     isFromOneTransactionReport?: boolean;
+
+    /** Whether the action is loading */
+    isActionLoading?: boolean;
 };
 
 /** Types of searchable transactions */
@@ -272,7 +361,9 @@ type SearchResults = {
     data: PrefixedRecord<typeof ONYXKEYS.COLLECTION.TRANSACTION, SearchTransaction> &
         Record<typeof ONYXKEYS.PERSONAL_DETAILS_LIST, Record<string, SearchPersonalDetails>> &
         PrefixedRecord<typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS, Record<string, SearchReportAction>> &
-        PrefixedRecord<typeof ONYXKEYS.COLLECTION.REPORT, SearchReport>;
+        PrefixedRecord<typeof ONYXKEYS.COLLECTION.REPORT, SearchReport> &
+        PrefixedRecord<typeof ONYXKEYS.COLLECTION.POLICY, SearchPolicy> &
+        PrefixedRecord<typeof ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, ReportNameValuePairs>;
 
     /** Whether search data is being fetched from server */
     isLoading?: boolean;
@@ -280,4 +371,15 @@ type SearchResults = {
 
 export default SearchResults;
 
-export type {ListItemType, ListItemDataType, SearchTransaction, SearchTransactionType, SearchTransactionAction, SearchPersonalDetails, SearchDataTypes, SearchReport, SearchReportAction};
+export type {
+    ListItemType,
+    ListItemDataType,
+    SearchTransaction,
+    SearchTransactionType,
+    SearchTransactionAction,
+    SearchPersonalDetails,
+    SearchDataTypes,
+    SearchReport,
+    SearchReportAction,
+    SearchPolicy,
+};
