diff --git a/src/NATS.Server/Events/EventJsonContext.cs b/src/NATS.Server/Events/EventJsonContext.cs
new file mode 100644
index 0000000..7ac4ed2
--- /dev/null
+++ b/src/NATS.Server/Events/EventJsonContext.cs
@@ -0,0 +1,12 @@
+using System.Text.Json.Serialization;
+
+namespace NATS.Server.Events;
+
+[JsonSerializable(typeof(ConnectEventMsg))]
+[JsonSerializable(typeof(DisconnectEventMsg))]
+[JsonSerializable(typeof(AccountNumConns))]
+[JsonSerializable(typeof(ServerStatsMsg))]
+[JsonSerializable(typeof(ShutdownEventMsg))]
+[JsonSerializable(typeof(LameDuckEventMsg))]
+[JsonSerializable(typeof(AuthErrorEventMsg))]
+internal partial class EventJsonContext : JsonSerializerContext;
diff --git a/src/NATS.Server/Events/EventTypes.cs b/src/NATS.Server/Events/EventTypes.cs
new file mode 100644
index 0000000..9da36bb
--- /dev/null
+++ b/src/NATS.Server/Events/EventTypes.cs
@@ -0,0 +1,270 @@
+using System.Text.Json.Serialization;
+
+namespace NATS.Server.Events;
+
+///
+/// Server identity block embedded in all system events.
+///
+public sealed class EventServerInfo
+{
+ [JsonPropertyName("name")]
+ public string Name { get; set; } = string.Empty;
+
+ [JsonPropertyName("host")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Host { get; set; }
+
+ [JsonPropertyName("id")]
+ public string Id { get; set; } = string.Empty;
+
+ [JsonPropertyName("cluster")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Cluster { get; set; }
+
+ [JsonPropertyName("domain")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Domain { get; set; }
+
+ [JsonPropertyName("ver")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Version { get; set; }
+
+ [JsonPropertyName("seq")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public ulong Seq { get; set; }
+
+ [JsonPropertyName("tags")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public Dictionary? Tags { get; set; }
+}
+
+///
+/// Client identity block for connect/disconnect events.
+///
+public sealed class EventClientInfo
+{
+ [JsonPropertyName("start")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public DateTime Start { get; set; }
+
+ [JsonPropertyName("stop")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public DateTime Stop { get; set; }
+
+ [JsonPropertyName("host")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Host { get; set; }
+
+ [JsonPropertyName("id")]
+ public ulong Id { get; set; }
+
+ [JsonPropertyName("acc")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Account { get; set; }
+
+ [JsonPropertyName("name")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Name { get; set; }
+
+ [JsonPropertyName("lang")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Lang { get; set; }
+
+ [JsonPropertyName("ver")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Version { get; set; }
+
+ [JsonPropertyName("rtt")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public long RttNanos { get; set; }
+}
+
+public sealed class DataStats
+{
+ [JsonPropertyName("msgs")]
+ public long Msgs { get; set; }
+
+ [JsonPropertyName("bytes")]
+ public long Bytes { get; set; }
+}
+
+/// Client connect advisory. Go events.go:155-160.
+public sealed class ConnectEventMsg
+{
+ public const string EventType = "io.nats.server.advisory.v1.client_connect";
+
+ [JsonPropertyName("type")]
+ public string Type { get; set; } = EventType;
+
+ [JsonPropertyName("id")]
+ public string Id { get; set; } = string.Empty;
+
+ [JsonPropertyName("timestamp")]
+ public DateTime Time { get; set; }
+
+ [JsonPropertyName("server")]
+ public EventServerInfo Server { get; set; } = new();
+
+ [JsonPropertyName("client")]
+ public EventClientInfo Client { get; set; } = new();
+}
+
+/// Client disconnect advisory. Go events.go:167-174.
+public sealed class DisconnectEventMsg
+{
+ public const string EventType = "io.nats.server.advisory.v1.client_disconnect";
+
+ [JsonPropertyName("type")]
+ public string Type { get; set; } = EventType;
+
+ [JsonPropertyName("id")]
+ public string Id { get; set; } = string.Empty;
+
+ [JsonPropertyName("timestamp")]
+ public DateTime Time { get; set; }
+
+ [JsonPropertyName("server")]
+ public EventServerInfo Server { get; set; } = new();
+
+ [JsonPropertyName("client")]
+ public EventClientInfo Client { get; set; } = new();
+
+ [JsonPropertyName("sent")]
+ public DataStats Sent { get; set; } = new();
+
+ [JsonPropertyName("received")]
+ public DataStats Received { get; set; } = new();
+
+ [JsonPropertyName("reason")]
+ public string Reason { get; set; } = string.Empty;
+}
+
+/// Account connection count heartbeat. Go events.go:210-214.
+public sealed class AccountNumConns
+{
+ public const string EventType = "io.nats.server.advisory.v1.account_connections";
+
+ [JsonPropertyName("type")]
+ public string Type { get; set; } = EventType;
+
+ [JsonPropertyName("id")]
+ public string Id { get; set; } = string.Empty;
+
+ [JsonPropertyName("timestamp")]
+ public DateTime Time { get; set; }
+
+ [JsonPropertyName("server")]
+ public EventServerInfo Server { get; set; } = new();
+
+ [JsonPropertyName("acc")]
+ public string AccountName { get; set; } = string.Empty;
+
+ [JsonPropertyName("conns")]
+ public int Connections { get; set; }
+
+ [JsonPropertyName("total_conns")]
+ public long TotalConnections { get; set; }
+
+ [JsonPropertyName("subs")]
+ public int Subscriptions { get; set; }
+
+ [JsonPropertyName("sent")]
+ public DataStats Sent { get; set; } = new();
+
+ [JsonPropertyName("received")]
+ public DataStats Received { get; set; } = new();
+}
+
+/// Server stats broadcast. Go events.go:150-153.
+public sealed class ServerStatsMsg
+{
+ [JsonPropertyName("server")]
+ public EventServerInfo Server { get; set; } = new();
+
+ [JsonPropertyName("statsz")]
+ public ServerStatsData Stats { get; set; } = new();
+}
+
+public sealed class ServerStatsData
+{
+ [JsonPropertyName("start")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public DateTime Start { get; set; }
+
+ [JsonPropertyName("mem")]
+ public long Mem { get; set; }
+
+ [JsonPropertyName("cores")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public int Cores { get; set; }
+
+ [JsonPropertyName("connections")]
+ public int Connections { get; set; }
+
+ [JsonPropertyName("total_connections")]
+ public long TotalConnections { get; set; }
+
+ [JsonPropertyName("active_accounts")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public int ActiveAccounts { get; set; }
+
+ [JsonPropertyName("subscriptions")]
+ public long Subscriptions { get; set; }
+
+ [JsonPropertyName("in_msgs")]
+ public long InMsgs { get; set; }
+
+ [JsonPropertyName("out_msgs")]
+ public long OutMsgs { get; set; }
+
+ [JsonPropertyName("in_bytes")]
+ public long InBytes { get; set; }
+
+ [JsonPropertyName("out_bytes")]
+ public long OutBytes { get; set; }
+
+ [JsonPropertyName("slow_consumers")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public long SlowConsumers { get; set; }
+}
+
+/// Server shutdown notification.
+public sealed class ShutdownEventMsg
+{
+ [JsonPropertyName("server")]
+ public EventServerInfo Server { get; set; } = new();
+
+ [JsonPropertyName("reason")]
+ public string Reason { get; set; } = string.Empty;
+}
+
+/// Lame duck mode notification.
+public sealed class LameDuckEventMsg
+{
+ [JsonPropertyName("server")]
+ public EventServerInfo Server { get; set; } = new();
+}
+
+/// Auth error advisory.
+public sealed class AuthErrorEventMsg
+{
+ public const string EventType = "io.nats.server.advisory.v1.client_auth";
+
+ [JsonPropertyName("type")]
+ public string Type { get; set; } = EventType;
+
+ [JsonPropertyName("id")]
+ public string Id { get; set; } = string.Empty;
+
+ [JsonPropertyName("timestamp")]
+ public DateTime Time { get; set; }
+
+ [JsonPropertyName("server")]
+ public EventServerInfo Server { get; set; } = new();
+
+ [JsonPropertyName("client")]
+ public EventClientInfo Client { get; set; } = new();
+
+ [JsonPropertyName("reason")]
+ public string Reason { get; set; } = string.Empty;
+}
diff --git a/src/NATS.Server/NATS.Server.csproj b/src/NATS.Server/NATS.Server.csproj
index d85e688..390f283 100644
--- a/src/NATS.Server/NATS.Server.csproj
+++ b/src/NATS.Server/NATS.Server.csproj
@@ -1,4 +1,7 @@
+
+
+
diff --git a/tests/NATS.Server.Tests/EventSystemTests.cs b/tests/NATS.Server.Tests/EventSystemTests.cs
new file mode 100644
index 0000000..ab6e501
--- /dev/null
+++ b/tests/NATS.Server.Tests/EventSystemTests.cs
@@ -0,0 +1,68 @@
+using System.Text.Json;
+using NATS.Server.Events;
+
+namespace NATS.Server.Tests;
+
+public class EventSystemTests
+{
+ [Fact]
+ public void ConnectEventMsg_serializes_with_correct_type()
+ {
+ var evt = new ConnectEventMsg
+ {
+ Type = ConnectEventMsg.EventType,
+ Id = "test123",
+ Time = new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc),
+ Server = new EventServerInfo { Name = "test-server", Id = "SRV1" },
+ Client = new EventClientInfo { Id = 1, Account = "$G" },
+ };
+
+ var json = JsonSerializer.Serialize(evt, EventJsonContext.Default.ConnectEventMsg);
+ json.ShouldContain("\"type\":\"io.nats.server.advisory.v1.client_connect\"");
+ json.ShouldContain("\"server\":");
+ json.ShouldContain("\"client\":");
+ }
+
+ [Fact]
+ public void DisconnectEventMsg_serializes_with_reason()
+ {
+ var evt = new DisconnectEventMsg
+ {
+ Type = DisconnectEventMsg.EventType,
+ Id = "test456",
+ Time = DateTime.UtcNow,
+ Server = new EventServerInfo { Name = "test-server", Id = "SRV1" },
+ Client = new EventClientInfo { Id = 2, Account = "myacc" },
+ Reason = "Client Closed",
+ Sent = new DataStats { Msgs = 10, Bytes = 1024 },
+ Received = new DataStats { Msgs = 5, Bytes = 512 },
+ };
+
+ var json = JsonSerializer.Serialize(evt, EventJsonContext.Default.DisconnectEventMsg);
+ json.ShouldContain("\"reason\":\"Client Closed\"");
+ }
+
+ [Fact]
+ public void ServerStatsMsg_serializes()
+ {
+ var evt = new ServerStatsMsg
+ {
+ Server = new EventServerInfo { Name = "srv1", Id = "ABC" },
+ Stats = new ServerStatsData
+ {
+ Connections = 10,
+ TotalConnections = 100,
+ InMsgs = 5000,
+ OutMsgs = 4500,
+ InBytes = 1_000_000,
+ OutBytes = 900_000,
+ Mem = 50 * 1024 * 1024,
+ Subscriptions = 42,
+ },
+ };
+
+ var json = JsonSerializer.Serialize(evt, EventJsonContext.Default.ServerStatsMsg);
+ json.ShouldContain("\"connections\":10");
+ json.ShouldContain("\"in_msgs\":5000");
+ }
+}