diff --git a/geomagio/metadata/Flag.py b/geomagio/metadata/Flag.py
new file mode 100644
index 0000000000000000000000000000000000000000..0791f94c63958100b7d247417f27244a75e0e7d3
--- /dev/null
+++ b/geomagio/metadata/Flag.py
@@ -0,0 +1,206 @@
+from typing import Dict, Union, List
+from datetime import timedelta
+
+from obspy import UTCDateTime
+from pydantic import BaseModel, Field, validator
+from enum import Enum
+
+
+# Are channels defined elsewhere?
+class ChannelType(str, Enum):
+    H = "H"
+    E = "E"
+    X = "X"
+    Y = "Y"
+    Z = "Z"
+    D = "D"
+    F = "F"
+
+
+class Flag(BaseModel):
+    """
+        Base class for flagging features in magnetic timeseries data.
+
+        Flag example:
+        ```
+        automatic_flag = Metadata(
+            created_by='ex_algorithm',
+            start_time=UTCDateTime('2023-01-01T00:00:00'),
+            end_time=UTCDateTime('2023-01-01T23:59:59'),
+            network='NT',
+            station='BOU',
+            channel='BEU',
+            category=MetadataCategory.FLAG,
+            comment="spike detected",
+            priority=1,
+            data_valid=False,
+            metadata= Spikes{
+                "starttime": "2023-01-01T03:05:00",
+                "endtime": "2023-01-01T03:07:00",
+                "channels": "F",
+                "description": "Spike in magnetic field strength",
+                "field_work": false,
+                "magnitude": 16 nt,
+        }
+    )
+        ```
+    """
+
+    starttime: UTCDateTime = None
+    endtime: UTCDateTime = None
+    channels: Union[ChannelType, List[ChannelType]]
+    description: str = Field(..., description="Description of the flag")
+    field_work: bool = Field(..., description="Flag signaling field work")
+    corrective_action: bool = Field(
+        ...,
+        description="whether or not corrective action has been taken for spikes, noise, etc.",
+    )
+
+
+class Noise(Flag):
+    """
+    This class is used to flag noise.
+
+    Noise can refer to random or unwanted variations in the magnetic field.
+    Typically it lacks a pattern, has varying amplitudes and frequency distributions.
+    Noise can be natural or unnatural.
+
+    Attributes
+    ----------
+    noise_level: float
+        Level of noise in the magnetic time series in decibels.
+    noise_source: str
+        Source of the noise.
+    filtered: bool
+        Whether the noise has been filtered.
+    filter_used: str
+        Type of filter used. This could be linked to another class representing processing tools.
+    """
+
+    noise_level: float = Field(
+        None, description="Level of noise in the magnetic time series in dB"
+    )
+    noise_source: str = Field(None, description="Source of the noise")
+    filtered: bool
+    filter_used: str = Field(None, description="Type of filter used")
+
+
+class Spikes(Flag):
+    """
+    This class is used to flag spikes.
+
+    a spike refers to a sudden, short-duration increase or decrease in the magnetic field.
+    Spikes are short-lived events and should appear as a single sample within the timeseries.
+
+    Attributes
+    ----------
+    magnitude: float
+        Magnitude of spike in nt.
+    """
+
+    magnitude: float  # we need to define what this magnitude is relative to
+
+    # add validator based on frequency?
+
+
+class Gaps(Flag):
+    """
+    This class is used to flag gaps in data.
+
+    A gap is a period where data is missing or not recorded.
+
+    Attributes
+    ----------
+    duration: timedelta
+        Length of time during which data is missing.
+    cause: str
+        Cause of gap, e.g., network outage.
+    handling: str
+        How the gap is being handled, e.g., backfilled.
+    """
+
+    duration: timedelta
+    cause: str = None
+    handling: str = None
+
+
+class Offsets(Flag):
+    """
+    This class is used to flag offsets.
+
+    An offset refers to a relatively constant shift or deviation in the baseline magnetic field
+    strength lasting for a duration or permanantly like a step.
+
+    Attributes
+    ----------
+    magnitude: float
+        A constant value added to or subtracted from the magnetic field strength (nt).
+    duration: timedelta
+        Length of the offset.
+    """
+
+    magnitude: float
+    duration: timedelta
+
+
+class AdjustedAlgorithmOffsets(Flag):
+    """
+    This class is used to flag shifts made by the Adjusted Algorithm.
+
+    Attributes
+    ----------
+     adjustments: Dict
+        Adjustments made by the algorithm.
+    """
+
+    adjustments: Dict
+
+
+class Events(Flag):
+    """
+    This class is used to flag an event of interest such as a geomagnetic storm or earthquake.
+
+    Attributes
+    ----------
+    geomagnetic_storm: bool
+        Geomagnetic storm period.
+    """
+
+    geomagnetic_storm: bool = None  # if true, ignore spike detection filter
+
+
+class Anomalies(Flag):
+    """
+    This class is used to flag anything that does not fall under the above categories.
+
+    Attributes
+    ----------
+    """
+
+
+# More example usage:
+noise_data = {
+    "starttime": "2023-11-16 12:00:00",
+    "endtime": "2023-11-16 12:15:00",
+    "channels": "X",
+    "metadata": {"key1": "value1", "key2": "value2"},
+    "description": "Noise description",
+    "field_work": True,
+    "noise_level": 0.2,
+}
+
+spikes_data = {
+    "starttime": "2023-11-16 12:00:00",
+    "endtime": "2023-11-16 12:15:00",
+    "channels": ["X", "Y", "Z"],
+    "metadata": {"key1": "value1", "key2": "value2"},
+    "description": "Spikes description",
+    "field_work": True,
+    "magnitude": 5.0,
+}
+
+single_channel_instance = Noise(**noise_data)
+multiple_channels_instance = Spikes(**spikes_data)
+
+print(single_channel_instance.dict())
+print(multiple_channels_instance.dict())