diff --git a/ee/app/assets/javascripts/billings/seat_usage/components/subscription_seats.vue b/ee/app/assets/javascripts/billings/seat_usage/components/subscription_seats.vue
index 3d7ee04eec42da86e48c8e81729e98b95e6b79bc..da998e66fddaea7adb195be3aa04671d22f03456 100644
--- a/ee/app/assets/javascripts/billings/seat_usage/components/subscription_seats.vue
+++ b/ee/app/assets/javascripts/billings/seat_usage/components/subscription_seats.vue
@@ -67,7 +67,7 @@ export default {
   },
   avatarSize: AVATAR_SIZE,
   emailNotVisibleTooltipText: s__(
-    'Billing|An email address is only visible for users managed through Group Managed Accounts.',
+    'Billing|An email address is only visible for users with public emails.',
   ),
 };
 </script>
diff --git a/ee/changelogs/unreleased/vij-billable-members-entity.yml b/ee/changelogs/unreleased/vij-billable-members-entity.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7e40437b77be81feb0b9710d0b2651d7e874704f
--- /dev/null
+++ b/ee/changelogs/unreleased/vij-billable-members-entity.yml
@@ -0,0 +1,5 @@
+---
+title: Display public emails for billable members
+merge_request: 50290
+author:
+type: changed
diff --git a/ee/lib/ee/api/entities/billable_member.rb b/ee/lib/ee/api/entities/billable_member.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8ccb57e9027e0fd62f762b6b8e4a7a2107e14bb9
--- /dev/null
+++ b/ee/lib/ee/api/entities/billable_member.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module EE
+  module API
+    module Entities
+      class BillableMember < ::API::Entities::UserBasic
+        expose :public_email, as: :email
+      end
+    end
+  end
+end
diff --git a/ee/lib/ee/api/members.rb b/ee/lib/ee/api/members.rb
index 8514440fa36a42b7adf0b747401c8b9f5f476645..b2090d4e68045023ce6b03235c99df244faa1622 100644
--- a/ee/lib/ee/api/members.rb
+++ b/ee/lib/ee/api/members.rb
@@ -63,7 +63,7 @@ module Members
                                     order_by: sorting).execute
             )
 
-            present users, with: ::API::Entities::UserBasic, current_user: current_user
+            present users, with: ::EE::API::Entities::BillableMember, current_user: current_user
           end
         end
       end
diff --git a/ee/spec/frontend/billings/seat_usage/components/__snapshots__/subscription_seats_spec.js.snap b/ee/spec/frontend/billings/seat_usage/components/__snapshots__/subscription_seats_spec.js.snap
index 68d0f38d03dc4ed24e2fa41732b900c081eb71ec..1b245078cd53421845d7e2d0cf7162cac6b6a1e5 100644
--- a/ee/spec/frontend/billings/seat_usage/components/__snapshots__/subscription_seats_spec.js.snap
+++ b/ee/spec/frontend/billings/seat_usage/components/__snapshots__/subscription_seats_spec.js.snap
@@ -34,7 +34,7 @@ Array [
   },
   Object {
     "email": "Private",
-    "tooltip": "An email address is only visible for users managed through Group Managed Accounts.",
+    "tooltip": "An email address is only visible for users with public emails.",
     "user": Object {
       "avatarLabeled": Object {
         "size": "32",
diff --git a/ee/spec/lib/ee/api/entities/billable_member_spec.rb b/ee/spec/lib/ee/api/entities/billable_member_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..23b3a3c9f3559b490310ea29b729d00d355cc387
--- /dev/null
+++ b/ee/spec/lib/ee/api/entities/billable_member_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::EE::API::Entities::BillableMember do
+  let(:member) { build(:user, public_email: public_email, email: 'private@email.com') }
+
+  subject(:entity_representation) { described_class.new(member).as_json }
+
+  context 'when the user has a public_email assigned' do
+    let(:public_email) { 'public@email.com' }
+
+    it 'exposes public_email instead of email' do
+      aggregate_failures do
+        expect(entity_representation.keys).to include(:email)
+        expect(entity_representation[:email]).to eq public_email
+        expect(entity_representation[:email]).not_to eq member.email
+      end
+    end
+  end
+
+  context 'when the user has no public_email assigned' do
+    let(:public_email) { nil }
+
+    it 'returns a nil value for email' do
+      aggregate_failures do
+        expect(entity_representation.keys).to include(:email)
+        expect(entity_representation[:email]).to be nil
+      end
+    end
+  end
+end
diff --git a/ee/spec/requests/api/members_spec.rb b/ee/spec/requests/api/members_spec.rb
index b7cd58075b141fb70ec9d587f93ef047171c44fe..223c2d514273a9d64205c6192a727ab1afc247cc 100644
--- a/ee/spec/requests/api/members_spec.rb
+++ b/ee/spec/requests/api/members_spec.rb
@@ -484,14 +484,20 @@
         group.add_owner(owner)
       end
 
-      include_context "group managed account with group members"
+      include_context 'group managed account with group members'
 
-      it_behaves_like 'members response with exposed emails' do
-        let(:emails) { gma_member.email }
+      context 'when members have a public_email' do
+        before do
+          allow_next_found_instance_of(User) do |instance|
+            allow(instance).to receive(:public_email).and_return('public@email.com')
+          end
+        end
+
+        it { is_expected.to include(a_hash_including('email' => 'public@email.com')) }
       end
 
-      it_behaves_like 'members response with hidden emails' do
-        let(:emails) { member.email }
+      context 'when members have no public_email' do
+        it { is_expected.to include(a_hash_including('email' => '')) }
       end
     end
   end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 21e804e4155926f7ee99714db163b9a5a164f34c..815833b3d36701e9aa950c5c0d42f7c3c451ec52 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4478,7 +4478,7 @@ msgstr ""
 msgid "BillingPlan|Upgrade"
 msgstr ""
 
-msgid "Billing|An email address is only visible for users managed through Group Managed Accounts."
+msgid "Billing|An email address is only visible for users with public emails."
 msgstr ""
 
 msgid "Billing|An error occurred while loading billable members list"