diff --git a/app/templates/admin/analytics.jade b/app/templates/admin/analytics.jade
index 741bc5971..ca900068a 100644
--- a/app/templates/admin/analytics.jade
+++ b/app/templates/admin/analytics.jade
@@ -145,6 +145,34 @@ block content
         else
           div Loading ...
 
+        #school-sales
+          h3 School Sales
+          if view.schoolSales
+            table.table.table-striped.table-condensed
+              tr
+                th Amount
+                th(style='min-width:85px;') Created
+                th PaymentID
+                th PrepaidID
+                th Description
+                th Email
+                th School
+              each val, i in view.schoolSales
+                tr
+                  td $#{Math.round(val.amount / 100, 2)}
+                  td= new Date(val.created).toISOString().substring(0, 10)
+                  td= val._id
+                  td= val.prepaidID
+                  td= val.description
+                  if val.user
+                    td= val.user.emailLower
+                    td= val.user.schoolName
+                  else
+                    td
+                    td
+          else
+            div Loading ...
+
         #school-counts
           h3 School Counts
           .small Only including schools with #{view.minSchoolCount}+ counts
diff --git a/app/views/admin/AnalyticsView.coffee b/app/views/admin/AnalyticsView.coffee
index 66a4e7111..9b9a6ccb7 100644
--- a/app/views/admin/AnalyticsView.coffee
+++ b/app/views/admin/AnalyticsView.coffee
@@ -3,6 +3,7 @@ Course = require 'models/Course'
 CourseInstance = require 'models/CourseInstance'
 require 'vendor/d3'
 d3Utils = require 'core/d3_utils'
+Payment = require 'models/Payment'
 RootView = require 'views/core/RootView'
 template = require 'templates/admin/analytics'
 utils = require 'core/utils'
@@ -149,6 +150,16 @@ module.exports = class AnalyticsView extends RootView
         @renderSelectors?('#school-counts')
     }, 0).load()
 
+    @supermodel.addRequestResource({
+      url: '/db/payment/-/school_sales'
+      success: (@schoolSales) =>
+        @schoolSales?.sort (a, b) ->
+          return -1 if a.created > b.created
+          return 0 if a.created is b.created
+          1
+        @renderSelectors?('#school-sales')
+    }, 0).load()
+
     @supermodel.addRequestResource({
       url: '/db/prepaid/-/courses'
       method: 'POST'
diff --git a/server/payments/payment_handler.coffee b/server/payments/payment_handler.coffee
index fd5da1677..01d608cf5 100644
--- a/server/payments/payment_handler.coffee
+++ b/server/payments/payment_handler.coffee
@@ -1,4 +1,5 @@
 Payment = require './Payment'
+Prepaid = require '../prepaids/Prepaid'
 Product = require '../models/Product'
 User = require '../users/User'
 Handler = require '../commons/Handler'
@@ -27,6 +28,11 @@ PaymentHandler = class PaymentHandler extends Handler
       res.send(payments)
     )
 
+  getByRelationship: (req, res, args...) ->
+    relationship = args[1]
+    return @getSchoolSalesAPI(req, res) if relationship is 'school_sales'
+    super arguments...
+
   logPaymentError: (req, msg) ->
     console.warn "Payment Error: #{req.user.get('slug')} (#{req.user._id}): '#{msg}'"
 
@@ -37,6 +43,43 @@ PaymentHandler = class PaymentHandler extends Handler
     payment.set 'created', new Date().toISOString()
     payment
 
+  getSchoolSalesAPI: (req, res, code) ->
+    return @sendSuccess(res, []) unless req.user?.isAdmin()
+    userIDs = [];
+    Payment.find({}, {amount: 1, created: 1, description: 1, prepaidID: 1, productID: 1, purchaser: 1, service: 1}).exec (err, payments) =>
+      return @sendDatabaseError(res, err) if err
+      schoolSales = []
+      prepaidIDs = []
+      prepaidPaymentMap = {}
+      for payment in payments
+        continue unless payment.get('amount')? and payment.get('amount') > 0
+        unless created = payment.get('created')
+          created = payment.get('_id').getTimestamp()
+        description = payment.get('description') ? ''
+        if prepaidID = payment.get('prepaidID')
+          unless prepaidPaymentMap[prepaidID.valueOf()]
+            prepaidPaymentMap[prepaidID.valueOf()] = {_id: payment.get('_id').valueOf(), amount: payment.get('amount'), created: created, description: description, userID: payment.get('purchaser').valueOf(), prepaidID: prepaidID.valueOf()}
+            prepaidIDs.push(prepaidID)
+            userIDs.push(payment.get('purchaser'))
+        else if payment.get('productID') is 'custom' or payment.get('service') is 'external' or payment.get('service') is 'invoice'
+          schoolSales.push({_id: payment.get('_id').valueOf(), amount: payment.get('amount'), created: created, description: description, userID: payment.get('purchaser').valueOf()})
+          userIDs.push(payment.get('purchaser'))
+
+      Prepaid.find({$and: [{_id: {$in: prepaidIDs}}, {type: 'course'}]}, {_id: 1}).exec (err, prepaids) =>
+        return @sendDatabaseError(res, err) if err
+        for prepaid in prepaids
+          schoolSales.push(prepaidPaymentMap[prepaid.get('_id').valueOf()])
+
+        User.find({_id: {$in: userIDs}}).exec (err, users) =>
+          return @sendDatabaseError(res, err) if err
+          userMap = {}
+          for user in users
+            userMap[user.get('_id').valueOf()] = user
+          for schoolSale in schoolSales
+            schoolSale.user = userMap[schoolSale.userID]?.toObject()
+
+          @sendSuccess(res, schoolSales)
+
   post: (req, res, pathName) ->
     if pathName is 'check-stripe-charges'
       return @checkStripeCharges(req, res)