diff --git a/Realtime/PostgresChanges/PostgresChangesOptions.cs b/Realtime/PostgresChanges/PostgresChangesOptions.cs
index 6f4a2e9..3b3d65c 100644
--- a/Realtime/PostgresChanges/PostgresChangesOptions.cs
+++ b/Realtime/PostgresChanges/PostgresChangesOptions.cs
@@ -57,9 +57,11 @@ public enum ListenType
public string Schema { get; set; }
///
- /// The table for this listener, can be: `*` matching all tables in schema.
+ /// The table for this listener, can be: `*` matching all tables in schema. When null
+ /// (a schema-wide listener), the table key is omitted from the join payload rather than
+ /// sent as null.
///
- [JsonProperty("table")]
+ [JsonProperty("table", NullValueHandling = NullValueHandling.Ignore)]
public string? Table { get; set; }
///
diff --git a/RealtimeTests/Serialization/PostgresChangesOptionsTests.cs b/RealtimeTests/Serialization/PostgresChangesOptionsTests.cs
new file mode 100644
index 0000000..a98c9f8
--- /dev/null
+++ b/RealtimeTests/Serialization/PostgresChangesOptionsTests.cs
@@ -0,0 +1,29 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Supabase.Realtime.PostgresChanges;
+
+namespace RealtimeTests;
+
+///
+/// Wire-shape of as it is serialized into a channel's
+/// join config.postgres_changes payload.
+///
+[TestClass]
+public class PostgresChangesOptionsTests
+{
+ [TestMethod]
+ public void Table_ShouldBeOmittedFromJson_WhenNull()
+ {
+ // A schema-wide listener has no table; the server expects the key absent, not `"table": null`.
+ var json = JsonConvert.SerializeObject(new PostgresChangesOptions("public"));
+ Assert.IsFalse(JObject.Parse(json).ContainsKey("table"));
+ }
+
+ [TestMethod]
+ public void Table_ShouldBeSerialized_WhenProvided()
+ {
+ var json = JsonConvert.SerializeObject(new PostgresChangesOptions("public", "todos"));
+ Assert.AreEqual("todos", JObject.Parse(json)["table"]?.Value());
+ }
+}