Repository: DataDog/terraform-provider-datadog
Pull request #2980: [datadog_monitor_notification_rule] Add support for Monitor Notification Rule
Author: login: shaneyuandd
Labels: name: changelog/feature
name: mergequeue-status: done
name: resource/datadog_monitor_notification_rule
Created: 2025-04-18T18:55:30Z | Merged: 2025-04-29T18:51:02Z

This PR introduces a new Terraform resource: `datadog_monitor_notification_rule`, which supports managing [Datadog Monitor Notification Rules](https://docs.datadoghq.com/api/latest/monitors/?code-lang=curl#get-a-monitor-notification-rule).

This resource allows users to define reusable notification rules that can be applied to multiple monitors via tag filters. It simplifies and centralizes notification configuration, reducing the need to manage alert channels individually across many monitors.

#### Example
```
resource "datadog_monitor_notification_rule" "foo" {
  name       = "A notification rule name"
  recipients = ["slack-test-channel", "jira-test"]
  filter {
    tags = ["env:abc"]
  }
}
```


Diff:
diff --git a/datadog/fwprovider/framework_provider.go b/datadog/fwprovider/framework_provider.go
index 653805f2d3..4fbc47457d 100644
--- a/datadog/fwprovider/framework_provider.go
+++ b/datadog/fwprovider/framework_provider.go
@@ -52,6 +52,7 @@ var Resources = []func() resource.Resource{
 	NewIntegrationGcpResource,
 	NewIntegrationGcpStsResource,
 	NewIpAllowListResource,
+	NewMonitorNotificationRuleResource,
 	NewSecurityNotificationRuleResource,
 	NewRestrictionPolicyResource,
 	NewRumApplicationResource,
@@ -437,6 +438,12 @@ func defaultConfigureFunc(p *FrameworkProvider, request *provider.ConfigureReque
 	ddClientConfig.SetUnstableOperationEnabled("v2.UpdatePipeline", true)
 	ddClientConfig.SetUnstableOperationEnabled("v2.DeletePipeline", true)
 
+	// Enable MonitorNotificationRule
+	ddClientConfig.SetUnstableOperationEnabled("v2.CreateMonitorNotificationRule", true)
+	ddClientConfig.SetUnstableOperationEnabled("v2.GetMonitorNotificationRule", true)
+	ddClientConfig.SetUnstableOperationEnabled("v2.DeleteMonitorNotificationRule", true)
+	ddClientConfig.SetUnstableOperationEnabled("v2.UpdateMonitorNotificationRule", true)
+
 	if !config.ApiUrl.IsNull() && config.ApiUrl.ValueString() != "" {
 		parsedAPIURL, parseErr := url.Parse(config.ApiUrl.ValueString())
 		if parseErr != nil {
diff --git a/datadog/fwprovider/resource_datadog_monitor_notification_rule.go b/datadog/fwprovider/resource_datadog_monitor_notification_rule.go
new file mode 100644
index 0000000000..7ea885fd95
--- /dev/null
+++ b/datadog/fwprovider/resource_datadog_monitor_notification_rule.go
@@ -0,0 +1,258 @@
+package fwprovider
+
+import (
+	"context"
+
+	"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+	"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/resourcevalidator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	frameworkPath "github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	"github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
+)
+
+const resourceType = "monitor-notification-rule"
+
+var (
+	_ resource.ResourceWithConfigure   = &MonitorNotificationRuleResource{}
+	_ resource.ResourceWithImportState = &MonitorNotificationRuleResource{}
+)
+
+type MonitorNotificationRuleResource struct {
+	Api  *datadogV2.MonitorsApi
+	Auth context.Context
+}
+
+type MonitorNotificationRuleModel struct {
+	ID                            types.String                   `tfsdk:"id"`
+	Name                          types.String                   `tfsdk:"name"`
+	Recipients                    types.Set                      `tfsdk:"recipients"`
+	MonitorNotificationRuleFilter *MonitorNotificationRuleFilter `tfsdk:"filter"`
+}
+
+type MonitorNotificationRuleFilter struct {
+	Tags types.Set `tfsdk:"tags"`
+}
+
+func NewMonitorNotificationRuleResource() resource.Resource {
+	return &MonitorNotificationRuleResource{}
+}
+
+func (r *MonitorNotificationRuleResource) ConfigValidators(ctx context.Context) []resource.ConfigValidator {
+	return []resource.ConfigValidator{
+		resourcevalidator.ExactlyOneOf(
+			frameworkPath.MatchRoot("filter").AtName("tags"),
+		),
+	}
+}
+
+func (r *MonitorNotificationRuleResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
+	providerData, _ := request.ProviderData.(*FrameworkProvider)
+	r.Api = providerData.DatadogApiInstances.GetMonitorsApiV2()
+	r.Auth = providerData.Auth
+}
+
+func (r *MonitorNotificationRuleResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) {
+	response.TypeName = "monitor_notification_rule"
+}
+
+func (r *MonitorNotificationRuleResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
+	response.Schema = schema.Schema{
+		Description: "Provides a Datadog MonitorNotificationRule resource.",
+		Attributes: map[string]schema.Attribute{
+			"id": utils.ResourceIDAttribute(),
+			"name": schema.StringAttribute{
+				Required:    true,
+				Description: "The name of the monitor notification rule.",
+			},
+			"recipients": schema.SetAttribute{
+				Required:    true,
+				ElementType: types.StringType,
+				Description: "List of recipients to notify.",
+				Validators: []validator.Set{
+					setvalidator.SizeAtLeast(1),
+				},
+			},
+		},
+		Blocks: map[string]schema.Block{
+			"filter": schema.SingleNestedBlock{
+				Attributes: map[string]schema.Attribute{
+					"tags": schema.SetAttribute{
+						Required:    true,
+						ElementType: types.StringType,
+						Description: "All tags that target monitors must match.",
+						Validators: []validator.Set{
+							setvalidator.SizeAtLeast(1),
+						},
+					},
+				},
+				Validators: []validator.Object{
+					objectvalidator.IsRequired(),
+				},
+			},
+		},
+	}
+}
+
+func (r *MonitorNotificationRuleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	resource.ImportStatePassthroughID(ctx, frameworkPath.Root("id"), req, resp)
+}
+
+func (r *MonitorNotificationRuleResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
+	var state MonitorNotificationRuleModel
+	response.Diagnostics.Append(request.State.Get(ctx, &state)...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+	id := state.ID.ValueString()
+
+	resp, httpResp, err := r.Api.GetMonitorNotificationRule(r.Auth, id)
+	if err != nil {
+		if httpResp != nil && httpResp.StatusCode == 404 {
+			response.State.RemoveResource(ctx)
+			return
+		}
+		response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error retrieving MonitorNotificationRule"))
+		return
+	}
+
+	r.updateState(ctx, &state, &resp)
+
+	// Save data into Terraform state
+	response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *MonitorNotificationRuleResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
+	var state MonitorNotificationRuleModel
+	response.Diagnostics.Append(request.Plan.Get(ctx, &state)...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	createRequest, diags := r.buildMonitorNotificationRuleCreateRequest(ctx, &state)
+	response.Diagnostics.Append(diags...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	resp, _, err := r.Api.CreateMonitorNotificationRule(r.Auth, *createRequest)
+	if err != nil {
+		response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error creating MonitorNotificationRule"))
+		return
+	}
+	r.updateState(ctx, &state, &resp)
+
+	// Save data into Terraform state
+	response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *MonitorNotificationRuleResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
+	var state MonitorNotificationRuleModel
+	response.Diagnostics.Append(request.Plan.Get(ctx, &state)...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	id := state.ID.ValueString()
+
+	updateRequest, diags := r.buildMonitorNotificationRuleUpdateRequest(ctx, &state)
+	response.Diagnostics.Append(diags...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	resp, _, err := r.Api.UpdateMonitorNotificationRule(r.Auth, id, *updateRequest)
+	if err != nil {
+		response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error updating MonitorNotificationRule"))
+		return
+	}
+	r.updateState(ctx, &state, &resp)
+
+	// Save data into Terraform state
+	response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *MonitorNotificationRuleResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) {
+	var state MonitorNotificationRuleModel
+	response.Diagnostics.Append(request.State.Get(ctx, &state)...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	id := state.ID.ValueString()
+
+	httpResp, err := r.Api.DeleteMonitorNotificationRule(r.Auth, id)
+	if err != nil {
+		if httpResp != nil && httpResp.StatusCode == 404 {
+			return
+		}
+		response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error deleting MonitorNotificationRule"))
+		return
+	}
+}
+
+func (r *MonitorNotificationRuleResource) updateState(ctx context.Context, state *MonitorNotificationRuleModel, resp *datadogV2.MonitorNotificationRuleResponse) {
+	state.ID = types.StringValue(resp.Data.GetId())
+
+	data := resp.GetData()
+	attributes := data.GetAttributes()
+
+	state.Name = types.StringValue(attributes.GetName())
+	state.Recipients, _ = types.SetValueFrom(ctx, types.StringType, attributes.GetRecipients())
+
+	if filter := attributes.GetFilter(); filter.MonitorNotificationRuleFilterTags != nil {
+		tags, _ := types.SetValueFrom(ctx, types.StringType, filter.MonitorNotificationRuleFilterTags.GetTags())
+		state.MonitorNotificationRuleFilter = &MonitorNotificationRuleFilter{
+			Tags: tags,
+		}
+	}
+}
+
+func buildRequestAttributes(ctx context.Context, state *MonitorNotificationRuleModel) (*datadogV2.MonitorNotificationRuleAttributes, diag.Diagnostics) {
+	diags := diag.Diagnostics{}
+	attributes := datadogV2.NewMonitorNotificationRuleAttributesWithDefaults()
+
+	attributes.SetName(state.Name.ValueString())
+
+	var recipients []string
+	diags.Append(state.Recipients.ElementsAs(ctx, &recipients, false)...)
+	attributes.SetRecipients(recipients)
+
+	var tags []string
+	diags.Append(state.MonitorNotificationRuleFilter.Tags.ElementsAs(ctx, &tags, false)...)
+	filterTags := datadogV2.NewMonitorNotificationRuleFilterTags(tags)
+	attributes.SetFilter(datadogV2.MonitorNotificationRuleFilter{MonitorNotificationRuleFilterTags: filterTags})
+
+	return attributes, diags
+}
+
+func (r *MonitorNotificationRuleResource) buildMonitorNotificationRuleCreateRequest(ctx context.Context, state *MonitorNotificationRuleModel) (*datadogV2.MonitorNotificationRuleCreateRequest, diag.Diagnostics) {
+	attributes, diags := buildRequestAttributes(ctx, state)
+
+	data := datadogV2.NewMonitorNotificationRuleCreateRequestDataWithDefaults()
+	data.SetType(resourceType)
+	data.SetAttributes(*attributes)
+
+	req := datadogV2.NewMonitorNotificationRuleCreateRequestWithDefaults()
+	req.SetData(*data)
+	return req, diags
+}
+
+func (r *MonitorNotificationRuleResource) buildMonitorNotificationRuleUpdateRequest(ctx context.Context, state *MonitorNotificationRuleModel) (*datadogV2.MonitorNotificationRuleUpdateRequest, diag.Diagnostics) {
+	attributes, diags := buildRequestAttributes(ctx, state)
+
+	data := datadogV2.NewMonitorNotificationRuleUpdateRequestDataWithDefaults()
+	data.SetId(state.ID.ValueString())
+	data.SetType(resourceType)
+	data.SetAttributes(*attributes)
+
+	req := datadogV2.NewMonitorNotificationRuleUpdateRequestWithDefaults()
+	req.SetData(*data)
+	return req, diags
+}
diff --git a/datadog/tests/cassettes/TestAccMonitorNotificationRule_Create.freeze b/datadog/tests/cassettes/TestAccMonitorNotificationRule_Create.freeze
new file mode 100644
index 0000000000..95beec80c3
--- /dev/null
+++ b/datadog/tests/cassettes/TestAccMonitorNotificationRule_Create.freeze
@@ -0,0 +1 @@
+2025-04-21T16:24:54.421464-04:00
\ No newline at end of file
diff --git a/datadog/tests/cassettes/TestAccMonitorNotificationRule_Create.yaml b/datadog/tests/cassettes/TestAccMonitorNotificationRule_Create.yaml
new file mode 100644
index 0000000000..c1df8303c3
--- /dev/null
+++ b/datadog/tests/cassettes/TestAccMonitorNotificationRule_Create.yaml
@@ -0,0 +1,109 @@
+---
+version: 2
+interactions:
+    - id: 0
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 228
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: |
+            {"data":{"attributes":{"filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Create-local-1745267094","host:abc"]},"name":"A notification rule name","recipients":["jira-bar","slack-foo"]},"type":"monitor-notification-rule"}}
+        form: {}
+        headers:
+            Accept:
+                - application/json
+            Content-Type:
+                - application/json
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule
+        method: POST
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding:
+            - chunked
+        trailer: {}
+        content_length: -1
+        uncompressed: true
+        body: |
+            {"data":{"type":"monitor-notification-rule","attributes":{"modified_at":"1970-01-01T00:00:00+00:00","filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Create-local-1745267094","host:abc"]},"name":"A notification rule name","created_at":"2025-04-21T20:24:55.453143+00:00","recipients":["jira-bar","slack-foo"]},"id":"ab1a0cab-a31a-4492-bbf3-ffafb5f06248","relationships":{"created_by":{"data":{"type":"users","id":"3ad549bf-eba0-11e9-a77a-0705486660d0"}}}},"included":[{"type":"users","id":"3ad549bf-eba0-11e9-a77a-0705486660d0","attributes":{"name":"frog","handle":"frog@datadoghq.com","created_at":"2019-10-02T08:15:39.795051+00:00","modified_at":"2025-04-07T20:19:46.118466+00:00","email":"frog@datadoghq.com","icon":"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro","title":null,"verified":true,"service_account":false,"disabled":false,"allowed_login_methods":[],"status":"Active"}}]}
+        headers:
+            Content-Type:
+                - application/json
+        status: 200 OK
+        code: 200
+        duration: 256.994375ms
+    - id: 1
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 0
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: ""
+        form: {}
+        headers:
+            Accept:
+                - application/json
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule/ab1a0cab-a31a-4492-bbf3-ffafb5f06248
+        method: GET
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding:
+            - chunked
+        trailer: {}
+        content_length: -1
+        uncompressed: true
+        body: |
+            {"data":{"type":"monitor-notification-rule","attributes":{"modified_at":"2025-04-21T20:24:55.488155+00:00","filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Create-local-1745267094","host:abc"]},"name":"A notification rule name","recipients":["jira-bar","slack-foo"],"created_at":"2025-04-21T20:24:55.453144+00:00"},"id":"ab1a0cab-a31a-4492-bbf3-ffafb5f06248"}}
+        headers:
+            Content-Type:
+                - application/json
+        status: 200 OK
+        code: 200
+        duration: 163.347292ms
+    - id: 2
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 0
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: ""
+        form: {}
+        headers:
+            Accept:
+                - '*/*'
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule/ab1a0cab-a31a-4492-bbf3-ffafb5f06248
+        method: DELETE
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding: []
+        trailer: {}
+        content_length: 0
+        uncompressed: false
+        body: ""
+        headers:
+            Content-Type:
+                - text/html; charset=utf-8
+        status: 204 No Content
+        code: 204
+        duration: 162.676417ms
diff --git a/datadog/tests/cassettes/TestAccMonitorNotificationRule_Import.freeze b/datadog/tests/cassettes/TestAccMonitorNotificationRule_Import.freeze
new file mode 100644
index 0000000000..6470f9444b
--- /dev/null
+++ b/datadog/tests/cassettes/TestAccMonitorNotificationRule_Import.freeze
@@ -0,0 +1 @@
+2025-04-21T16:24:54.421432-04:00
\ No newline at end of file
diff --git a/datadog/tests/cassettes/TestAccMonitorNotificationRule_Import.yaml b/datadog/tests/cassettes/TestAccMonitorNotificationRule_Import.yaml
new file mode 100644
index 0000000000..a81efb4650
--- /dev/null
+++ b/datadog/tests/cassettes/TestAccMonitorNotificationRule_Import.yaml
@@ -0,0 +1,144 @@
+---
+version: 2
+interactions:
+    - id: 0
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 228
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: |
+            {"data":{"attributes":{"filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Import-local-1745267094","host:abc"]},"name":"A notification rule name","recipients":["jira-bar","slack-foo"]},"type":"monitor-notification-rule"}}
+        form: {}
+        headers:
+            Accept:
+                - application/json
+            Content-Type:
+                - application/json
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule
+        method: POST
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding:
+            - chunked
+        trailer: {}
+        content_length: -1
+        uncompressed: true
+        body: |
+            {"data":{"type":"monitor-notification-rule","attributes":{"recipients":["jira-bar","slack-foo"],"filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Import-local-1745267094","host:abc"]},"created_at":"2025-04-21T20:24:55.452918+00:00","name":"A notification rule name","modified_at":"1970-01-01T00:00:00+00:00"},"id":"dff61907-261c-4bdb-a898-93eb1d2afa93","relationships":{"created_by":{"data":{"type":"users","id":"3ad549bf-eba0-11e9-a77a-0705486660d0"}}}},"included":[{"type":"users","id":"3ad549bf-eba0-11e9-a77a-0705486660d0","attributes":{"name":"frog","handle":"frog@datadoghq.com","created_at":"2019-10-02T08:15:39.795051+00:00","modified_at":"2025-04-07T20:19:46.118466+00:00","email":"frog@datadoghq.com","icon":"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro","title":null,"verified":true,"service_account":false,"disabled":false,"allowed_login_methods":[],"status":"Active"}}]}
+        headers:
+            Content-Type:
+                - application/json
+        status: 200 OK
+        code: 200
+        duration: 232.224375ms
+    - id: 1
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 0
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: ""
+        form: {}
+        headers:
+            Accept:
+                - application/json
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule/dff61907-261c-4bdb-a898-93eb1d2afa93
+        method: GET
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding:
+            - chunked
+        trailer: {}
+        content_length: -1
+        uncompressed: true
+        body: |
+            {"data":{"type":"monitor-notification-rule","attributes":{"recipients":["jira-bar","slack-foo"],"created_at":"2025-04-21T20:24:55.452919+00:00","filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Import-local-1745267094","host:abc"]},"modified_at":"2025-04-21T20:24:55.490589+00:00","name":"A notification rule name"},"id":"dff61907-261c-4bdb-a898-93eb1d2afa93"}}
+        headers:
+            Content-Type:
+                - application/json
+        status: 200 OK
+        code: 200
+        duration: 152.000625ms
+    - id: 2
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 0
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: ""
+        form: {}
+        headers:
+            Accept:
+                - application/json
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule/dff61907-261c-4bdb-a898-93eb1d2afa93
+        method: GET
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding:
+            - chunked
+        trailer: {}
+        content_length: -1
+        uncompressed: true
+        body: |
+            {"data":{"type":"monitor-notification-rule","id":"dff61907-261c-4bdb-a898-93eb1d2afa93","attributes":{"filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Import-local-1745267094","host:abc"]},"recipients":["jira-bar","slack-foo"],"modified_at":"2025-04-21T20:24:55.490589+00:00","name":"A notification rule name","created_at":"2025-04-21T20:24:55.452919+00:00"}}}
+        headers:
+            Content-Type:
+                - application/json
+        status: 200 OK
+        code: 200
+        duration: 104.193709ms
+    - id: 3
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 0
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: ""
+        form: {}
+        headers:
+            Accept:
+                - '*/*'
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule/dff61907-261c-4bdb-a898-93eb1d2afa93
+        method: DELETE
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding: []
+        trailer: {}
+        content_length: 0
+        uncompressed: false
+        body: ""
+        headers:
+            Content-Type:
+                - text/html; charset=utf-8
+        status: 204 No Content
+        code: 204
+        duration: 115.729042ms
diff --git a/datadog/tests/cassettes/TestAccMonitorNotificationRule_Update.freeze b/datadog/tests/cassettes/TestAccMonitorNotificationRule_Update.freeze
new file mode 100644
index 0000000000..35a4d3a0f4
--- /dev/null
+++ b/datadog/tests/cassettes/TestAccMonitorNotificationRule_Update.freeze
@@ -0,0 +1 @@
+2025-04-21T16:24:54.42145-04:00
\ No newline at end of file
diff --git a/datadog/tests/cassettes/TestAccMonitorNotificationRule_Update.yaml b/datadog/tests/cassettes/TestAccMonitorNotificationRule_Update.yaml
new file mode 100644
index 0000000000..66badd1a2e
--- /dev/null
+++ b/datadog/tests/cassettes/TestAccMonitorNotificationRule_Update.yaml
@@ -0,0 +1,217 @@
+---
+version: 2
+interactions:
+    - id: 0
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 228
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: |
+            {"data":{"attributes":{"filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Update-local-1745267094","host:abc"]},"name":"A notification rule name","recipients":["jira-bar","slack-foo"]},"type":"monitor-notification-rule"}}
+        form: {}
+        headers:
+            Accept:
+                - application/json
+            Content-Type:
+                - application/json
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule
+        method: POST
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding:
+            - chunked
+        trailer: {}
+        content_length: -1
+        uncompressed: true
+        body: |
+            {"data":{"type":"monitor-notification-rule","id":"861943f3-2ae4-475b-ac49-94b3ccedde0c","attributes":{"filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Update-local-1745267094","host:abc"]},"name":"A notification rule name","recipients":["jira-bar","slack-foo"],"created_at":"2025-04-21T20:24:55.452609+00:00","modified_at":"1970-01-01T00:00:00+00:00"},"relationships":{"created_by":{"data":{"type":"users","id":"3ad549bf-eba0-11e9-a77a-0705486660d0"}}}},"included":[{"type":"users","id":"3ad549bf-eba0-11e9-a77a-0705486660d0","attributes":{"name":"frog","handle":"frog@datadoghq.com","created_at":"2019-10-02T08:15:39.795051+00:00","modified_at":"2025-04-07T20:19:46.118466+00:00","email":"frog@datadoghq.com","icon":"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro","title":null,"verified":true,"service_account":false,"disabled":false,"allowed_login_methods":[],"status":"Active"}}]}
+        headers:
+            Content-Type:
+                - application/json
+        status: 200 OK
+        code: 200
+        duration: 218.15825ms
+    - id: 1
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 0
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: ""
+        form: {}
+        headers:
+            Accept:
+                - application/json
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule/861943f3-2ae4-475b-ac49-94b3ccedde0c
+        method: GET
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding:
+            - chunked
+        trailer: {}
+        content_length: -1
+        uncompressed: true
+        body: |
+            {"data":{"type":"monitor-notification-rule","attributes":{"created_at":"2025-04-21T20:24:55.452610+00:00","modified_at":"2025-04-21T20:24:55.480442+00:00","name":"A notification rule name","filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Update-local-1745267094","host:abc"]},"recipients":["jira-bar","slack-foo"]},"id":"861943f3-2ae4-475b-ac49-94b3ccedde0c"}}
+        headers:
+            Content-Type:
+                - application/json
+        status: 200 OK
+        code: 200
+        duration: 170.629916ms
+    - id: 2
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 0
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: ""
+        form: {}
+        headers:
+            Accept:
+                - application/json
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule/861943f3-2ae4-475b-ac49-94b3ccedde0c
+        method: GET
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding:
+            - chunked
+        trailer: {}
+        content_length: -1
+        uncompressed: true
+        body: |
+            {"data":{"type":"monitor-notification-rule","attributes":{"name":"A notification rule name","recipients":["jira-bar","slack-foo"],"filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Update-local-1745267094","host:abc"]},"modified_at":"2025-04-21T20:24:55.480442+00:00","created_at":"2025-04-21T20:24:55.452610+00:00"},"id":"861943f3-2ae4-475b-ac49-94b3ccedde0c"}}
+        headers:
+            Content-Type:
+                - application/json
+        status: 200 OK
+        code: 200
+        duration: 70.525333ms
+    - id: 3
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 275
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: |
+            {"data":{"attributes":{"filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Update-local-1745267094","host:abc","poke:mon"]},"name":"Updated rule name","recipients":["jira-bar","jira-foo"]},"id":"861943f3-2ae4-475b-ac49-94b3ccedde0c","type":"monitor-notification-rule"}}
+        form: {}
+        headers:
+            Accept:
+                - application/json
+            Content-Type:
+                - application/json
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule/861943f3-2ae4-475b-ac49-94b3ccedde0c
+        method: PATCH
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding:
+            - chunked
+        trailer: {}
+        content_length: -1
+        uncompressed: true
+        body: |
+            {"data":{"type":"monitor-notification-rule","attributes":{"modified_at":"2025-04-21T20:24:56.619236+00:00","filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Update-local-1745267094","host:abc","poke:mon"]},"name":"Updated rule name","recipients":["jira-bar","jira-foo"],"created_at":"2025-04-21T20:24:55.452610+00:00"},"id":"861943f3-2ae4-475b-ac49-94b3ccedde0c","relationships":{"created_by":{"data":{"type":"users","id":"3ad549bf-eba0-11e9-a77a-0705486660d0"}}}},"included":[{"type":"users","id":"3ad549bf-eba0-11e9-a77a-0705486660d0","attributes":{"name":"frog","handle":"frog@datadoghq.com","created_at":"2019-10-02T08:15:39.795051+00:00","modified_at":"2025-04-07T20:19:46.118466+00:00","email":"frog@datadoghq.com","icon":"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro","title":null,"verified":true,"service_account":false,"disabled":false,"allowed_login_methods":[],"status":"Active"}}]}
+        headers:
+            Content-Type:
+                - application/json
+        status: 200 OK
+        code: 200
+        duration: 120.02025ms
+    - id: 4
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 0
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: ""
+        form: {}
+        headers:
+            Accept:
+                - application/json
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule/861943f3-2ae4-475b-ac49-94b3ccedde0c
+        method: GET
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding:
+            - chunked
+        trailer: {}
+        content_length: -1
+        uncompressed: true
+        body: |
+            {"data":{"type":"monitor-notification-rule","id":"861943f3-2ae4-475b-ac49-94b3ccedde0c","attributes":{"filter":{"tags":["env:tf-TestAccMonitorNotificationRule_Update-local-1745267094","host:abc","poke:mon"]},"recipients":["jira-bar","jira-foo"],"modified_at":"2025-04-21T20:24:56.619237+00:00","name":"Updated rule name","created_at":"2025-04-21T20:24:55.452610+00:00"}}}
+        headers:
+            Content-Type:
+                - application/json
+        status: 200 OK
+        code: 200
+        duration: 139.655084ms
+    - id: 5
+      request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 0
+        transfer_encoding: []
+        trailer: {}
+        host: api.datadoghq.com
+        remote_addr: ""
+        request_uri: ""
+        body: ""
+        form: {}
+        headers:
+            Accept:
+                - '*/*'
+        url: https://api.datadoghq.com/api/v2/monitor/notification_rule/861943f3-2ae4-475b-ac49-94b3ccedde0c
+        method: DELETE
+      response:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        transfer_encoding: []
+        trailer: {}
+        content_length: 0
+        uncompressed: false
+        body: ""
+        headers:
+            Content-Type:
+                - text/html; charset=utf-8
+        status: 204 No Content
+        code: 204
+        duration: 174.613375ms
diff --git a/datadog/tests/framework_provider_test.go b/datadog/tests/framework_provider_test.go
index 20298403e7..9e44d01c97 100644
--- a/datadog/tests/framework_provider_test.go
+++ b/datadog/tests/framework_provider_test.go
@@ -51,6 +51,12 @@ func buildFrameworkDatadogClient(ctx context.Context, httpClient *http.Client) *
 	config.SetUnstableOperationEnabled("v2.UpdatePipeline", true)
 	config.SetUnstableOperationEnabled("v2.DeletePipeline", true)
 
+	// Enable MonitorNotificationRule
+	config.SetUnstableOperationEnabled("v2.CreateMonitorNotificationRule", true)
+	config.SetUnstableOperationEnabled("v2.GetMonitorNotificationRule", true)
+	config.SetUnstableOperationEnabled("v2.DeleteMonitorNotificationRule", true)
+	config.SetUnstableOperationEnabled("v2.UpdateMonitorNotificationRule", true)
+
 	if ctx.Value("http_retry_enable") == true {
 		config.RetryConfiguration.EnableRetry = true
 	}
diff --git a/datadog/tests/provider_test.go b/datadog/tests/provider_test.go
index cdfea01fe6..9984d6aade 100644
--- a/datadog/tests/provider_test.go
+++ b/datadog/tests/provider_test.go
@@ -227,6 +227,7 @@ var testFiles2EndpointTags = map[string]string{
 	"tests/resource_datadog_metric_tag_configuration_test":                   "metrics",
 	"tests/resource_datadog_monitor_config_policy_test":                      "monitor-config-policies",
 	"tests/resource_datadog_monitor_json_test":                               "monitors-json",
+	"tests/resource_datadog_monitor_notification_rule_test":                  "monitor-notification-rule",
 	"tests/resource_datadog_monitor_test":                                    "monitors",
 	"tests/resource_datadog_organization_settings_test":                      "organization",
 	"tests/resource_datadog_restriction_policy_test":                         "restriction-policy",
diff --git a/datadog/tests/resource_datadog_monitor_notification_rule_test.go b/datadog/tests/resource_datadog_monitor_notification_rule_test.go
new file mode 100644
index 0000000000..33e580ca95
--- /dev/null
+++ b/datadog/tests/resource_datadog_monitor_notification_rule_test.go
@@ -0,0 +1,194 @@
+package test
+
+import (
+	"context"
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+	"github.com/hashicorp/terraform-plugin-testing/terraform"
+
+	"github.com/terraform-providers/terraform-provider-datadog/datadog/fwprovider"
+	"github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
+)
+
+func TestAccMonitorNotificationRule_Import(t *testing.T) {
+	t.Parallel()
+	ctx, providers, accProviders := testAccFrameworkMuxProviders(context.Background(), t)
+	uniq := uniqueEntityName(ctx, t)
+
+	resource.Test(t, resource.TestCase{
+		ProtoV5ProviderFactories: accProviders,
+		CheckDestroy:             testAccCheckDatadogMonitorNotificationRuleDestroy(providers.frameworkProvider),
+		Steps: []resource.TestStep{
+			{
+				Config: testAccCheckDatadogMonitorNotificationRule(uniq),
+			},
+			{
+				ResourceName:      "datadog_monitor_notification_rule.r",
+				ImportState:       true,
+				ImportStateVerify: true,
+			},
+		},
+	})
+}
+
+func TestAccMonitorNotificationRule_Create(t *testing.T) {
+	t.Parallel()
+	ctx, providers, accProviders := testAccFrameworkMuxProviders(context.Background(), t)
+	uniq := uniqueEntityName(ctx, t)
+
+	resource.Test(t, resource.TestCase{
+		ProtoV5ProviderFactories: accProviders,
+		CheckDestroy:             testAccCheckDatadogMonitorNotificationRuleDestroy(providers.frameworkProvider),
+		Steps: []resource.TestStep{
+			{
+				Config: testAccCheckDatadogMonitorNotificationRule(uniq),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckDatadogMonitorNotificationRuleExists(providers.frameworkProvider),
+					resource.TestCheckResourceAttr(
+						"datadog_monitor_notification_rule.r", "name", "A notification rule name"),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "recipients.*", "slack-foo"),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "recipients.*", "jira-bar"),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "filter.tags.*", fmt.Sprintf("env:%s", uniq)),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "filter.tags.*", "host:abc"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccMonitorNotificationRule_Update(t *testing.T) {
+	t.Parallel()
+	ctx, providers, accProviders := testAccFrameworkMuxProviders(context.Background(), t)
+	uniq := uniqueEntityName(ctx, t)
+	uniq_updated := uniqueEntityName(ctx, t)
+
+	resource.Test(t, resource.TestCase{
+		ProtoV5ProviderFactories: accProviders,
+		CheckDestroy:             testAccCheckDatadogMonitorNotificationRuleDestroy(providers.frameworkProvider),
+		Steps: []resource.TestStep{
+			{
+				Config: testAccCheckDatadogMonitorNotificationRule(uniq),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckDatadogMonitorNotificationRuleExists(providers.frameworkProvider),
+					resource.TestCheckResourceAttr(
+						"datadog_monitor_notification_rule.r", "name", "A notification rule name"),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "recipients.*", "slack-foo"),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "recipients.*", "jira-bar"),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "filter.tags.*", fmt.Sprintf("env:%s", uniq)),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "filter.tags.*", "host:abc"),
+				),
+			},
+			{
+				Config: testAccCheckDatadogMonitorNotificationRule_update(uniq_updated),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckDatadogMonitorNotificationRuleExists(providers.frameworkProvider),
+					resource.TestCheckResourceAttr(
+						"datadog_monitor_notification_rule.r", "name", "Updated rule name"),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "recipients.*", "jira-foo"),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "recipients.*", "jira-bar"),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "filter.tags.*", fmt.Sprintf("env:%s", uniq_updated)),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "filter.tags.*", "host:abc"),
+					resource.TestCheckTypeSetElemAttr(
+						"datadog_monitor_notification_rule.r", "filter.tags.*", "poke:mon"),
+				),
+			},
+		},
+	})
+}
+
+func testAccCheckDatadogMonitorNotificationRule(uniq string) string {
+	// Update me to make use of the unique value
+	return fmt.Sprintf(`resource "datadog_monitor_notification_rule" "r" {
+    name = "A notification rule name"
+    recipients = ["slack-foo", "jira-bar"]
+	filter {
+	  tags = ["env:%s", "host:abc"]
+	}
+}`, uniq)
+}
+
+func testAccCheckDatadogMonitorNotificationRule_update(uniq string) string {
+	// Update me to make use of the unique value
+	return fmt.Sprintf(`resource "datadog_monitor_notification_rule" "r" {
+    name = "Updated rule name"
+    recipients = ["jira-foo", "jira-bar"]
+	filter {
+	  tags = ["env:%s", "host:abc", "poke:mon"]
+	}
+}`, uniq)
+}
+
+func testAccCheckDatadogMonitorNotificationRuleDestroy(accProvider *fwprovider.FrameworkProvider) func(*terraform.State) error {
+	return func(s *terraform.State) error {
+		apiInstances := accProvider.DatadogApiInstances
+		auth := accProvider.Auth
+
+		if err := MonitorNotificationRuleDestroyHelper(auth, s, apiInstances); err != nil {
+			return err
+		}
+		return nil
+	}
+}
+
+func MonitorNotificationRuleDestroyHelper(auth context.Context, s *terraform.State, apiInstances *utils.ApiInstances) error {
+	err := utils.Retry(2, 10, func() error {
+		for _, r := range s.RootModule().Resources {
+			if r.Type != "resource_datadog_monitor_notification_rule" {
+				continue
+			}
+			id := r.Primary.ID
+
+			_, httpResp, err := apiInstances.GetMonitorsApiV2().GetMonitorNotificationRule(auth, id)
+			if err != nil {
+				if httpResp != nil && httpResp.StatusCode == 404 {
+					return nil
+				}
+				return &utils.RetryableError{Prob: fmt.Sprintf("received an error retrieving MonitorNotificationRule %s", err)}
+			}
+			return &utils.RetryableError{Prob: "MonitorNotificationRule still exists"}
+		}
+		return nil
+	})
+	return err
+}
+
+func testAccCheckDatadogMonitorNotificationRuleExists(accProvider *fwprovider.FrameworkProvider) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		apiInstances := accProvider.DatadogApiInstances
+		auth := accProvider.Auth
+
+		if err := monitorNotificationRuleExistsHelper(auth, s, apiInstances); err != nil {
+			return err
+		}
+		return nil
+	}
+}
+
+func monitorNotificationRuleExistsHelper(auth context.Context, s *terraform.State, apiInstances *utils.ApiInstances) error {
+	for _, r := range s.RootModule().Resources {
+		if r.Type != "resource_datadog_monitor_notification_rule" {
+			continue
+		}
+		id := r.Primary.ID
+
+		_, httpResp, err := apiInstances.GetMonitorsApiV2().GetMonitorNotificationRule(auth, id)
+		if err != nil {
+			return utils.TranslateClientError(err, httpResp, "error retrieving MonitorNotificationRule")
+		}
+	}
+	return nil
+}
diff --git a/docs/resources/monitor_notification_rule.md b/docs/resources/monitor_notification_rule.md
new file mode 100644
index 0000000000..8934da3f3b
--- /dev/null
+++ b/docs/resources/monitor_notification_rule.md
@@ -0,0 +1,56 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "datadog_monitor_notification_rule Resource - terraform-provider-datadog"
+subcategory: ""
+description: |-
+  Provides a Datadog MonitorNotificationRule resource.
+---
+
+# datadog_monitor_notification_rule (Resource)
+
+Provides a Datadog MonitorNotificationRule resource.
+
+## Example Usage
+
+```terraform
+# Create new monitor_notification_rule resource
+
+resource "datadog_monitor_notification_rule" "foo" {
+  name       = "A notification rule name"
+  recipients = ["slack-test-channel", "jira-test"]
+  filter {
+    tags = ["env:foo"]
+  }
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `name` (String) The name of the monitor notification rule.
+- `recipients` (Set of String) List of recipients to notify.
+
+### Optional
+
+- `filter` (Block, Optional) (see [below for nested schema](#nestedblock--filter))
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+<a id="nestedblock--filter"></a>
+### Nested Schema for `filter`
+
+Required:
+
+- `tags` (Set of String) All tags that target monitors must match.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import datadog_monitor_notification_rule.new_list "00e000000-0000-1234-0000-000000000000"
+```
diff --git a/examples/resources/datadog_monitor_notification_rule/import.sh b/examples/resources/datadog_monitor_notification_rule/import.sh
new file mode 100644
index 0000000000..e4cfc480be
--- /dev/null
+++ b/examples/resources/datadog_monitor_notification_rule/import.sh
@@ -0,0 +1 @@
+terraform import datadog_monitor_notification_rule.new_list "00e000000-0000-1234-0000-000000000000"
\ No newline at end of file
diff --git a/examples/resources/datadog_monitor_notification_rule/resource.tf b/examples/resources/datadog_monitor_notification_rule/resource.tf
new file mode 100644
index 0000000000..0ec3a33118
--- /dev/null
+++ b/examples/resources/datadog_monitor_notification_rule/resource.tf
@@ -0,0 +1,9 @@
+# Create new monitor_notification_rule resource
+
+resource "datadog_monitor_notification_rule" "foo" {
+  name       = "A notification rule name"
+  recipients = ["slack-test-channel", "jira-test"]
+  filter {
+    tags = ["env:foo"]
+  }
+}
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 95ce1f2d08..e14c994f19 100644
--- a/go.mod
+++ b/go.mod
@@ -1,7 +1,7 @@
 module github.com/terraform-providers/terraform-provider-datadog
 
 require (
-	github.com/DataDog/datadog-api-client-go/v2 v2.37.2-0.20250414171606-63df4a4d718f
+	github.com/DataDog/datadog-api-client-go/v2 v2.37.2-0.20250417170906-65afec6a4463
 	github.com/DataDog/dd-sdk-go-testing v0.0.0-20211116174033-1cd082e322ad
 	github.com/Masterminds/semver/v3 v3.2.0
 	github.com/google/go-cmp v0.7.0
diff --git a/go.sum b/go.sum
index 12aec7bbdd..0b138a2537 100644
--- a/go.sum
+++ b/go.sum
@@ -2,8 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
 dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
 dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/DataDog/datadog-api-client-go/v2 v2.37.2-0.20250414171606-63df4a4d718f h1:S8xL/cTAlHJmcBS0NZ+pLHnY72dsdpDN9MAjE4jnOiU=
-github.com/DataDog/datadog-api-client-go/v2 v2.37.2-0.20250414171606-63df4a4d718f/go.mod h1:d3tOEgUd2kfsr9uuHQdY+nXrWp4uikgTgVCPdKNK30U=
+github.com/DataDog/datadog-api-client-go/v2 v2.37.2-0.20250417170906-65afec6a4463 h1:SeJRLPk5pUrd0egyhYdb10VfOdRdkcTVIVEDTkjMLGk=
+github.com/DataDog/datadog-api-client-go/v2 v2.37.2-0.20250417170906-65afec6a4463/go.mod h1:d3tOEgUd2kfsr9uuHQdY+nXrWp4uikgTgVCPdKNK30U=
 github.com/DataDog/datadog-go v4.4.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
 github.com/DataDog/datadog-go v4.8.3+incompatible h1:fNGaYSuObuQb5nzeTQqowRAd9bpDIRRV4/gUtIBjh8Q=
 github.com/DataDog/datadog-go v4.8.3+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=


Reviews:
user: login: shaneyuandd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T18:58:53Z
user: login: shaneyuandd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:49:52Z
user: login: maycmlee
body: Just a small suggestion
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T15:35:01Z
user: login: carlmartensen
body: Nice 👍 
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T16:25:13Z
user: login: carlmartensen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T16:29:54Z
user: login: shaneyuandd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T17:32:28Z
user: login: shaneyuandd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T17:33:08Z
user: login: MintsInc
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T07:45:24Z
user: login: shaneyuandd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T14:53:29Z
user: login: maycmlee
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T18:28:22Z
user: login: skarimo
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-25T18:31:59Z
user: login: fpighi
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-28T06:46:07Z

Review comments:
diff_hunk: @@ -0,0 +1,240 @@
+package fwprovider
+
+import (
+	"context"
+
+	"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+	"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	frameworkPath "github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	"github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
+)
+
+const resourceType = "monitor-notification-rule"
+
+var (
+	_ resource.ResourceWithConfigure   = &MonitorNotificationRuleResource{}
+	_ resource.ResourceWithImportState = &MonitorNotificationRuleResource{}
+)
+
+type MonitorNotificationRuleResource struct {
+	Api  *datadogV2.MonitorsApi
+	Auth context.Context
+}
+
+type MonitorNotificationRuleModel struct {
+	ID                                types.String                       `tfsdk:"id"`
+	Name                              types.String                       `tfsdk:"name"`
+	Recipients                        types.Set                          `tfsdk:"recipients"`
+	MonitorNotificationRuleTagsFilter *MonitorNotificationRuleTagsFilter `tfsdk:"tags_filter"`
+}
+
+type MonitorNotificationRuleTagsFilter struct {
+	Tags types.Set `tfsdk:"tags"`
+}
+
+func NewMonitorNotificationRuleResource() resource.Resource {
+	return &MonitorNotificationRuleResource{}
+}
+
+func (r *MonitorNotificationRuleResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
+	providerData, _ := request.ProviderData.(*FrameworkProvider)
+	r.Api = providerData.DatadogApiInstances.GetMonitorsApiV2()
+	r.Auth = providerData.Auth
+}
+
+func (r *MonitorNotificationRuleResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) {
+	response.TypeName = "monitor_notification_rule"
+}
+
+func (r *MonitorNotificationRuleResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
+	response.Schema = schema.Schema{
+		Description: "Provides a Datadog MonitorNotificationRule resource.",
+		Attributes: map[string]schema.Attribute{
+			"id": utils.ResourceIDAttribute(),
+			"name": schema.StringAttribute{
+				Required:    true,
+				Description: "The name of the monitor notification rule.",
+			},
+			"recipients": schema.SetAttribute{
+				Required:    true,
+				ElementType: types.StringType,
+				Description: "List of recipients to notify.",
+			},
+		},
+		Blocks: map[string]schema.Block{
+			"tags_filter": schema.SingleNestedBlock{
+				Attributes: map[string]schema.Attribute{
+					"tags": schema.SetAttribute{
+						Required:    true,
+						ElementType: types.StringType,
+						Description: "Tags that all target monitors must match.",
+					},
+				},
+				Validators: []validator.Object{objectvalidator.IsRequired()},
path: datadog/fwprovider/resource_datadog_monitor_notification_rule.go
user: login: shaneyuandd
body: This can be potentially confusing. The generated doc listed this field as `Optional` for now (which matches our low level API `oneOf`). However, given that we only support `tags_filter` right now, in practice this is actually a required field. 
created_at: 2025-04-18T18:58:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,251 @@
+package fwprovider
+
+import (
+	"context"
+
+	"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+	"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/resourcevalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	frameworkPath "github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	"github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
+)
+
+const resourceType = "monitor-notification-rule"
+
+var (
+	_ resource.ResourceWithConfigure   = &MonitorNotificationRuleResource{}
+	_ resource.ResourceWithImportState = &MonitorNotificationRuleResource{}
+)
+
+type MonitorNotificationRuleResource struct {
+	Api  *datadogV2.MonitorsApi
+	Auth context.Context
+}
+
+type MonitorNotificationRuleModel struct {
+	ID                            types.String                   `tfsdk:"id"`
+	Name                          types.String                   `tfsdk:"name"`
+	Recipients                    types.Set                      `tfsdk:"recipients"`
+	MonitorNotificationRuleFilter *MonitorNotificationRuleFilter `tfsdk:"filter"`
+}
+
+type MonitorNotificationRuleFilter struct {
+	Tags types.Set `tfsdk:"tags"`
+}
+
+func NewMonitorNotificationRuleResource() resource.Resource {
+	return &MonitorNotificationRuleResource{}
+}
+
+func (r *MonitorNotificationRuleResource) ConfigValidators(ctx context.Context) []resource.ConfigValidator {
+	return []resource.ConfigValidator{
+		resourcevalidator.ExactlyOneOf(
+			frameworkPath.MatchRoot("filter").AtName("tags"),
+		),
+	}
+}
+
+func (r *MonitorNotificationRuleResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
+	providerData, _ := request.ProviderData.(*FrameworkProvider)
+	r.Api = providerData.DatadogApiInstances.GetMonitorsApiV2()
+	r.Auth = providerData.Auth
+}
+
+func (r *MonitorNotificationRuleResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) {
+	response.TypeName = "monitor_notification_rule"
+}
+
+func (r *MonitorNotificationRuleResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
+	response.Schema = schema.Schema{
+		Description: "Provides a Datadog MonitorNotificationRule resource.",
+		Attributes: map[string]schema.Attribute{
+			"id": utils.ResourceIDAttribute(),
+			"name": schema.StringAttribute{
+				Required:    true,
+				Description: "The name of the monitor notification rule.",
+			},
+			"recipients": schema.SetAttribute{
+				Required:    true,
+				ElementType: types.StringType,
+				Description: "List of recipients to notify.",
+			},
+		},
+		Blocks: map[string]schema.Block{
+			"filter": schema.SingleNestedBlock{
+				Attributes: map[string]schema.Attribute{
+					"tags": schema.SetAttribute{
+						Required:    true,
path: datadog/fwprovider/resource_datadog_monitor_notification_rule.go
user: login: shaneyuandd
body: On the API level, `tags` is a `oneOf` field, so conceptually it's more like an optional field. However, since `tags` is currently the only available option now, it effectively functions as a required field in practice.


created_at: 2025-04-22T14:49:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,56 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "datadog_monitor_notification_rule Resource - terraform-provider-datadog"
+subcategory: ""
+description: |-
+  Provides a Datadog MonitorNotificationRule resource.
+---
+
+# datadog_monitor_notification_rule (Resource)
+
+Provides a Datadog MonitorNotificationRule resource.
+
+## Example Usage
+
+```terraform
+# Create new monitor_notification_rule resource
+
+resource "datadog_monitor_notification_rule" "foo" {
+  name       = "A notification rule name"
+  recipients = ["slack-test-channel", "jira-test"]
+  filter {
+    tags = ["env:foo"]
+  }
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `name` (String) The name of the monitor notification rule.
+- `recipients` (Set of String) List of recipients to notify.
+
+### Optional
+
+- `filter` (Block, Optional) (see [below for nested schema](#nestedblock--filter))
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+<a id="nestedblock--filter"></a>
+### Nested Schema for `filter`
+
+Required:
+
+- `tags` (Set of String) Tags that all target monitors must match.
path: docs/resources/monitor_notification_rule.md
user: login: maycmlee
body: ```suggestion
- `tags` (Set of String) All tags that target monitors must match.
```
created_at: 2025-04-22T15:34:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -437,6 +438,12 @@ func defaultConfigureFunc(p *FrameworkProvider, request *provider.ConfigureReque
 	ddClientConfig.SetUnstableOperationEnabled("v2.UpdatePipeline", true)
 	ddClientConfig.SetUnstableOperationEnabled("v2.DeletePipeline", true)
 
+	// Enable MonitorNotificationRule
+	ddClientConfig.SetUnstableOperationEnabled("v2.CreateMonitorNotificationRule", true)
path: datadog/fwprovider/framework_provider.go
user: login: carlmartensen
body: Is this needed for v2 endpoints?
created_at: 2025-04-22T16:21:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -51,6 +51,12 @@ func buildFrameworkDatadogClient(ctx context.Context, httpClient *http.Client) *
 	config.SetUnstableOperationEnabled("v2.UpdatePipeline", true)
 	config.SetUnstableOperationEnabled("v2.DeletePipeline", true)
 
+	// Enable MonitorNotificationRule
+	config.SetUnstableOperationEnabled("v2.CreateMonitorNotificationRule", true)
path: datadog/tests/framework_provider_test.go
user: login: carlmartensen
body: Unnecessary here also?
created_at: 2025-04-22T16:24:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,251 @@
+package fwprovider
+
+import (
+	"context"
+
+	"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+	"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/resourcevalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	frameworkPath "github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	"github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
+)
+
+const resourceType = "monitor-notification-rule"
+
+var (
+	_ resource.ResourceWithConfigure   = &MonitorNotificationRuleResource{}
+	_ resource.ResourceWithImportState = &MonitorNotificationRuleResource{}
+)
+
+type MonitorNotificationRuleResource struct {
+	Api  *datadogV2.MonitorsApi
+	Auth context.Context
+}
+
+type MonitorNotificationRuleModel struct {
+	ID                            types.String                   `tfsdk:"id"`
+	Name                          types.String                   `tfsdk:"name"`
+	Recipients                    types.Set                      `tfsdk:"recipients"`
+	MonitorNotificationRuleFilter *MonitorNotificationRuleFilter `tfsdk:"filter"`
+}
+
+type MonitorNotificationRuleFilter struct {
+	Tags types.Set `tfsdk:"tags"`
+}
+
+func NewMonitorNotificationRuleResource() resource.Resource {
+	return &MonitorNotificationRuleResource{}
+}
+
+func (r *MonitorNotificationRuleResource) ConfigValidators(ctx context.Context) []resource.ConfigValidator {
+	return []resource.ConfigValidator{
+		resourcevalidator.ExactlyOneOf(
+			frameworkPath.MatchRoot("filter").AtName("tags"),
+		),
+	}
+}
+
+func (r *MonitorNotificationRuleResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
+	providerData, _ := request.ProviderData.(*FrameworkProvider)
+	r.Api = providerData.DatadogApiInstances.GetMonitorsApiV2()
+	r.Auth = providerData.Auth
+}
+
+func (r *MonitorNotificationRuleResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) {
+	response.TypeName = "monitor_notification_rule"
+}
+
+func (r *MonitorNotificationRuleResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
+	response.Schema = schema.Schema{
+		Description: "Provides a Datadog MonitorNotificationRule resource.",
+		Attributes: map[string]schema.Attribute{
+			"id": utils.ResourceIDAttribute(),
+			"name": schema.StringAttribute{
+				Required:    true,
+				Description: "The name of the monitor notification rule.",
+			},
+			"recipients": schema.SetAttribute{
+				Required:    true,
+				ElementType: types.StringType,
+				Description: "List of recipients to notify.",
+			},
+		},
+		Blocks: map[string]schema.Block{
+			"filter": schema.SingleNestedBlock{
+				Attributes: map[string]schema.Attribute{
+					"tags": schema.SetAttribute{
path: datadog/fwprovider/resource_datadog_monitor_notification_rule.go
user: login: carlmartensen
body: Consider setting a min size `setvalidator.SizeAtLeast(1)` with recipients and tags
created_at: 2025-04-22T16:29:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -437,6 +438,12 @@ func defaultConfigureFunc(p *FrameworkProvider, request *provider.ConfigureReque
 	ddClientConfig.SetUnstableOperationEnabled("v2.UpdatePipeline", true)
 	ddClientConfig.SetUnstableOperationEnabled("v2.DeletePipeline", true)
 
+	// Enable MonitorNotificationRule
+	ddClientConfig.SetUnstableOperationEnabled("v2.CreateMonitorNotificationRule", true)
path: datadog/fwprovider/framework_provider.go
user: login: shaneyuandd
body: Preview endpoints are set by default as "Unstable Operation" on [Go client](https://github.com/DataDog/datadog-api-client-go/blob/65afec6a446323c465509119879cd3d702498a92/api/datadog/configuration.go#L367). Thus, the override is required, until status is cleared. 
created_at: 2025-04-22T17:32:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,251 @@
+package fwprovider
+
+import (
+	"context"
+
+	"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+	"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/resourcevalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	frameworkPath "github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	"github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
+)
+
+const resourceType = "monitor-notification-rule"
+
+var (
+	_ resource.ResourceWithConfigure   = &MonitorNotificationRuleResource{}
+	_ resource.ResourceWithImportState = &MonitorNotificationRuleResource{}
+)
+
+type MonitorNotificationRuleResource struct {
+	Api  *datadogV2.MonitorsApi
+	Auth context.Context
+}
+
+type MonitorNotificationRuleModel struct {
+	ID                            types.String                   `tfsdk:"id"`
+	Name                          types.String                   `tfsdk:"name"`
+	Recipients                    types.Set                      `tfsdk:"recipients"`
+	MonitorNotificationRuleFilter *MonitorNotificationRuleFilter `tfsdk:"filter"`
+}
+
+type MonitorNotificationRuleFilter struct {
+	Tags types.Set `tfsdk:"tags"`
+}
+
+func NewMonitorNotificationRuleResource() resource.Resource {
+	return &MonitorNotificationRuleResource{}
+}
+
+func (r *MonitorNotificationRuleResource) ConfigValidators(ctx context.Context) []resource.ConfigValidator {
+	return []resource.ConfigValidator{
+		resourcevalidator.ExactlyOneOf(
+			frameworkPath.MatchRoot("filter").AtName("tags"),
+		),
+	}
+}
+
+func (r *MonitorNotificationRuleResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
+	providerData, _ := request.ProviderData.(*FrameworkProvider)
+	r.Api = providerData.DatadogApiInstances.GetMonitorsApiV2()
+	r.Auth = providerData.Auth
+}
+
+func (r *MonitorNotificationRuleResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) {
+	response.TypeName = "monitor_notification_rule"
+}
+
+func (r *MonitorNotificationRuleResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
+	response.Schema = schema.Schema{
+		Description: "Provides a Datadog MonitorNotificationRule resource.",
+		Attributes: map[string]schema.Attribute{
+			"id": utils.ResourceIDAttribute(),
+			"name": schema.StringAttribute{
+				Required:    true,
+				Description: "The name of the monitor notification rule.",
+			},
+			"recipients": schema.SetAttribute{
+				Required:    true,
+				ElementType: types.StringType,
+				Description: "List of recipients to notify.",
+			},
+		},
+		Blocks: map[string]schema.Block{
+			"filter": schema.SingleNestedBlock{
+				Attributes: map[string]schema.Attribute{
+					"tags": schema.SetAttribute{
path: datadog/fwprovider/resource_datadog_monitor_notification_rule.go
user: login: shaneyuandd
body: Will add these checks
created_at: 2025-04-22T17:33:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,258 @@
+package fwprovider
+
+import (
+	"context"
+
+	"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+	"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/resourcevalidator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	frameworkPath "github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	"github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
+)
+
+const resourceType = "monitor-notification-rule"
+
+var (
+	_ resource.ResourceWithConfigure   = &MonitorNotificationRuleResource{}
+	_ resource.ResourceWithImportState = &MonitorNotificationRuleResource{}
+)
+
+type MonitorNotificationRuleResource struct {
+	Api  *datadogV2.MonitorsApi
+	Auth context.Context
+}
+
+type MonitorNotificationRuleModel struct {
+	ID                            types.String                   `tfsdk:"id"`
+	Name                          types.String                   `tfsdk:"name"`
+	Recipients                    types.Set                      `tfsdk:"recipients"`
+	MonitorNotificationRuleFilter *MonitorNotificationRuleFilter `tfsdk:"filter"`
+}
+
+type MonitorNotificationRuleFilter struct {
+	Tags types.Set `tfsdk:"tags"`
+}
+
+func NewMonitorNotificationRuleResource() resource.Resource {
+	return &MonitorNotificationRuleResource{}
+}
+
+func (r *MonitorNotificationRuleResource) ConfigValidators(ctx context.Context) []resource.ConfigValidator {
+	return []resource.ConfigValidator{
+		resourcevalidator.ExactlyOneOf(
+			frameworkPath.MatchRoot("filter").AtName("tags"),
+		),
+	}
+}
+
+func (r *MonitorNotificationRuleResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
+	providerData, _ := request.ProviderData.(*FrameworkProvider)
+	r.Api = providerData.DatadogApiInstances.GetMonitorsApiV2()
+	r.Auth = providerData.Auth
+}
+
+func (r *MonitorNotificationRuleResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) {
+	response.TypeName = "monitor_notification_rule"
+}
+
+func (r *MonitorNotificationRuleResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
+	response.Schema = schema.Schema{
+		Description: "Provides a Datadog MonitorNotificationRule resource.",
+		Attributes: map[string]schema.Attribute{
+			"id": utils.ResourceIDAttribute(),
+			"name": schema.StringAttribute{
+				Required:    true,
+				Description: "The name of the monitor notification rule.",
+			},
+			"recipients": schema.SetAttribute{
+				Required:    true,
+				ElementType: types.StringType,
+				Description: "List of recipients to notify.",
+				Validators: []validator.Set{
+					setvalidator.SizeAtLeast(1),
+				},
+			},
+		},
+		Blocks: map[string]schema.Block{
+			"filter": schema.SingleNestedBlock{
+				Attributes: map[string]schema.Attribute{
+					"tags": schema.SetAttribute{
+						Required:    true,
+						ElementType: types.StringType,
+						Description: "All tags that target monitors must match.",
+						Validators: []validator.Set{
+							setvalidator.SizeAtLeast(1),
+						},
+					},
+				},
+				Validators: []validator.Object{
+					objectvalidator.IsRequired(),
+				},
+			},
+		},
+	}
+}
+
+func (r *MonitorNotificationRuleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	resource.ImportStatePassthroughID(ctx, frameworkPath.Root("id"), req, resp)
+}
+
+func (r *MonitorNotificationRuleResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
+	var state MonitorNotificationRuleModel
+	response.Diagnostics.Append(request.State.Get(ctx, &state)...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+	id := state.ID.ValueString()
+
+	resp, httpResp, err := r.Api.GetMonitorNotificationRule(r.Auth, id)
+	if err != nil {
+		if httpResp != nil && httpResp.StatusCode == 404 {
+			response.State.RemoveResource(ctx)
+			return
+		}
+		response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error retrieving MonitorNotificationRule"))
+		return
+	}
+
+	r.updateState(ctx, &state, &resp)
+
+	// Save data into Terraform state
+	response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *MonitorNotificationRuleResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
+	var state MonitorNotificationRuleModel
+	response.Diagnostics.Append(request.Plan.Get(ctx, &state)...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	createRequest, diags := r.buildMonitorNotificationRuleCreateRequest(ctx, &state)
+	response.Diagnostics.Append(diags...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	resp, _, err := r.Api.CreateMonitorNotificationRule(r.Auth, *createRequest)
+	if err != nil {
+		response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error creating MonitorNotificationRule"))
+		return
+	}
+	r.updateState(ctx, &state, &resp)
+
+	// Save data into Terraform state
+	response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *MonitorNotificationRuleResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
+	var state MonitorNotificationRuleModel
+	response.Diagnostics.Append(request.Plan.Get(ctx, &state)...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	id := state.ID.ValueString()
+
+	updateRequest, diags := r.buildMonitorNotificationRuleUpdateRequest(ctx, &state)
+	response.Diagnostics.Append(diags...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	resp, _, err := r.Api.UpdateMonitorNotificationRule(r.Auth, id, *updateRequest)
+	if err != nil {
+		response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error updating MonitorNotificationRule"))
+		return
+	}
+	r.updateState(ctx, &state, &resp)
+
+	// Save data into Terraform state
+	response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *MonitorNotificationRuleResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) {
+	var state MonitorNotificationRuleModel
+	response.Diagnostics.Append(request.State.Get(ctx, &state)...)
path: datadog/fwprovider/resource_datadog_monitor_notification_rule.go
user: login: MintsInc
body: Any reason why this is not at the end of the function ?
created_at: 2025-04-23T07:45:18Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,258 @@
+package fwprovider
+
+import (
+	"context"
+
+	"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+	"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/resourcevalidator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	frameworkPath "github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	"github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
+)
+
+const resourceType = "monitor-notification-rule"
+
+var (
+	_ resource.ResourceWithConfigure   = &MonitorNotificationRuleResource{}
+	_ resource.ResourceWithImportState = &MonitorNotificationRuleResource{}
+)
+
+type MonitorNotificationRuleResource struct {
+	Api  *datadogV2.MonitorsApi
+	Auth context.Context
+}
+
+type MonitorNotificationRuleModel struct {
+	ID                            types.String                   `tfsdk:"id"`
+	Name                          types.String                   `tfsdk:"name"`
+	Recipients                    types.Set                      `tfsdk:"recipients"`
+	MonitorNotificationRuleFilter *MonitorNotificationRuleFilter `tfsdk:"filter"`
+}
+
+type MonitorNotificationRuleFilter struct {
+	Tags types.Set `tfsdk:"tags"`
+}
+
+func NewMonitorNotificationRuleResource() resource.Resource {
+	return &MonitorNotificationRuleResource{}
+}
+
+func (r *MonitorNotificationRuleResource) ConfigValidators(ctx context.Context) []resource.ConfigValidator {
+	return []resource.ConfigValidator{
+		resourcevalidator.ExactlyOneOf(
+			frameworkPath.MatchRoot("filter").AtName("tags"),
+		),
+	}
+}
+
+func (r *MonitorNotificationRuleResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
+	providerData, _ := request.ProviderData.(*FrameworkProvider)
+	r.Api = providerData.DatadogApiInstances.GetMonitorsApiV2()
+	r.Auth = providerData.Auth
+}
+
+func (r *MonitorNotificationRuleResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) {
+	response.TypeName = "monitor_notification_rule"
+}
+
+func (r *MonitorNotificationRuleResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
+	response.Schema = schema.Schema{
+		Description: "Provides a Datadog MonitorNotificationRule resource.",
+		Attributes: map[string]schema.Attribute{
+			"id": utils.ResourceIDAttribute(),
+			"name": schema.StringAttribute{
+				Required:    true,
+				Description: "The name of the monitor notification rule.",
+			},
+			"recipients": schema.SetAttribute{
+				Required:    true,
+				ElementType: types.StringType,
+				Description: "List of recipients to notify.",
+				Validators: []validator.Set{
+					setvalidator.SizeAtLeast(1),
+				},
+			},
+		},
+		Blocks: map[string]schema.Block{
+			"filter": schema.SingleNestedBlock{
+				Attributes: map[string]schema.Attribute{
+					"tags": schema.SetAttribute{
+						Required:    true,
+						ElementType: types.StringType,
+						Description: "All tags that target monitors must match.",
+						Validators: []validator.Set{
+							setvalidator.SizeAtLeast(1),
+						},
+					},
+				},
+				Validators: []validator.Object{
+					objectvalidator.IsRequired(),
+				},
+			},
+		},
+	}
+}
+
+func (r *MonitorNotificationRuleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	resource.ImportStatePassthroughID(ctx, frameworkPath.Root("id"), req, resp)
+}
+
+func (r *MonitorNotificationRuleResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
+	var state MonitorNotificationRuleModel
+	response.Diagnostics.Append(request.State.Get(ctx, &state)...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+	id := state.ID.ValueString()
+
+	resp, httpResp, err := r.Api.GetMonitorNotificationRule(r.Auth, id)
+	if err != nil {
+		if httpResp != nil && httpResp.StatusCode == 404 {
+			response.State.RemoveResource(ctx)
+			return
+		}
+		response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error retrieving MonitorNotificationRule"))
+		return
+	}
+
+	r.updateState(ctx, &state, &resp)
+
+	// Save data into Terraform state
+	response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *MonitorNotificationRuleResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
+	var state MonitorNotificationRuleModel
+	response.Diagnostics.Append(request.Plan.Get(ctx, &state)...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	createRequest, diags := r.buildMonitorNotificationRuleCreateRequest(ctx, &state)
+	response.Diagnostics.Append(diags...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	resp, _, err := r.Api.CreateMonitorNotificationRule(r.Auth, *createRequest)
+	if err != nil {
+		response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error creating MonitorNotificationRule"))
+		return
+	}
+	r.updateState(ctx, &state, &resp)
+
+	// Save data into Terraform state
+	response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *MonitorNotificationRuleResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
+	var state MonitorNotificationRuleModel
+	response.Diagnostics.Append(request.Plan.Get(ctx, &state)...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	id := state.ID.ValueString()
+
+	updateRequest, diags := r.buildMonitorNotificationRuleUpdateRequest(ctx, &state)
+	response.Diagnostics.Append(diags...)
+	if response.Diagnostics.HasError() {
+		return
+	}
+
+	resp, _, err := r.Api.UpdateMonitorNotificationRule(r.Auth, id, *updateRequest)
+	if err != nil {
+		response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error updating MonitorNotificationRule"))
+		return
+	}
+	r.updateState(ctx, &state, &resp)
+
+	// Save data into Terraform state
+	response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *MonitorNotificationRuleResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) {
+	var state MonitorNotificationRuleModel
+	response.Diagnostics.Append(request.State.Get(ctx, &state)...)
path: datadog/fwprovider/resource_datadog_monitor_notification_rule.go
user: login: shaneyuandd
body: This line appends the prior `request.State` into `response.Diagnostics`, which allows provider to know if it is ok to proceed with the deletion. The following line `response.Diagnostics.HasError()` won't catch any error if this is moved towards the end. ([Reference](https://developer.hashicorp.com/terraform/plugin/framework/resources/delete#define-delete-method))
created_at: 2025-04-23T14:53:29Z
author_association: CONTRIBUTOR

PR comments:
user: login: shaneyuandd
created_at: 2025-04-29T18:33:28Z
body: /merge
author_association: CONTRIBUTOR
user: login: dd-devflow[bot]
created_at: 2025-04-29T18:33:31Z
body: <!-- "FeedbackWorkflowId":"6112199f-c36c-452d-87ec-d07f86a33409_36" -->
[View all feedbacks in Devflow UI.](https://mosaic.us1.ddbuild.io/devflow/logs/6112199f-c36c-452d-87ec-d07f86a33409_36)

`2025-04-29 18:33:31 UTC` :information_source: Start processing command `/merge`

---
`2025-04-29 18:33:36 UTC` :information_source: **MergeQueue:** pull request added to the queue

The expected merge time in `master` is approximately 19m (p90).

---
`2025-04-29 18:51:07 UTC` :information_source: **MergeQueue:** This merge request was merged

author_association: NONE