diff --git a/common/djangoapps/user_api/models.py b/common/djangoapps/user_api/models.py
index 36ed30eddc3b8921be36d214c05d40b5a37fb234..76b8cd5053f4f0ce349962ba66ab7047b80d18fa 100644
--- a/common/djangoapps/user_api/models.py
+++ b/common/djangoapps/user_api/models.py
@@ -1,11 +1,13 @@
 from django.contrib.auth.models import User
+from django.core.validators import RegexValidator
 from django.db import models
 
 
 class UserPreference(models.Model):
     """A user's preference, stored as generic text to be processed by client"""
-    user = models.ForeignKey(User, db_index=True, related_name="+")
-    key = models.CharField(max_length=255, db_index=True)
+    KEY_REGEX = r"[-_a-zA-Z0-9]+"
+    user = models.ForeignKey(User, db_index=True, related_name="preferences")
+    key = models.CharField(max_length=255, db_index=True, validators=[RegexValidator(KEY_REGEX)])
     value = models.TextField()
 
     class Meta:  # pylint: disable=missing-docstring
diff --git a/common/djangoapps/user_api/serializers.py b/common/djangoapps/user_api/serializers.py
index 8822817933330d7d221c49f62c5ee315576c433d..edd9b1e7ccb8fc08759060c6252f0680a0681885 100644
--- a/common/djangoapps/user_api/serializers.py
+++ b/common/djangoapps/user_api/serializers.py
@@ -6,15 +6,19 @@ from user_api.models import UserPreference
 
 class UserSerializer(serializers.HyperlinkedModelSerializer):
     name = serializers.SerializerMethodField("get_name")
+    preferences = serializers.SerializerMethodField("get_preferences")
 
     def get_name(self, user):
         profile = UserProfile.objects.get(user=user)
         return profile.name
 
+    def get_preferences(self, user):
+        return dict([(pref.key, pref.value) for pref in user.preferences.all()])
+
     class Meta:
         model = User
         # This list is the minimal set required by the notification service
-        fields = ("id", "email", "name", "username")
+        fields = ("id", "email", "name", "username", "preferences")
         read_only_fields = ("id", "email", "username")
 
 
diff --git a/common/djangoapps/user_api/tests/test_views.py b/common/djangoapps/user_api/tests/test_views.py
index 4143a467d796c28f1ee271ba25f620a9273e6a18..d187b21b9466ac87323a875cbf0ff0397e34edee 100644
--- a/common/djangoapps/user_api/tests/test_views.py
+++ b/common/djangoapps/user_api/tests/test_views.py
@@ -66,7 +66,11 @@ class ApiTestCase(TestCase):
 
     def assertUserIsValid(self, user):
         """Assert that the given user result is valid"""
-        self.assertItemsEqual(user.keys(), ["email", "id", "name", "username", "url"])
+        self.assertItemsEqual(user.keys(), ["email", "id", "name", "username", "preferences", "url"])
+        self.assertItemsEqual(
+            user["preferences"].items(),
+            [(pref.key, pref.value) for pref in self.prefs if pref.user.id == user["id"]]
+        )
         self.assertSelfReferential(user)
 
     def assertPrefIsValid(self, pref):
@@ -221,6 +225,11 @@ class UserViewSetTest(UserApiTestCase):
                 "id": user.id,
                 "name": user.profile.name,
                 "username": user.username,
+                "preferences": dict([
+                    (user_pref.key, user_pref.value)
+                    for user_pref in self.prefs
+                    if user_pref.user == user
+                ]),
                 "url": uri
             }
         )
@@ -352,6 +361,11 @@ class UserPreferenceViewSetTest(UserApiTestCase):
                     "id": pref.user.id,
                     "name": pref.user.profile.name,
                     "username": pref.user.username,
+                    "preferences": dict([
+                        (user_pref.key, user_pref.value)
+                        for user_pref in self.prefs
+                        if user_pref.user == pref.user
+                    ]),
                     "url": self.get_uri_for_user(pref.user),
                 },
                 "key": pref.key,
@@ -359,3 +373,59 @@ class UserPreferenceViewSetTest(UserApiTestCase):
                 "url": uri,
             }
         )
+
+
+class PreferenceUsersListViewTest(UserApiTestCase):
+    LIST_URI = "/user_api/v1/preferences/key0/users/"
+
+    def test_options(self):
+        self.assertAllowedMethods(self.LIST_URI, ["OPTIONS", "GET", "HEAD"])
+
+    def test_put_not_allowed(self):
+        self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.LIST_URI))
+
+    def test_patch_not_allowed(self):
+        raise SkipTest("Django 1.4's test client does not support patch")
+
+    def test_delete_not_allowed(self):
+        self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.LIST_URI))
+
+    def test_unauthorized(self):
+        self.assertHttpForbidden(self.client.get(self.LIST_URI))
+
+    @override_settings(DEBUG=True)
+    @override_settings(EDX_API_KEY=None)
+    def test_debug_auth(self):
+        self.assertHttpOK(self.client.get(self.LIST_URI))
+
+    def test_get_basic(self):
+        result = self.get_json(self.LIST_URI)
+        self.assertEqual(result["count"], 2)
+        self.assertIsNone(result["next"])
+        self.assertIsNone(result["previous"])
+        users = result["results"]
+        self.assertEqual(len(users), 2)
+        for user in users:
+            self.assertUserIsValid(user)
+
+    def test_get_pagination(self):
+        first_page = self.get_json(self.LIST_URI, data={"page_size": 1})
+        self.assertEqual(first_page["count"], 2)
+        first_page_next_uri = first_page["next"]
+        self.assertIsNone(first_page["previous"])
+        first_page_users = first_page["results"]
+        self.assertEqual(len(first_page_users), 1)
+
+        second_page = self.get_json(first_page_next_uri)
+        self.assertEqual(second_page["count"], 2)
+        self.assertIsNone(second_page["next"])
+        second_page_prev_uri = second_page["previous"]
+        second_page_users = second_page["results"]
+        self.assertEqual(len(second_page_users), 1)
+
+        self.assertEqual(self.get_json(second_page_prev_uri), first_page)
+
+        for user in first_page_users + second_page_users:
+            self.assertUserIsValid(user)
+        all_user_uris = [user["url"] for user in first_page_users + second_page_users]
+        self.assertEqual(len(set(all_user_uris)), 2)
diff --git a/common/djangoapps/user_api/urls.py b/common/djangoapps/user_api/urls.py
index de24b67f02de0c61444b64456687240a91f34fc8..c9d86c96207f1529806b184a7f06fd477d398dd4 100644
--- a/common/djangoapps/user_api/urls.py
+++ b/common/djangoapps/user_api/urls.py
@@ -1,6 +1,7 @@
 from django.conf.urls import include, patterns, url
 from rest_framework import routers
 from user_api import views as user_api_views
+from user_api.models import UserPreference
 
 
 user_api_router = routers.DefaultRouter()
@@ -9,4 +10,8 @@ user_api_router.register(r'user_prefs', user_api_views.UserPreferenceViewSet)
 urlpatterns = patterns(
     '',
     url(r'^v1/', include(user_api_router.urls)),
+    url(
+        r'^v1/preferences/(?P<pref_key>{})/users/$'.format(UserPreference.KEY_REGEX),
+        user_api_views.PreferenceUsersListView.as_view()
+    ),
 )
diff --git a/common/djangoapps/user_api/views.py b/common/djangoapps/user_api/views.py
index 23066920d8e320956da14ff523604caf892b60f2..53bb99b38c37406a48769e020cfc7e7e17618ca6 100644
--- a/common/djangoapps/user_api/views.py
+++ b/common/djangoapps/user_api/views.py
@@ -2,6 +2,7 @@ from django.conf import settings
 from django.contrib.auth.models import User
 from rest_framework import authentication
 from rest_framework import filters
+from rest_framework import generics
 from rest_framework import permissions
 from rest_framework import viewsets
 from user_api.serializers import UserSerializer, UserPreferenceSerializer
@@ -28,7 +29,7 @@ class ApiKeyHeaderPermission(permissions.BasePermission):
 class UserViewSet(viewsets.ReadOnlyModelViewSet):
     authentication_classes = (authentication.SessionAuthentication,)
     permission_classes = (ApiKeyHeaderPermission,)
-    queryset = User.objects.all()
+    queryset = User.objects.all().prefetch_related("preferences")
     serializer_class = UserSerializer
     paginate_by = 10
     paginate_by_param = "page_size"
@@ -43,3 +44,14 @@ class UserPreferenceViewSet(viewsets.ReadOnlyModelViewSet):
     serializer_class = UserPreferenceSerializer
     paginate_by = 10
     paginate_by_param = "page_size"
+
+
+class PreferenceUsersListView(generics.ListAPIView):
+    authentication_classes = (authentication.SessionAuthentication,)
+    permission_classes = (ApiKeyHeaderPermission,)
+    serializer_class = UserSerializer
+    paginate_by = 10
+    paginate_by_param = "page_size"
+
+    def get_queryset(self):
+        return User.objects.filter(preferences__key=self.kwargs["pref_key"]).prefetch_related("preferences")