diff --git a/compendium_v2/routes/api.py b/compendium_v2/routes/api.py
index 3707e116df9f7754e16feb9f218b3113986c8fe8..97eac240383e1478f546bece6b057aab899d8c91 100644
--- a/compendium_v2/routes/api.py
+++ b/compendium_v2/routes/api.py
@@ -18,9 +18,10 @@ import time
 from flask import Blueprint, jsonify
 
 from compendium_v2.routes import common
+from compendium_v2.routes.data_entry import routes as data_entry_routes
 
 routes = Blueprint('compendium-v2-api', __name__)
-
+routes.register_blueprint(data_entry_routes, url_prefix='/data-entries/')
 
 THING_LIST_SCHEMA = {
     '$schema': 'http://json-schema.org/draft-07/schema#',
diff --git a/compendium_v2/routes/data_entry.py b/compendium_v2/routes/data_entry.py
new file mode 100644
index 0000000000000000000000000000000000000000..c2a03b59dd2505ce3f94fa16636d6db7ca42e036
--- /dev/null
+++ b/compendium_v2/routes/data_entry.py
@@ -0,0 +1,228 @@
+from typing import Any
+
+from flask import Blueprint, abort, jsonify, url_for
+
+from compendium_v2.db import db
+from compendium_v2.db.models import (DataEntryItem, DataEntrySection,
+                                     DataSourceType)
+from compendium_v2.db.survey import get_budget_by_year
+from compendium_v2.routes import common
+
+routes = Blueprint('data-entry', __name__)
+
+col_pal = ['#fd7f6f', '#7eb0d5', '#b2e061',
+           '#bd7ebe', '#ffb55a', '#ffee65',
+           '#beb9db', '#fdcce5', '#8bd3c7']
+
+DATA_ENTRY_SECTIONS_LIST_SCHEMA = {
+    '$schema': 'http://json-schema.org/draft-07/schema#',
+
+    'definitions': {
+        'section': {
+            'type': 'object',
+            'properties': {
+                'id': {'type': 'number'},
+                'name': {'type': 'string'},
+                'description': {'type': 'string'},
+                'url': {'type': 'string'}
+            },
+            'required': ['id', 'name', 'description', 'url'],
+            'additionalProperties': False
+        }
+    },
+
+    'type': 'array',
+    'items': {'$ref': '#/definitions/section'}
+}
+
+DATA_ENTRY_SECTIONS_DETAIL_SCHEMA = {
+    '$schema': 'http://json-schema.org/draft-07/schema#',
+
+    'definitions': {
+        'item': {
+            'type': 'object',
+            'properties': {
+                'id': {'type': 'number'},
+                'title': {'type': 'string'},
+                'url': {'type': 'string'}
+            },
+            'required': ['id', 'title', 'url'],
+            'additionalProperties': False
+        }
+    },
+
+    'type': 'object',
+    'properties': {
+        'name': {'type': 'string'},
+        'description': {'type': 'string'},
+        'items': {
+            'type': 'array',
+            'items': {'$ref': '#/definitions/item'}
+        }
+    },
+    'required': ['name', 'description', 'items'],
+    'additionalProperties': False
+}
+
+DATA_ENTRY_ITEM_DETAIL_SCHEMA = {
+    '$schema': 'http://json-schema.org/draft-07/schema#',
+
+    'definitions': {
+        'settings': {
+            'type': 'object',
+            'properties': {
+
+            },
+            'additionalProperties': False
+        },
+        'dataset': {
+            'type': 'object',
+            'properties': {
+                'data': {
+                    'type': 'array',
+                    'items': {'type': ['number', 'null']}
+                },
+                'backgroundColor': {
+                    'type': 'string'
+                },
+                'label': {
+                    'type': 'string'
+                }
+            }
+        },
+        'data': {
+            'type': 'object',
+            'properties': {
+                'labels': {
+                    'type': 'array',
+                    'items': {'type': 'string'}},
+                'datasets': {
+                    'type': 'array',
+                    'items': {
+                        '$ref': '#/definitions/dataset'
+                    }
+                }
+            },
+            'required': ['labels', 'datasets'],
+            'additionalProperties': False
+        }
+    },
+
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'number'},
+        'title': {'type': 'string'},
+        'description': {'type': 'string'},
+        'settings': {
+            'type': 'object',
+            '$ref': '#/definitions/settings'
+        },
+        'data': {
+            'type': 'object',
+            '$ref': '#/definitions/data'
+        }
+    },
+    'required': ['id', 'title', 'description', 'settings', 'data'],
+    'additionalProperties': False
+}
+
+
+def load_data(data_source_id: DataSourceType) -> Any:
+    response_data = {}
+    if data_source_id == DataSourceType.BUDGETS_BY_YEAR:
+        response_data = get_budget_by_year()
+
+    # Enrich response data
+    # Add the colour formatting
+    for index, dataset in enumerate(response_data['datasets']):
+        dataset['backgroundColor'] = col_pal[index % len(col_pal)]
+
+    return response_data
+
+
+@routes.route('/item/<int:item_id>', methods=['GET'])
+@common.require_accepts_json
+def item_view(item_id):
+    """
+    handler for /api/data-entries/item/<item_id> requests
+
+    response will be formatted as:
+
+    .. asjson::
+        compendium_v2.routes.data_entry.DATA_ENTRY_ITEM_DETAIL_SCHEMA
+
+    :return:
+    """
+    de_item = db.get_or_404(DataEntryItem, item_id)
+    # Confirm that only active sections can be loaded
+    if not de_item.is_active:
+        return abort(404)
+
+    return jsonify({
+        'id': de_item.id,
+        'title': de_item.title,
+        'description': de_item.description,
+        'settings': {},
+        'data': load_data(de_item.data_source)
+    })
+
+
+@routes.route('/sections/<int:section_id>', methods=['GET'])
+@common.require_accepts_json
+def section_view(section_id):
+    """
+    handler for /api/data-entries/sections/<section_id> requests
+
+    response will be formatted as:
+
+    .. asjson::
+        compendium_v2.routes.data_entry.DATA_ENTRY_SECTIONS_DETAIL_SCHEMA
+
+    :return:
+    """
+    de_section = db.get_or_404(DataEntrySection, section_id)
+    # Confirm that only active sections can be loaded
+    if not de_section.is_active:
+        return abort(404)
+
+    items = [
+        {
+            'id': item.id,
+            'url': url_for('.item_view', item_id=item.id),
+            'title': item.title
+        } for item in de_section.items if item.is_active
+    ]
+    response_section = {
+        'name': de_section.name,
+        'description': de_section.description,
+        'items': items
+    }
+    return jsonify(response_section)
+
+
+@routes.route('/sections', methods=['GET'])
+@common.require_accepts_json
+def sections_view():
+    """
+    handler for /api/data-entries/sections requests
+
+    response will be formatted as:
+
+    .. asjson::
+        compendium_v2.routes.data_entry.DATA_ENTRY_SECTIONS_LIST_SCHEMA
+
+    :return:
+    """
+    model_sections = db.session.execute(
+        db.select(DataEntrySection)
+        .filter(DataEntrySection.is_active)
+        .order_by(DataEntrySection.sort_order)
+    ).scalars()
+
+    de_sections = [{'id': de_section.id,
+                    'name': de_section.name,
+                    'description': de_section.description,
+                    'url': url_for('.section_view', section_id=de_section.id)
+                    } for de_section in model_sections]
+
+    return jsonify(list(de_sections))
diff --git a/config-example.json b/config-example.json
index 03c0451aa13163afe7ee0cbea79c32db9106b1c7..5a9ddebf6d02d12a1f3d9e7036d22ea85fc98ba3 100644
--- a/config-example.json
+++ b/config-example.json
@@ -1,3 +1,3 @@
 {
-  "SQLALCHEMY_DATABASE_URI": "psql://username:password@hostname/db_name"
+  "SQLALCHEMY_DATABASE_URI": "postgresql://compendium_v2:password@localhost/compendium_v2"
 }
diff --git a/test/test_routes.py b/test/test_routes.py
index 2e42f3e438e6eddb5215e25af7e343d605bb9b4e..5d2d12d62d5ce4f87f07cdad3cbb1e158d4cb96a 100644
--- a/test/test_routes.py
+++ b/test/test_routes.py
@@ -4,6 +4,9 @@ import jsonschema
 import pytest
 
 from compendium_v2.routes.api import THING_LIST_SCHEMA
+from compendium_v2.routes.data_entry import (DATA_ENTRY_ITEM_DETAIL_SCHEMA,
+                                             DATA_ENTRY_SECTIONS_DETAIL_SCHEMA,
+                                             DATA_ENTRY_SECTIONS_LIST_SCHEMA)
 from compendium_v2.routes.default import VERSION_SCHEMA
 
 
@@ -18,7 +21,6 @@ def test_bad_accept(endpoint, client):
 
 
 def test_version_request(client):
-
     rv = client.post(
         'version',
         headers={'Accept': ['application/json']})
@@ -28,10 +30,36 @@ def test_version_request(client):
 
 
 def test_things(client):
-
     rv = client.post(
         'api/things',
         headers={'Accept': ['application/json']})
     assert rv.status_code == 200
     result = json.loads(rv.data.decode('utf-8'))
     jsonschema.validate(result, THING_LIST_SCHEMA)
+
+
+def test_api_data_entry_sections(client):
+    rv = client.get(
+        'api/data-entries/sections',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    jsonschema.validate(result, DATA_ENTRY_SECTIONS_LIST_SCHEMA)
+
+
+def test_api_data_entry_sections_detail(client):
+    rv = client.get(
+        'api/data-entries/sections/1',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    jsonschema.validate(result, DATA_ENTRY_SECTIONS_DETAIL_SCHEMA)
+
+
+def test_api_data_entry_item_detail(client):
+    rv = client.get(
+        'api/data-entries/item/1',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    jsonschema.validate(result, DATA_ENTRY_ITEM_DETAIL_SCHEMA)