diff --git a/api/api.py b/api/api.py
index 4c4d5b5419cfef74d0141a830e06049a691bb14c..ac06191e560804f77dedcf057526eb14d2751136 100644
--- a/api/api.py
+++ b/api/api.py
@@ -134,11 +134,13 @@ routes = [
 
 
 def dispatcher(router, request, response):
-    rv = router.default_dispatcher(request, response)
-    if rv is not None:
-        response.write(json.dumps(rv, default=util.custom_json_serializer))
-        response.headers['Content-Type'] = 'application/json; charset=utf-8'
-
+    try:
+        rv = router.default_dispatcher(request, response)
+        if rv is not None:
+            response.write(json.dumps(rv, default=util.custom_json_serializer))
+            response.headers['Content-Type'] = 'application/json; charset=utf-8'
+    except (webapp2.exc.HTTPNotFound, webapp2.exc.HTTPMethodNotAllowed) as e:
+        util.send_json_http_exception(response, str(e), e.code)
 
 def app_factory(*_, **__):
     # don't use config.get_item() as we don't want to require the database at startup
diff --git a/api/base.py b/api/base.py
index 2e3ee02d7c703b4bf67ef9a9ff0045de56859978..36056990c77aa2764a2eacdb99617aa4d7edf653 100644
--- a/api/base.py
+++ b/api/base.py
@@ -7,6 +7,7 @@ import requests
 import urlparse
 import jsonschema
 
+from . import util
 from . import config
 
 log = config.log
@@ -119,6 +120,18 @@ class RequestHandler(webapp2.RequestHandler):
     def get_param(self, param, default=None):
         return self.request.GET.get(param, default)
 
+    def handle_exception(self, exception, debug):
+        # Log the error.
+        log.error(exception)
+
+        # If the exception is a HTTPException, use its error code.
+        # Otherwise use a generic 500 error code.
+        if isinstance(exception, webapp2.HTTPException):
+            code = exception.code
+        else:
+            code = 500
+        util.send_json_http_exception(self.response, str(exception), code)
+
     def dispatch(self):
         """dispatching and request forwarding"""
         site_id = config.get_item('site', 'id')
@@ -183,3 +196,4 @@ class RequestHandler(webapp2.RequestHandler):
         json_schema = copy.deepcopy(self.json_schema)
         json_schema['properties'].update(updates)
         return json_schema
+
diff --git a/api/util.py b/api/util.py
index 9d3bd9c997c206abcab92655d28c338e71ba0087..13e374d3bcb8d7bbd9b63e01941f85fc9372100c 100644
--- a/api/util.py
+++ b/api/util.py
@@ -1,4 +1,5 @@
 import os
+import json
 import pytz
 import uuid
 import datetime
@@ -108,6 +109,15 @@ def custom_json_serializer(obj):
         return pytz.timezone('UTC').localize(obj).isoformat()
     raise TypeError(repr(obj) + " is not JSON serializable")
 
+def send_json_http_exception(response, message, code):
+    response.set_status(code)
+    content = json.dumps({
+        'message': message,
+        'status_code': code
+    })
+    response.headers['Content-Type'] = 'application/json; charset=utf-8'
+    response.write(content)
+
 class Enum(baseEnum.Enum):
     # Enum strings are prefixed by their class: "Category.classifier".
     # This overrides that behaviour and removes the prefix.