diff --git a/src/Resend.Webhooks/DomainEventData.cs b/src/Resend.Webhooks/DomainEventData.cs
index a556286..65fed39 100644
--- a/src/Resend.Webhooks/DomainEventData.cs
+++ b/src/Resend.Webhooks/DomainEventData.cs
@@ -1,4 +1,4 @@
-using System.Text.Json.Serialization;
+using System.Text.Json.Serialization;
namespace Resend.Webhooks;
@@ -34,6 +34,26 @@ public class DomainEventData : IWebhookData
[JsonPropertyName( "region" )]
public DeliveryRegion Region { get; set; }
+ ///
+ [JsonPropertyName( "open_tracking" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public bool? OpenTracking { get; set; }
+
+ ///
+ [JsonPropertyName( "click_tracking" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public bool? ClickTracking { get; set; }
+
+ ///
+ [JsonPropertyName( "tracking_subdomain" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public string? TrackingSubdomain { get; set; }
+
+ ///
+ [JsonPropertyName( "capabilities" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public DomainCapabilities? Capabilities { get; set; }
+
///
/// DNS records used for domain validation.
///
diff --git a/src/Resend/Domain.cs b/src/Resend/Domain.cs
index 3f32a55..04797dd 100644
--- a/src/Resend/Domain.cs
+++ b/src/Resend/Domain.cs
@@ -1,4 +1,4 @@
-using System.Text.Json.Serialization;
+using System.Text.Json.Serialization;
namespace Resend;
@@ -36,6 +36,34 @@ public class Domain
[JsonPropertyName( "region" )]
public DeliveryRegion Region { get; set; }
+ ///
+ /// Whether open tracking is enabled for this domain.
+ ///
+ [JsonPropertyName( "open_tracking" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public bool? OpenTracking { get; set; }
+
+ ///
+ /// Whether click tracking is enabled for this domain.
+ ///
+ [JsonPropertyName( "click_tracking" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public bool? ClickTracking { get; set; }
+
+ ///
+ /// Subdomain used for click and open tracking URLs (for example, links for links.example.com).
+ ///
+ [JsonPropertyName( "tracking_subdomain" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public string? TrackingSubdomain { get; set; }
+
+ ///
+ /// Whether this domain can send and receive email.
+ ///
+ [JsonPropertyName( "capabilities" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public DomainCapabilities? Capabilities { get; set; }
+
///
/// DNS records used for domain validation.
///
diff --git a/src/Resend/DomainAddData.cs b/src/Resend/DomainAddData.cs
index d7a116b..7524ded 100644
--- a/src/Resend/DomainAddData.cs
+++ b/src/Resend/DomainAddData.cs
@@ -1,4 +1,4 @@
-using System.Text.Json.Serialization;
+using System.Text.Json.Serialization;
namespace Resend;
@@ -29,4 +29,39 @@ public class DomainAddData
[JsonPropertyName( "custom_return_path" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public string? CustomReturnPath { get; set; }
+
+ ///
+ /// TLS mode for outbound mail from this domain.
+ ///
+ [JsonPropertyName( "tls" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public TlsMode? TlsMode { get; set; }
+
+ ///
+ /// Configure sending and receiving for this domain. At least one capability must remain enabled.
+ ///
+ [JsonPropertyName( "capabilities" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public DomainCapabilities? Capabilities { get; set; }
+
+ ///
+ /// Track the open rate of each email.
+ ///
+ [JsonPropertyName( "open_tracking" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public bool? OpenTracking { get; set; }
+
+ ///
+ /// Track clicks within the body of each HTML email.
+ ///
+ [JsonPropertyName( "click_tracking" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public bool? ClickTracking { get; set; }
+
+ ///
+ /// Subdomain for click and open tracking (for example, links for links.example.com).
+ ///
+ [JsonPropertyName( "tracking_subdomain" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public string? TrackingSubdomain { get; set; }
}
\ No newline at end of file
diff --git a/src/Resend/DomainCapabilities.cs b/src/Resend/DomainCapabilities.cs
new file mode 100644
index 0000000..7fa61c3
--- /dev/null
+++ b/src/Resend/DomainCapabilities.cs
@@ -0,0 +1,23 @@
+using System.Text.Json.Serialization;
+
+namespace Resend;
+
+///
+/// Sending and receiving capabilities for a domain.
+///
+public class DomainCapabilities
+{
+ ///
+ /// Whether sending is enabled for this domain. Example values: enabled, disabled.
+ ///
+ [JsonPropertyName( "sending" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public string? Sending { get; set; }
+
+ ///
+ /// Whether receiving is enabled for this domain. Example values: enabled, disabled.
+ ///
+ [JsonPropertyName( "receiving" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public string? Receiving { get; set; }
+}
diff --git a/src/Resend/DomainRecord.cs b/src/Resend/DomainRecord.cs
index 37156de..8aa7eeb 100644
--- a/src/Resend/DomainRecord.cs
+++ b/src/Resend/DomainRecord.cs
@@ -1,4 +1,4 @@
-using System.Text.Json.Serialization;
+using System.Text.Json.Serialization;
namespace Resend;
@@ -7,7 +7,7 @@ public class DomainRecord
{
///
///
- /// Example values: SPF, DKIM.
+ /// Example values: SPF, DKIM, Receiving, Tracking.
///
[JsonPropertyName( "record" )]
public string Record { get; set; } = default!;
diff --git a/src/Resend/DomainUpdateData.cs b/src/Resend/DomainUpdateData.cs
index 303297f..3e6f724 100644
--- a/src/Resend/DomainUpdateData.cs
+++ b/src/Resend/DomainUpdateData.cs
@@ -1,4 +1,4 @@
-using System.Text.Json.Serialization;
+using System.Text.Json.Serialization;
namespace Resend;
@@ -23,6 +23,24 @@ public class DomainUpdateData
[JsonPropertyName( "tls" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public TlsMode? TlsMode { get; set; }
+
+ ///
+ /// Configure sending and receiving for this domain. At least one capability must remain enabled.
+ ///
+ [JsonPropertyName( "capabilities" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public DomainCapabilities? Capabilities { get; set; }
+
+ ///
+ /// Subdomain for click and open tracking (for example, links for links.example.com).
+ ///
+ ///
+ /// This value can only be set after it has been specified, never cleared. After changing the tracking
+ /// subdomain, verify DNS again; until then, the previous value may still be used for tracked links.
+ ///
+ [JsonPropertyName( "tracking_subdomain" )]
+ [JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
+ public string? TrackingSubdomain { get; set; }
}
diff --git a/tests/Resend.Tests/DomainTests.cs b/tests/Resend.Tests/DomainTests.cs
new file mode 100644
index 0000000..b6f47d6
--- /dev/null
+++ b/tests/Resend.Tests/DomainTests.cs
@@ -0,0 +1,113 @@
+using System.Net.Http.Json;
+using System.Text.Json;
+
+namespace Resend.Tests;
+
+///
+public class DomainTests
+{
+ ///
+ [Fact]
+ public void DomainAddData_serializes_capabilities_and_tls()
+ {
+ var data = new DomainAddData()
+ {
+ DomainName = "example.com",
+ TlsMode = TlsMode.Enforced,
+ Capabilities = new DomainCapabilities()
+ {
+ Sending = "enabled",
+ Receiving = "disabled",
+ },
+ };
+
+ var json = JsonSerializer.Serialize( data );
+ Assert.Contains( "\"tls\":\"enforced\"", json );
+ Assert.Contains( "\"capabilities\"", json );
+ Assert.Contains( "\"sending\":\"enabled\"", json );
+ }
+
+
+ ///
+ [Fact]
+ public void DomainAddData_serializes_tracking_fields()
+ {
+ var data = new DomainAddData()
+ {
+ DomainName = "example.com",
+ ClickTracking = true,
+ TrackingSubdomain = "links",
+ };
+
+ var json = JsonSerializer.Serialize( data );
+ Assert.Contains( "\"click_tracking\":true", json );
+ Assert.Contains( "\"tracking_subdomain\":\"links\"", json );
+ Assert.DoesNotContain( "open_tracking", json );
+ }
+
+
+ ///
+ [Fact]
+ public void Domain_deserializes_tracking_and_capabilities()
+ {
+ const string json = """
+ {
+ "id": "d91cd9bd-1176-453e-8fc1-35364d380206",
+ "name": "example.com",
+ "status": "not_started",
+ "created_at": "2023-04-26T20:21:26.347412+00:00",
+ "region": "us-east-1",
+ "open_tracking": true,
+ "click_tracking": false,
+ "tracking_subdomain": "links",
+ "capabilities": {
+ "sending": "enabled",
+ "receiving": "disabled"
+ },
+ "records": []
+ }
+ """;
+
+ var domain = JsonSerializer.Deserialize( json );
+ Assert.NotNull( domain );
+ Assert.Equal( "links", domain!.TrackingSubdomain );
+ Assert.True( domain.OpenTracking );
+ Assert.False( domain.ClickTracking );
+ Assert.NotNull( domain.Capabilities );
+ Assert.Equal( "enabled", domain.Capabilities!.Sending );
+ Assert.Equal( "disabled", domain.Capabilities.Receiving );
+ }
+
+
+ ///
+ [Fact]
+ public void DomainUpdateData_serializes_tracking_subdomain()
+ {
+ var data = new DomainUpdateData()
+ {
+ TrackClicks = true,
+ TrackOpen = false,
+ TrackingSubdomain = "links",
+ };
+
+ var json = JsonSerializer.Serialize( data );
+ Assert.Contains( "\"tracking_subdomain\":\"links\"", json );
+ }
+
+
+ ///
+ [Fact]
+ public async Task JsonContent_Create_omits_null_tracking_subdomain_on_update()
+ {
+ var data = new DomainUpdateData()
+ {
+ TrackClicks = true,
+ TrackOpen = true,
+ TrackingSubdomain = null,
+ };
+
+ using var content = JsonContent.Create( data );
+ var json = await content.ReadAsStringAsync();
+ Assert.DoesNotContain( "tracking_subdomain", json );
+ }
+}