diff --git a/app/controllers/custom_data_controller.rb b/app/controllers/custom_data_controller.rb
new file mode 100644
index 00000000000..18530c2e69a
--- /dev/null
+++ b/app/controllers/custom_data_controller.rb
@@ -0,0 +1,411 @@
+#
+# Copyright (C) 2014 Instructure, Inc.
+#
+# This file is part of Canvas.
+#
+# Canvas is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, version 3 of the License.
+#
+# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program. If not, see .
+#
+
+# @API Users
+class CustomDataController < ApplicationController
+ before_filter :require_namespace, :get_scope, :get_context
+ before_filter :require_custom_data, :except => :set_data
+
+ # @API Store custom data
+ # @beta
+ # Store arbitrary user data as JSON.
+ #
+ # Arbitrary JSON data can be stored for a User.
+ # A typical scenario would be an external site/service that registers users in Canvas
+ # and wants to capture additional info about them. The part of the URL that follows
+ # +/custom_data/+ defines the scope of the request, and it reflects the structure of
+ # the JSON data to be stored or retrieved.
+ #
+ # A namespace parameter, +ns+, is used to prevent custom_data collisions between
+ # different apps. This parameter is required for all custom_data requests.
+ #
+ # A request with Content-Type multipart/form-data or Content-Type
+ # application/x-www-form-urlencoded can only be used to store strings.
+ #
+ # Example PUT with multipart/form-data data:
+ # curl 'https://