diff --git a/geomagio/api/db/create.py b/geomagio/api/db/create.py
index 0ccc0a97a0d0ce5161a3850dfc0d8588ada2fdfd..facf86081eb7318b6f85c7a68992362a02891966 100644
--- a/geomagio/api/db/create.py
+++ b/geomagio/api/db/create.py
@@ -3,6 +3,7 @@ import sqlalchemy
 from .common import database, sqlalchemy_metadata
 
 # register models with sqlalchemy_metadata by importing
+from .metadata_history import metadata_history
 from .metadata_table import metadata
 from .session_table import session
 
diff --git a/geomagio/api/db/metadata_history.py b/geomagio/api/db/metadata_history.py
new file mode 100644
index 0000000000000000000000000000000000000000..2cb3a6a2a78c4b83683d95c62c694971765bc3a1
--- /dev/null
+++ b/geomagio/api/db/metadata_history.py
@@ -0,0 +1,35 @@
+from sqlalchemy import Column, ForeignKey, Integer
+
+from ...metadata import Metadata
+from .common import database, sqlalchemy_metadata
+from .metadata_table import metadata
+
+# create copy of original metadata table and add to sqlalchemy metadata
+metadata_history = metadata.tometadata(
+    metadata=sqlalchemy_metadata, name="metadata_history"
+)
+metadata_history.append_column(
+    Column(
+        "metadata_id",
+        Integer,
+        ForeignKey("metadata.id"),
+        nullable=False,
+    ),
+)
+metadata_history.indexes.clear()
+
+
+async def create_metadata(meta: Metadata) -> Metadata:
+    query = metadata_history.insert()
+    meta.metadata_id = meta.id
+    values = meta.datetime_dict(exclude={"id"}, exclude_none=True)
+    query = query.values(**values)
+    meta.id = await database.execute(query)
+    return meta
+
+
+async def get_metadata(metadata_id: int):
+    query = metadata_history.select()
+    query = query.where(metadata_history.c.metadata_id == metadata_id)
+    rows = await database.fetch_all(query)
+    return [Metadata(**row) for row in rows]
diff --git a/geomagio/api/secure/metadata.py b/geomagio/api/secure/metadata.py
index 86fad54558903b4fb786e7f92416110ecb3e1530..fcb694d394c1a93bd9dcc1426f9dcc0c38bbd3a1 100644
--- a/geomagio/api/secure/metadata.py
+++ b/geomagio/api/secure/metadata.py
@@ -21,7 +21,7 @@ from obspy import UTCDateTime
 
 from ...metadata import Metadata, MetadataCategory, MetadataQuery
 from ... import pydantic_utcdatetime
-from ..db import metadata_table
+from ..db import metadata_history, metadata_table
 from .login import require_user, User
 
 # routes for login/logout
@@ -45,6 +45,14 @@ async def delete_metadata(
     await metadata_table.delete_metadata(id)
 
 
+@router.get("/metadata/{id}/history", response_model=List[Metadata])
+async def get_history_by_metadata_id(
+    metadata_id: int,
+    user: User = Depends(require_user([os.getenv("REVIEWER_GROUP", "reviewer")])),
+):
+    return await metadata_history.get_metadata(metadata_id=metadata_id)
+
+
 @router.get("/metadata", response_model=List[Metadata])
 async def get_metadata(
     category: MetadataCategory = None,
@@ -93,6 +101,9 @@ async def update_metadata(
     metadata: Metadata = Body(...),
     user: User = Depends(require_user([os.getenv("REVIEWER_GROUP", "reviewer")])),
 ):
+    original_metadata = await get_metadata_by_id(metadata.id)
+    await metadata_history.create_metadata(original_metadata)
+    metadata.updated_by = user.nickname
+    metadata.updated_time = UTCDateTime()
     await metadata_table.update_metadata(metadata)
-    # should be same, but read from database
     return await get_metadata_by_id(metadata.id)