diff --git a/geomagio/api/db/MetadataDatabaseFactory.py b/geomagio/api/db/MetadataDatabaseFactory.py
index e97afd77261ec76e7209cfe482cb57a224aefad9..c7676bc7352d0e3db0cb9a96f0b95cbf38ed9ae1 100644
--- a/geomagio/api/db/MetadataDatabaseFactory.py
+++ b/geomagio/api/db/MetadataDatabaseFactory.py
@@ -5,7 +5,7 @@ from databases import Database
 from obspy import UTCDateTime
 from sqlalchemy import or_
 
-from ...metadata import Metadata, MetadataCategory
+from ...metadata import Metadata, MetadataQuery
 from .metadata_history_table import metadata_history
 from .metadata_table import metadata
 
@@ -24,68 +24,84 @@ class MetadataDatabaseFactory(object):
 
     async def get_metadata(
         self,
-        *,  # make all params keyword
-        id: int = None,
-        network: str = None,
-        station: str = None,
-        channel: str = None,
-        location: str = None,
-        category: MetadataCategory = None,
-        starttime: datetime = None,
-        endtime: datetime = None,
-        created_after: datetime = None,
-        created_before: datetime = None,
-        data_valid: bool = None,
-        metadata_valid: bool = None,
-        status: List[str] = None,
-    ):
-        query = metadata.select()
+        params: MetadataQuery,
+        history: bool = False,
+    ) -> List[Metadata]:
+        table = metadata
+        if history:
+            table = metadata_history
+        query = table.select()
+        (
+            id,
+            category,
+            network,
+            station,
+            channel,
+            location,
+            starttime,
+            endtime,
+            created_after,
+            created_before,
+            data_valid,
+            metadata_valid,
+            status,
+        ) = params.dict().values()
         if id:
-            query = query.where(metadata.c.id == id)
+            query = query.where(table.c.id == id)
         if category:
-            query = query.where(metadata.c.category == category)
+            query = query.where(table.c.category == category)
         if network:
-            query = query.where(metadata.c.network == network)
+            query = query.where(table.c.network == network)
         if station:
-            query = query.where(metadata.c.station == station)
+            query = query.where(table.c.station == station)
         if channel:
-            query = query.where(metadata.c.channel.like(channel))
+            query = query.where(table.c.channel.like(channel))
         if location:
-            query = query.where(metadata.c.location.like(location))
+            query = query.where(table.c.location.like(location))
         if starttime:
             query = query.where(
                 or_(
-                    metadata.c.endtime == None,
-                    metadata.c.endtime > starttime,
+                    table.c.endtime == None,
+                    table.c.endtime > starttime,
                 )
             )
         if endtime:
             query = query.where(
                 or_(
-                    metadata.c.starttime == None,
-                    metadata.c.starttime < endtime,
+                    table.c.starttime == None,
+                    table.c.starttime < endtime,
                 )
             )
         if created_after:
-            query = query.where(metadata.c.created_time > created_after)
+            query = query.where(table.c.created_time > created_after)
         if created_before:
-            query = query.where(metadata.c.created_time < created_before)
+            query = query.where(table.c.created_time < created_before)
         if data_valid is not None:
-            query = query.where(metadata.c.data_valid == data_valid)
+            query = query.where(table.c.data_valid == data_valid)
         if metadata_valid is not None:
-            query = query.where(metadata.c.metadata_valid == metadata_valid)
+            query = query.where(table.c.metadata_valid == metadata_valid)
         if status is not None:
-            query = query.where(metadata.c.status.in_(status))
+            query = query.where(table.c.status.in_(status))
         rows = await self.database.fetch_all(query)
         return [Metadata(**row) for row in rows]
 
     async def get_metadata_by_id(self, id: int):
-        meta = await self.get_metadata(id=id)
+        meta = await self.get_metadata(MetadataQuery(id=id))
         if len(meta) != 1:
             raise ValueError(f"{len(meta)} records found")
         return meta[0]
 
-    async def get_metadata_history(self, metadata_id: int) -> List[Metadata]:
+    async def get_metadata_history_by_id(self, id: int) -> Optional[Metadata]:
+        query = metadata_history.select()
+        query = query.where(metadata_history.c.id == id)
+        meta = await self.database.fetch_one(query)
+        if meta is None:
+            return meta
+        return Metadata(**meta)
+
+    async def get_metadata_history_by_metadata_id(
+        self, metadata_id: int
+    ) -> List[Metadata]:
         async with self.database.transaction() as transaction:
             query = metadata_history.select()
             query = query.where(metadata_history.c.metadata_id == metadata_id).order_by(
@@ -99,14 +115,6 @@ class MetadataDatabaseFactory(object):
             metadata.reverse()
             return metadata
 
-    async def get_metadata_history_by_id(self, id: int) -> Optional[Metadata]:
-        query = metadata_history.select()
-        query = query.where(metadata_history.c.id == id)
-        meta = await self.database.fetch_one(query)
-        if meta is None:
-            return meta
-        return Metadata(**meta)
-
     async def update_metadata(self, meta: Metadata, updated_by: str) -> Metadata:
         async with self.database.transaction() as transaction:
             # write current record to metadata history table
diff --git a/geomagio/api/secure/metadata.py b/geomagio/api/secure/metadata.py
index a2015abc469a67a94867aed0caa0974b3f336b41..755948d12afa590d377ee034ebd0b77bf3bddc11 100644
--- a/geomagio/api/secure/metadata.py
+++ b/geomagio/api/secure/metadata.py
@@ -29,20 +29,7 @@ from .login import require_user, User
 router = APIRouter()
 
 
-@router.post("/metadata", response_model=Metadata)
-async def create_metadata(
-    request: Request,
-    metadata: Metadata,
-    user: User = Depends(require_user()),
-):
-    metadata = await MetadataDatabaseFactory(database=database).create_metadata(
-        meta=metadata
-    )
-    return Response(metadata.json(), status_code=201, media_type="application/json")
-
-
-@router.get("/metadata", response_model=List[Metadata])
-async def get_metadata(
+def get_metadata_query(
     category: MetadataCategory = None,
     starttime: UTCDateTime = None,
     endtime: UTCDateTime = None,
@@ -55,8 +42,8 @@ async def get_metadata(
     data_valid: bool = None,
     metadata_valid: bool = True,
     status: List[str] = Query(None),
-):
-    query = MetadataQuery(
+) -> MetadataQuery:
+    return MetadataQuery(
         category=category,
         starttime=starttime,
         endtime=endtime,
@@ -70,8 +57,30 @@ async def get_metadata(
         metadata_valid=metadata_valid,
         status=status,
     )
+
+
+@router.post("/metadata", response_model=Metadata)
+async def create_metadata(
+    request: Request,
+    metadata: Metadata,
+    user: User = Depends(require_user()),
+):
+    metadata = await MetadataDatabaseFactory(database=database).create_metadata(
+        meta=metadata
+    )
+    return Response(metadata.json(), status_code=201, media_type="application/json")
+
+
+@router.get("/metadata", response_model=List[Metadata])
+async def get_metadata(query: MetadataQuery = Depends(get_metadata_query)):
+    metas = await MetadataDatabaseFactory(database=database).get_metadata(params=query)
+    return metas
+
+
+@router.get("/metadata/history", response_model=List[Metadata])
+async def get_metadata_history(query: MetadataQuery = Depends(get_metadata_query)):
     metas = await MetadataDatabaseFactory(database=database).get_metadata(
-        **query.datetime_dict(exclude={"id", "metadata_id"})
+        params=query, history=True
     )
     return metas
 
@@ -82,10 +91,12 @@ async def get_metadata_by_id(id: int):
 
 
 @router.get("/metadata/{metadata_id}/history", response_model=List[Metadata])
-async def get_metadata_history(
+async def get_metadata_history_by_metadata_id(
     metadata_id: int,
 ):
-    return await MetadataDatabaseFactory(database=database).get_metadata_history(
+    return await MetadataDatabaseFactory(
+        database=database
+    ).get_metadata_history_by_metadata_id(
         metadata_id=metadata_id,
     )