diff --git a/Cargo.toml b/Cargo.toml
index 4c2969a..165d564 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,3 +14,5 @@ tower-http = { version = "0.6.2", features = ["fs"] }
 tracing = "0.1.41"
 serde = { version = "1.0.203", features = ["derive"] }
 lettre = { version = "0.11.15", default-features = false, features = ["builder", "smtp-transport", "ring", "rustls", "rustls-tls"] }
+uuid = { version = "1.16.0", features = ["serde", "v4"] }
+chrono = "0.4.38"
diff --git a/src/lib.rs b/src/lib.rs
index 34df6cb..c33d4fa 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,10 +1,12 @@
 mod api;
 mod model;
 
-pub use model::config;
-
 use crate::model::config::SMTPConfig;
 use axum::Router;
+pub use model::config;
+pub use model::event;
+pub use model::Event;
+pub use model::EventPayload;
 use tower_http::services::{ServeDir, ServeFile};
 
 const VERSION: &str = env!("CARGO_PKG_VERSION");
diff --git a/src/model.rs b/src/model.rs
index ef68c36..884f07b 100644
--- a/src/model.rs
+++ b/src/model.rs
@@ -1 +1,3 @@
 pub mod config;
+pub mod event;
+pub use event::{Event, EventPayload};
diff --git a/src/model/event.rs b/src/model/event.rs
new file mode 100644
index 0000000..23f1678
--- /dev/null
+++ b/src/model/event.rs
@@ -0,0 +1,59 @@
+mod registration;
+use chrono::{DateTime, Utc};
+pub use registration::RegistrationEvent;
+use serde::de::DeserializeOwned;
+use serde::{Deserialize, Serialize};
+use std::fmt::Debug;
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd)]
+#[serde(bound = "T: DeserializeOwned")]
+pub struct Event<T>
+where
+    T: EventPayload,
+{
+    id: uuid::Uuid,
+    timestamp: DateTime<Utc>,
+    version: u32,
+    domain: String,
+    payload: T,
+}
+
+impl<T> From<T> for Event<T>
+where
+    T: EventPayload,
+{
+    fn from(payload: T) -> Self {
+        Self {
+            id: uuid::Uuid::new_v4(),
+            timestamp: Utc::now(),
+            version: 1,
+            domain: payload.domain().to_string(),
+            payload,
+        }
+    }
+}
+
+impl<T> Event<T>
+where
+    T: EventPayload,
+{
+    pub const fn id(&self) -> &uuid::Uuid {
+        &self.id
+    }
+
+    pub const fn timestamp(&self) -> &DateTime<Utc> {
+        &self.timestamp
+    }
+
+    pub const fn version(&self) -> u32 {
+        self.version
+    }
+
+    pub const fn payload(&self) -> &T {
+        &self.payload
+    }
+}
+
+pub trait EventPayload: Debug + Clone + Serialize + DeserializeOwned + PartialEq + Eq {
+    fn domain(&self) -> &str;
+}
diff --git a/src/model/event/registration.rs b/src/model/event/registration.rs
new file mode 100644
index 0000000..b06c550
--- /dev/null
+++ b/src/model/event/registration.rs
@@ -0,0 +1,54 @@
+use crate::model::event::EventPayload;
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd)]
+pub enum RegistrationEvent {
+    RegistrationRequestReceived {
+        email_address: String,
+    },
+    VerificationEmailSent {
+        email_address: String,
+        secret: String,
+    },
+    VerificationEmailFailed {
+        email_address: String,
+        error: String,
+    },
+    VerificationSucceeded {
+        email_address: String,
+    },
+}
+
+impl RegistrationEvent {
+    #[must_use]
+    pub const fn registration_request_received(email_address: String) -> Self {
+        Self::RegistrationRequestReceived { email_address }
+    }
+
+    #[must_use]
+    pub const fn verification_email_sent(email_address: String, secret: String) -> Self {
+        Self::VerificationEmailSent {
+            email_address,
+            secret,
+        }
+    }
+
+    #[must_use]
+    pub const fn verification_email_failed(email_address: String, error: String) -> Self {
+        Self::VerificationEmailFailed {
+            email_address,
+            error,
+        }
+    }
+
+    #[must_use]
+    pub const fn verification_succeeded(email_address: String) -> Self {
+        Self::VerificationSucceeded { email_address }
+    }
+}
+
+impl EventPayload for RegistrationEvent {
+    fn domain(&self) -> &'static str {
+        "registration"
+    }
+}