diff --git a/GNUmakefile b/GNUmakefile
index 920c116..4f6e645 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -33,11 +33,9 @@ dev:
 	cd local && TF_LOG=TRACE terraform init -upgrade
 
 fmt:
-	go fmt ./checkly
-	terraform fmt
-
-doc:
-	./tools/tfplugindocs
+	go fmt ./...
+	terraform fmt -recursive
 
+# Generate docs
 generate:
-	go generate ./...
+	cd tools; go generate ./...
diff --git a/checkly/data_source_static_ips.go b/checkly/data_source_static_ips.go
deleted file mode 100644
index c5cbaa5..0000000
--- a/checkly/data_source_static_ips.go
+++ /dev/null
@@ -1,109 +0,0 @@
-package checkly
-
-import (
-	"context"
-	"fmt"
-	"slices"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	checkly "github.com/checkly/checkly-go-sdk"
-)
-
-func dataSourceStaticIPs() *schema.Resource {
-	return &schema.Resource{
-		Read: dataSourceStaticIPsRead,
-		Schema: map[string]*schema.Schema{
-			"id": {
-				Type:        schema.TypeString,
-				Computed:    true,
-				Description: "ID of the static IPs data source.",
-			},
-			"addresses": {
-				Type: schema.TypeSet,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-				Computed:    true,
-				Description: "Static IP addresses for Checkly's runner infrastructure.",
-			},
-			"locations": {
-				Type: schema.TypeSet,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-				Optional:    true,
-				Description: "Specify the locations you want to get static IPs for.",
-			},
-			"ip_family": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Description: "Specify the IP families you want to get static IPs for. Only `IPv6` or `IPv4` are valid options.",
-				ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
-					value := val.(string)
-					if !slices.Contains([]string{"IPv6", "IPv4"}, value) {
-						errs = append(errs, fmt.Errorf("%q must be either \"IPv6\" or \"IPv4\"", key))
-					}
-					return
-				},
-			},
-		},
-	}
-}
-
-func dataSourceStaticIPsRead(d *schema.ResourceData, client interface{}) error {
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	staticIPs, err := client.(checkly.Client).GetStaticIPs(ctx)
-	defer cancel()
-	if err != nil {
-		return fmt.Errorf("dateSourceStaticIPsRead: API error: %w", err)
-	}
-	return dataSourceFromStaticIPs(staticIPs, d)
-}
-
-func dataSourceFromStaticIPs(s []checkly.StaticIP, d *schema.ResourceData) error {
-	var staticIPs []checkly.StaticIP
-	var addresses []string
-
-	locations := stringsFromSet(d.Get("locations").(*schema.Set))
-	ip_family := d.Get("ip_family").(string)
-
-	// only locations is set for filtering
-	if len(locations) > 0 && ip_family == "" {
-		for _, ip := range s {
-			if slices.Contains(locations, ip.Region) {
-				staticIPs = append(staticIPs, ip)
-			}
-		}
-		// only ip_family is set for filtering
-	} else if ip_family != "" && len(locations) == 0 {
-		for _, ip := range s {
-			if ip_family == "IPv4" && ip.Address.Addr().Is4() {
-				staticIPs = append(staticIPs, ip)
-			} else if ip_family == "IPv6" && ip.Address.Addr().Is6() {
-				staticIPs = append(staticIPs, ip)
-			}
-		}
-		// both region and ip_family are set for filtering
-	} else if len(locations) > 0 && ip_family != "" {
-		for _, ip := range s {
-			if ip_family == "IPv4" && ip.Address.Addr().Is4() && slices.Contains(locations, ip.Region) {
-				staticIPs = append(staticIPs, ip)
-			} else if ip_family == "IPv6" && ip.Address.Addr().Is6() && slices.Contains(locations, ip.Region) {
-				staticIPs = append(staticIPs, ip)
-			}
-		}
-		// no region nor ip_family filters set
-	} else {
-		staticIPs = s
-	}
-
-	for _, ip := range staticIPs {
-		addresses = append(addresses, ip.Address.String())
-	}
-
-	d.Set("addresses", addresses)
-	d.SetId("checkly_static_ips_data_source_id")
-
-	return nil
-}
diff --git a/checkly/data_source_static_ips_test.go b/checkly/data_source_static_ips_test.go
deleted file mode 100644
index 0ba4bf4..0000000
--- a/checkly/data_source_static_ips_test.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package checkly
-
-import (
-	"regexp"
-	"testing"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-)
-
-func TestAccStaticIPsAll(t *testing.T) {
-	config := `data "checkly_static_ips" "test" {}`
-
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: config,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"data.checkly_static_ips.test",
-					"addresses.#",
-					"162",
-				),
-			),
-		},
-	})
-}
-
-func TestAccStaticIPsTwoRegionsOnly(t *testing.T) {
-	config := `data "checkly_static_ips" "test" {
-    locations = ["us-east-1","ap-southeast-1"]
-  }`
-
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: config,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"data.checkly_static_ips.test",
-					"addresses.#",
-					"20",
-				),
-			),
-		},
-	})
-}
-
-func TestAccStaticIPsIPv6Only(t *testing.T) {
-	config := `data "checkly_static_ips" "test" {
-    ip_family = "IPv6"
-  }`
-
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: config,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"data.checkly_static_ips.test",
-					"addresses.#",
-					"22",
-				),
-			),
-		},
-	})
-}
-
-func TestAccStaticIPsIPv4Only(t *testing.T) {
-	config := `data "checkly_static_ips" "test" {
-    ip_family = "IPv4"
-  }`
-
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: config,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"data.checkly_static_ips.test",
-					"addresses.#",
-					"140",
-				),
-			),
-		},
-	})
-}
-
-func TestAccStaticIPsIPv6AndOneRegionOnly(t *testing.T) {
-	config := `data "checkly_static_ips" "test" {
-    ip_family = "IPv6"
-    locations = ["us-east-1"]
-  }`
-
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: config,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"data.checkly_static_ips.test",
-					"addresses.#",
-					"1",
-				),
-			),
-		},
-	})
-}
-
-func TestAccStaticIPsIPv4AndOneRegionOnly(t *testing.T) {
-	config := `data "checkly_static_ips" "test" {
-    ip_family = "IPv4"
-    locations = ["us-east-1"]
-  }`
-
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: config,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"data.checkly_static_ips.test",
-					"addresses.#",
-					"12",
-				),
-			),
-		},
-	})
-}
-
-func TestAccStaticIPsInvalidIPFamily(t *testing.T) {
-	config := `data "checkly_static_ips" "test" {
-    ip_family = "invalid"
-  }`
-
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`"ip_family" must be either "IPv6" or "IPv4"`),
-		},
-	})
-}
diff --git a/checkly/error_with_log.go b/checkly/error_with_log.go
deleted file mode 100644
index 25acb78..0000000
--- a/checkly/error_with_log.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package checkly
-
-import (
-	"encoding/json"
-	"fmt"
-)
-
-// ErrorLog defines ErrorLog type
-type ErrorLog map[string]interface{}
-
-// ErrorWithLog defines checkly error type
-type ErrorWithLog struct {
-	Err  string
-	Data *ErrorLog
-}
-
-func (e ErrorWithLog) Error() string {
-	data, _ := json.Marshal(e.Data)
-	return fmt.Sprintf("%s [%s]", e.Err, data)
-}
-
-func makeError(err string, l *ErrorLog) ErrorWithLog {
-	return ErrorWithLog{err, l}
-}
diff --git a/checkly/helpers.go b/checkly/helpers.go
deleted file mode 100644
index a9233e4..0000000
--- a/checkly/helpers.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package checkly
-
-import (
-	"os"
-	"strconv"
-	"time"
-)
-
-func apiCallTimeout() time.Duration {
-	timeout := os.Getenv("API_CALL_TIMEOUT")
-	if timeout != "" {
-		v, err := strconv.ParseInt(timeout, 10, 64)
-		if err != nil || v < 1 {
-			panic("Invalid API_CALL_TIMEOUT value, must be a positive number")
-		} else {
-			return time.Duration(v) * time.Second
-		}
-	}
-	return 15 * time.Second
-}
diff --git a/checkly/integration_test.go b/checkly/integration_test.go
deleted file mode 100644
index fae3f59..0000000
--- a/checkly/integration_test.go
+++ /dev/null
@@ -1,50 +0,0 @@
-//go:build integration
-// +build integration
-
-package checkly
-
-import (
-	"os"
-	"testing"
-
-	"github.com/gruntwork-io/terratest/modules/terraform"
-)
-
-func getAPIKey(t *testing.T) string {
-	key := os.Getenv("CHECKLY_API_KEY")
-	if key == "" {
-		t.Fatal("'CHECKLY_API_KEY' must be set for integration tests")
-	}
-
-	return key
-}
-
-func getAccountId(t *testing.T) string {
-	key := os.Getenv("CHECKLY_ACCOUNT_ID")
-	if key == "" {
-		t.Fatal("'CHECKLY_ACCOUNT_ID' must be set for integration tests")
-	}
-	return key
-}
-
-func TestChecklyTerraformIntegration(t *testing.T) {
-	t.Parallel()
-	terraformOptions := &terraform.Options{
-		TerraformDir: "../",
-		Vars: map[string]interface{}{
-			"checkly_api_key":    getAPIKey(t),
-			"checkly_account_id": getAccountId(t),
-		},
-	}
-	defer terraform.Destroy(t, terraformOptions)
-	terraform.InitAndApply(t, terraformOptions)
-	planPath := "./test.plan"
-	exit, err := terraform.GetExitCodeForTerraformCommandE(t, terraformOptions, terraform.FormatArgs(terraformOptions, "plan", "--out="+planPath, "-input=false", "-lock=true", "-detailed-exitcode")...)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.Remove(planPath)
-	if exit != terraform.DefaultSuccessExitCode {
-		t.Fatalf("want DefaultSuccessExitCode, got %d", exit)
-	}
-}
diff --git a/checkly/provider.go b/checkly/provider.go
deleted file mode 100644
index 797126b..0000000
--- a/checkly/provider.go
+++ /dev/null
@@ -1,102 +0,0 @@
-package checkly
-
-import (
-	"fmt"
-	"io"
-	"os"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	"github.com/checkly/checkly-go-sdk"
-)
-
-// Provider makes the provider available to Terraform.
-func Provider() *schema.Provider {
-	return &schema.Provider{
-		Schema: map[string]*schema.Schema{
-			"api_key": {
-				Type:        schema.TypeString,
-				Required:    true,
-				DefaultFunc: schema.EnvDefaultFunc("CHECKLY_API_KEY", nil),
-			},
-			"api_url": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				DefaultFunc: schema.EnvDefaultFunc("CHECKLY_API_URL", nil),
-			},
-			"account_id": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				DefaultFunc: schema.EnvDefaultFunc("CHECKLY_ACCOUNT_ID", nil),
-			},
-		},
-		ResourcesMap: map[string]*schema.Resource{
-			"checkly_check":                resourceCheck(),
-			"checkly_heartbeat":            resourceHeartbeat(),
-			"checkly_check_group":          resourceCheckGroup(),
-			"checkly_snippet":              resourceSnippet(),
-			"checkly_dashboard":            resourceDashboard(),
-			"checkly_maintenance_windows":  resourceMaintenanceWindow(),
-			"checkly_alert_channel":        resourceAlertChannel(),
-			"checkly_trigger_check":        resourceTriggerCheck(),
-			"checkly_trigger_group":        resourceTriggerGroup(),
-			"checkly_environment_variable": resourceEnvironmentVariable(),
-			"checkly_private_location":     resourcePrivateLocation(),
-		},
-		DataSourcesMap: map[string]*schema.Resource{
-			"checkly_static_ips": dataSourceStaticIPs(),
-		},
-		ConfigureFunc: func(r *schema.ResourceData) (interface{}, error) {
-			debugLog := os.Getenv("CHECKLY_DEBUG_LOG")
-			var debugOutput io.Writer
-			if debugLog != "" {
-				debugFile, err := os.OpenFile(debugLog, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
-				if err != nil {
-					panic(fmt.Sprintf("can't write to debug log file: %v", err))
-				}
-				debugOutput = debugFile
-			}
-
-			apiKey := ""
-			switch v := r.Get("api_key").(type) {
-			case string:
-				apiKey = v
-			}
-
-			apiUrl := ""
-			switch v := r.Get("api_url").(type) {
-			case string:
-				apiUrl = v
-			}
-
-			if apiUrl == "" {
-				apiUrl = "https://api.checklyhq.com"
-			}
-
-			client := checkly.NewClient(
-				apiUrl,
-				apiKey,
-				nil,
-				debugOutput,
-			)
-
-			accountId := ""
-			switch v := r.Get("account_id").(type) {
-			case string:
-				accountId = v
-			}
-			if accountId != "" {
-				client.SetAccountId(accountId)
-			}
-
-			checklyApiSource := os.Getenv("CHECKLY_API_SOURCE")
-			if checklyApiSource != "" {
-				client.SetChecklySource(checklyApiSource)
-			} else {
-				client.SetChecklySource("TF")
-			}
-
-			return client, nil
-		},
-	}
-}
diff --git a/checkly/provider_test.go b/checkly/provider_test.go
deleted file mode 100644
index 4704aa9..0000000
--- a/checkly/provider_test.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package checkly
-
-import (
-	"testing"
-)
-
-func TestProvider(t *testing.T) {
-	if err := Provider().InternalValidate(); err != nil {
-		t.Fatalf("err: %s", err)
-	}
-}
diff --git a/checkly/resource_alert_channel.go b/checkly/resource_alert_channel.go
deleted file mode 100644
index ebcfdec..0000000
--- a/checkly/resource_alert_channel.go
+++ /dev/null
@@ -1,572 +0,0 @@
-package checkly
-
-import (
-	"context"
-	"encoding/json"
-	"fmt"
-	"strings"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	"github.com/checkly/checkly-go-sdk"
-)
-
-const (
-	AcFieldEmail                = "email"
-	AcFieldEmailAddress         = "address"
-	AcFieldSlack                = "slack"
-	AcFieldSlackURL             = "url"
-	AcFieldSlackChannel         = "channel"
-	AcFieldSMS                  = "sms"
-	AcFieldSMSName              = "name"
-	AcFieldSMSNumber            = "number"
-	AcFieldWebhook              = "webhook"
-	AcFieldWebhookName          = "name"
-	AcFieldWebhookMethod        = "method"
-	AcFieldWebhookHeaders       = "headers"
-	AcFieldWebhookQueryParams   = "query_parameters"
-	AcFieldWebhookTemplate      = "template"
-	AcFieldWebhookURL           = "url"
-	AcFieldWebhookSecret        = "webhook_secret"
-	AcFieldWebhookType          = "webhook_type"
-	AcFieldOpsgenie             = "opsgenie"
-	AcFieldOpsgenieName         = "name"
-	AcFieldOpsgenieAPIKey       = "api_key"
-	AcFieldOpsgenieRegion       = "region"
-	AcFieldOpsgeniePriority     = "priority"
-	AcFieldPagerduty            = "pagerduty"
-	AcFieldPagerdutyAccount     = "account"
-	AcFieldPagerdutyServiceKey  = "service_key"
-	AcFieldPagerdutyServiceName = "service_name"
-	AcFieldSendRecovery         = "send_recovery"
-	AcFieldSendFailure          = "send_failure"
-	AcFieldSendDegraded         = "send_degraded"
-	AcFieldSSLExpiry            = "ssl_expiry"
-	AcFieldSSLExpiryThreshold   = "ssl_expiry_threshold"
-	AcFieldCall                 = "call"
-	AcFieldCallName             = "name"
-	AcFieldCallNumber           = "number"
-)
-
-func resourceAlertChannel() *schema.Resource {
-	return &schema.Resource{
-		Description: "Allows you to define alerting channels for the checks and groups in your account",
-		Create:      resourceAlertChannelCreate,
-		Read:        resourceAlertChannelRead,
-		Update:      resourceAlertChannelUpdate,
-		Delete:      resourceAlertChannelDelete,
-		Importer: &schema.ResourceImporter{
-			StateContext: schema.ImportStatePassthroughContext,
-		},
-		Schema: map[string]*schema.Schema{
-			AcFieldEmail: {
-				Type:     schema.TypeSet,
-				Optional: true,
-				MaxItems: 1,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						AcFieldEmailAddress: {
-							Type:        schema.TypeString,
-							Required:    true,
-							Description: "The email address of this email alert channel.",
-						},
-					},
-				},
-			},
-			AcFieldSlack: {
-				Type:     schema.TypeSet,
-				Optional: true,
-				MaxItems: 1,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						AcFieldSlackURL: {
-							Type:        schema.TypeString,
-							Required:    true,
-							Description: "The Slack webhook URL",
-						},
-						AcFieldSlackChannel: {
-							Type:        schema.TypeString,
-							Required:    true,
-							Description: "The name of the alert's Slack channel",
-						},
-					},
-				},
-			},
-			AcFieldSMS: {
-				Type:     schema.TypeSet,
-				Optional: true,
-				MaxItems: 1,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						AcFieldSMSName: {
-							Type:        schema.TypeString,
-							Required:    true,
-							Description: "The name of this alert channel",
-						},
-						AcFieldSMSNumber: {
-							Type:        schema.TypeString,
-							Required:    true,
-							Description: "The mobile number to receive the alerts",
-						},
-					},
-				},
-			},
-			AcFieldCall: {
-				Type:     schema.TypeSet,
-				Optional: true,
-				MaxItems: 1,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						AcFieldCallName: {
-							Type:        schema.TypeString,
-							Required:    true,
-							Description: "The name of this alert channel",
-						},
-						AcFieldCallNumber: {
-							Type:        schema.TypeString,
-							Required:    true,
-							Description: "The mobile number to receive the alerts",
-						},
-					},
-				},
-			},
-			AcFieldWebhook: {
-				Type:     schema.TypeSet,
-				Optional: true,
-				MaxItems: 1,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						AcFieldWebhookName: {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						AcFieldWebhookMethod: {
-							Type:        schema.TypeString,
-							Optional:    true,
-							Default:     "POST",
-							Description: "(Default `POST`)",
-						},
-						AcFieldWebhookHeaders: {
-							Type:     schema.TypeMap,
-							Optional: true,
-							Computed: true,
-							DefaultFunc: func() (interface{}, error) {
-								return []tfMap{}, nil
-							},
-						},
-						AcFieldWebhookQueryParams: {
-							Type:     schema.TypeMap,
-							Optional: true,
-							Computed: true,
-							DefaultFunc: func() (interface{}, error) {
-								return []tfMap{}, nil
-							},
-						},
-						AcFieldWebhookTemplate: {
-							Type:     schema.TypeString,
-							Optional: true,
-						},
-						AcFieldWebhookURL: {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						AcFieldWebhookSecret: {
-							Type:     schema.TypeString,
-							Optional: true,
-						},
-						AcFieldWebhookType: {
-							Type:        schema.TypeString,
-							Optional:    true,
-							Description: "Type of the webhook. Possible values are 'WEBHOOK_DISCORD', 'WEBHOOK_FIREHYDRANT', 'WEBHOOK_GITLAB_ALERT', 'WEBHOOK_SPIKESH', 'WEBHOOK_SPLUNK', 'WEBHOOK_MSTEAMS' and 'WEBHOOK_TELEGRAM'.",
-							ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) {
-								v := value.(string)
-								isValid := false
-								options := []string{"WEBHOOK_DISCORD", "WEBHOOK_FIREHYDRANT", "WEBHOOK_GITLAB_ALERT", "WEBHOOK_SPIKESH", "WEBHOOK_SPLUNK", "WEBHOOK_MSTEAMS", "WEBHOOK_TELEGRAM"}
-								for _, option := range options {
-									if v == option {
-										isValid = true
-									}
-								}
-								if !isValid {
-									errs = append(errs, fmt.Errorf("%q must be one of %v, got %s", key, options, v))
-								}
-								return warns, errs
-							},
-						},
-					},
-				},
-			},
-			AcFieldOpsgenie: {
-				Type:     schema.TypeSet,
-				Optional: true,
-				MaxItems: 1,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						AcFieldOpsgenieName: {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						AcFieldOpsgenieAPIKey: {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						AcFieldOpsgenieRegion: {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						AcFieldOpsgeniePriority: {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-					},
-				},
-			},
-			AcFieldPagerduty: {
-				Type:     schema.TypeSet,
-				Optional: true,
-				MaxItems: 1,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						AcFieldPagerdutyServiceKey: {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						AcFieldPagerdutyServiceName: {
-							Type:     schema.TypeString,
-							Optional: true,
-						},
-						AcFieldPagerdutyAccount: {
-							Type:     schema.TypeString,
-							Optional: true,
-						},
-					},
-				},
-			},
-			AcFieldSendRecovery: {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Default:     true,
-				Description: "(Default `true`)",
-			},
-			AcFieldSendFailure: {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Default:     true,
-				Description: "(Default `true`)",
-			},
-			AcFieldSendDegraded: {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Default:     false,
-				Description: "(Default `false`)",
-			},
-			AcFieldSSLExpiry: {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Default:     false,
-				Description: "(Default `false`)",
-			},
-			AcFieldSSLExpiryThreshold: {
-				Type:     schema.TypeInt,
-				Optional: true,
-				Default:  30,
-				ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
-					min := 1
-					max := 30
-					v := val.(int)
-					if v < min || v > max {
-						errs = append(errs, fmt.Errorf("%q must be between %d and  %d, got: %d", key, min, max, v))
-					}
-					return warns, errs
-				},
-				Description: "Value must be between 1 and 30 (Default `30`)",
-			},
-		},
-	}
-}
-
-func resourceAlertChannelCreate(d *schema.ResourceData, client interface{}) error {
-	ac, err := alertChannelFromResourceData(d)
-	if err != nil {
-		return makeError("resourceAlertChannelCreate.1", &ErrorLog{"err": err.Error()})
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	resp, err := client.(checkly.Client).CreateAlertChannel(ctx, ac)
-	if err != nil {
-		cjson, _ := json.Marshal(ac.GetConfig())
-		return makeError("resourceAlertChannelCreate.2", &ErrorLog{
-			"err":    err.Error(),
-			"type":   ac.Type,
-			"config": string(cjson),
-		})
-	}
-	d.SetId(fmt.Sprintf("%d", resp.ID))
-	return resourceAlertChannelRead(d, client)
-}
-
-func resourceAlertChannelRead(d *schema.ResourceData, client interface{}) error {
-	ID, err := resourceIDToInt(d.Id())
-	if err != nil {
-		return makeError("resourceAlertChannelRead.1", &ErrorLog{"err": err.Error()})
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	ac, err := client.(checkly.Client).GetAlertChannel(ctx, ID)
-	if err != nil {
-		if strings.Contains(err.Error(), "404") {
-			//if resource is deleted remotely, then mark it as
-			//successfully gone by unsetting it's ID
-			d.SetId("")
-			return nil
-		}
-		return makeError("resourceAlertChannelRead.2", &ErrorLog{"err": err.Error()})
-	}
-	return resourceDataFromAlertChannel(ac, d)
-}
-
-func resourceAlertChannelUpdate(d *schema.ResourceData, client interface{}) error {
-	ac, err := alertChannelFromResourceData(d)
-	if err != nil {
-		return makeError("resourceAlertChannelUpdate.1", &ErrorLog{"err": err.Error()})
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	_, err = client.(checkly.Client).UpdateAlertChannel(ctx, ac.ID, ac)
-	if err != nil {
-		return makeError("resourceAlertChannelUpdate.2", &ErrorLog{"err": err.Error()})
-	}
-	d.SetId(fmt.Sprintf("%d", ac.ID))
-	return resourceAlertChannelRead(d, client)
-}
-
-func resourceAlertChannelDelete(d *schema.ResourceData, client interface{}) error {
-	ID, err := resourceIDToInt(d.Id())
-	if err != nil {
-		return makeError("resourceAlertChannelDelete.1", &ErrorLog{"err": err.Error()})
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	if err := client.(checkly.Client).DeleteAlertChannel(ctx, ID); err != nil {
-		return makeError("resourceAlertChannelDelete.2", &ErrorLog{"err": err.Error()})
-	}
-	return nil
-}
-
-func resourceDataFromAlertChannel(it *checkly.AlertChannel, d *schema.ResourceData) error {
-	d.Set(AcFieldEmail, setFromEmail(it.Email))
-	d.Set(AcFieldSMS, setFromSMS(it.SMS))
-	d.Set(AcFieldCall, setFromCall(it.CALL))
-	d.Set(AcFieldSlack, setFromSlack(it.Slack))
-	d.Set(AcFieldWebhook, setFromWebhook(it.Webhook))
-	d.Set(AcFieldOpsgenie, setFromOpsgenie(it.Opsgenie))
-	d.Set(AcFieldPagerduty, setFromPagerduty(it.Pagerduty))
-	if it.SendRecovery != nil {
-		d.Set(AcFieldSendRecovery, *it.SendRecovery)
-	}
-	if it.SendFailure != nil {
-		d.Set(AcFieldSendFailure, *it.SendFailure)
-	}
-	if it.SendDegraded != nil {
-		d.Set(AcFieldSendDegraded, *it.SendDegraded)
-	}
-	if it.SSLExpiry != nil {
-		d.Set(AcFieldSSLExpiry, *it.SSLExpiry)
-	}
-	if it.SSLExpiryThreshold != nil {
-		d.Set(AcFieldSSLExpiryThreshold, *it.SSLExpiryThreshold)
-	}
-	return nil
-}
-
-func alertChannelFromResourceData(d *schema.ResourceData) (checkly.AlertChannel, error) {
-	ac := checkly.AlertChannel{}
-	ID, err := resourceIDToInt(d.Id())
-	if err != nil {
-		return ac, makeError("alertChannelFromResourceData.1", &ErrorLog{"err": err.Error()})
-	}
-	if err == nil {
-		ac.ID = ID
-	}
-
-	sendRecovery := d.Get(AcFieldSendRecovery).(bool)
-	ac.SendRecovery = &sendRecovery
-
-	sendFailure := d.Get(AcFieldSendFailure).(bool)
-	ac.SendFailure = &sendFailure
-
-	sndDegraded := d.Get(AcFieldSendDegraded).(bool)
-	ac.SendDegraded = &sndDegraded
-
-	sslExpiry := d.Get(AcFieldSSLExpiry).(bool)
-	ac.SSLExpiry = &sslExpiry
-
-	if v, ok := d.GetOk(AcFieldSSLExpiryThreshold); ok {
-		i := v.(int)
-		ac.SSLExpiryThreshold = &i
-	}
-
-	fields := []string{AcFieldEmail, AcFieldSMS, AcFieldCall, AcFieldSlack, AcFieldWebhook, AcFieldOpsgenie, AcFieldPagerduty}
-	setCount := 0
-	for _, field := range fields {
-		cfgSet := (d.Get(field)).(*schema.Set)
-		if cfgSet.Len() > 0 {
-			ac.Type = strings.ToUpper(field)
-			c, err := alertChannelConfigFromSet(ac.Type, cfgSet)
-			if err != nil {
-				return ac, makeError("alertChannelFromResourceData.2", &ErrorLog{"err": err.Error()})
-			}
-			ac.SetConfig(c)
-			setCount++
-		}
-	}
-	if setCount > 1 {
-		return ac, makeError("Alert-Channel config can't contain more than one Channel", nil)
-	}
-	return ac, nil
-}
-
-func alertChannelConfigFromSet(channelType string, s *schema.Set) (interface{}, error) {
-	if s.Len() == 0 {
-		return nil, nil
-	}
-	cfg := s.List()[0].(map[string]interface{})
-	switch channelType {
-	case checkly.AlertTypeEmail:
-		return &checkly.AlertChannelEmail{
-			Address: cfg[AcFieldEmailAddress].(string),
-		}, nil
-	case checkly.AlertTypeSMS:
-		return &checkly.AlertChannelSMS{
-			Name:   cfg[AcFieldSMSName].(string),
-			Number: cfg[AcFieldSMSNumber].(string),
-		}, nil
-	case checkly.AlertTypeCall:
-		return &checkly.AlertChannelCall{
-			Name:   cfg[AcFieldCallName].(string),
-			Number: cfg[AcFieldCallNumber].(string),
-		}, nil
-	case checkly.AlertTypeSlack:
-		return &checkly.AlertChannelSlack{
-			Channel:    cfg[AcFieldSlackChannel].(string),
-			WebhookURL: cfg[AcFieldSlackURL].(string),
-		}, nil
-	case checkly.AlertTypeOpsgenie:
-		return &checkly.AlertChannelOpsgenie{
-			Name:     cfg[AcFieldOpsgenieName].(string),
-			APIKey:   cfg[AcFieldOpsgenieAPIKey].(string),
-			Region:   cfg[AcFieldOpsgenieRegion].(string),
-			Priority: cfg[AcFieldOpsgeniePriority].(string),
-		}, nil
-	case checkly.AlertTypePagerduty:
-		return &checkly.AlertChannelPagerduty{
-			Account:     cfg[AcFieldPagerdutyAccount].(string),
-			ServiceKey:  cfg[AcFieldPagerdutyServiceKey].(string),
-			ServiceName: cfg[AcFieldPagerdutyServiceName].(string),
-		}, nil
-	case checkly.AlertTypeWebhook:
-		return &checkly.AlertChannelWebhook{
-			Name:            cfg[AcFieldWebhookName].(string),
-			Method:          cfg[AcFieldWebhookMethod].(string),
-			Template:        cfg[AcFieldWebhookTemplate].(string),
-			URL:             cfg[AcFieldWebhookURL].(string),
-			WebhookSecret:   cfg[AcFieldWebhookSecret].(string),
-			WebhookType:     cfg[AcFieldWebhookType].(string),
-			Headers:         keyValuesFromMap(cfg[AcFieldWebhookHeaders].(tfMap)),
-			QueryParameters: keyValuesFromMap(cfg[AcFieldWebhookQueryParams].(tfMap)),
-		}, nil
-	}
-	return nil, makeError("alertChannelConfigFromSet:unkownType", nil)
-}
-
-func setFromEmail(cfg *checkly.AlertChannelEmail) []tfMap {
-	if cfg == nil {
-		return []tfMap{}
-	}
-	return []tfMap{
-		{
-			AcFieldEmailAddress: cfg.Address,
-		},
-	}
-}
-
-func setFromSMS(cfg *checkly.AlertChannelSMS) []tfMap {
-	if cfg == nil {
-		return []tfMap{}
-	}
-	return []tfMap{
-		{
-			AcFieldSMSName:   cfg.Name,
-			AcFieldSMSNumber: cfg.Number,
-		},
-	}
-}
-
-func setFromCall(cfg *checkly.AlertChannelCall) []tfMap {
-	if cfg == nil {
-		return []tfMap{}
-	}
-	return []tfMap{
-		{
-			AcFieldCallName:   cfg.Name,
-			AcFieldCallNumber: cfg.Number,
-		},
-	}
-}
-
-func setFromSlack(cfg *checkly.AlertChannelSlack) []tfMap {
-	if cfg == nil {
-		return []tfMap{}
-	}
-	return []tfMap{
-		{
-			AcFieldSlackChannel: cfg.Channel,
-			AcFieldSlackURL:     cfg.WebhookURL,
-		},
-	}
-}
-
-func setFromWebhook(cfg *checkly.AlertChannelWebhook) []tfMap {
-	if cfg == nil {
-		return []tfMap{}
-	}
-	return []tfMap{
-		{
-			AcFieldWebhookName:        cfg.Name,
-			AcFieldWebhookMethod:      cfg.Method,
-			AcFieldWebhookHeaders:     mapFromKeyValues(cfg.Headers),
-			AcFieldWebhookQueryParams: mapFromKeyValues(cfg.QueryParameters),
-			AcFieldWebhookTemplate:    cfg.Template,
-			AcFieldWebhookURL:         cfg.URL,
-			AcFieldWebhookSecret:      cfg.WebhookSecret,
-			AcFieldWebhookType:        cfg.WebhookType,
-		},
-	}
-}
-
-func setFromOpsgenie(cfg *checkly.AlertChannelOpsgenie) []tfMap {
-	if cfg == nil {
-		return []tfMap{}
-	}
-	return []tfMap{
-		{
-			AcFieldOpsgenieName:     cfg.Name,
-			AcFieldOpsgenieAPIKey:   cfg.APIKey,
-			AcFieldOpsgenieRegion:   cfg.Region,
-			AcFieldOpsgeniePriority: cfg.Priority,
-		},
-	}
-}
-
-func setFromPagerduty(cfg *checkly.AlertChannelPagerduty) []tfMap {
-	if cfg == nil {
-		return []tfMap{}
-	}
-	return []tfMap{
-		{
-			AcFieldPagerdutyAccount:     cfg.Account,
-			AcFieldPagerdutyServiceKey:  cfg.ServiceKey,
-			AcFieldPagerdutyServiceName: cfg.ServiceName,
-		},
-	}
-}
diff --git a/checkly/resource_alert_channel_test.go b/checkly/resource_alert_channel_test.go
deleted file mode 100644
index 884c0c0..0000000
--- a/checkly/resource_alert_channel_test.go
+++ /dev/null
@@ -1,202 +0,0 @@
-package checkly
-
-import (
-	"fmt"
-	"regexp"
-	"testing"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-)
-
-func TestAccEmail(t *testing.T) {
-	t.Parallel()
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: `resource "checkly_alert_channel" "t1" {
-				email {
-					address = "info@example.com"
-				}
-				send_recovery = false
-				send_failure  = false
-				send_degraded = false
-				ssl_expiry    = false
-				ssl_expiry_threshold = 10
-				}`,
-		},
-	})
-}
-
-func TestAccSlack(t *testing.T) {
-	t.Parallel()
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: `resource "checkly_alert_channel" "slack_ac" {
-				slack {
-					channel = "checkly_alerts"
-					url     = "https://hooks.slack.com/services/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"
-				}
-				send_recovery        = true
-				send_failure         = true
-				send_degraded        = false
-				ssl_expiry           = true
-				ssl_expiry_threshold = 11
-			}`,
-		},
-	})
-}
-
-func TestAccSMS(t *testing.T) {
-	t.Parallel()
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: `resource "checkly_alert_channel" "sms_ac" {
-				sms {
-					name   = "smsalerts"
-					number = "4917512345678"
-				}
-			}`,
-		},
-	})
-}
-
-func TestAccOpsgenie(t *testing.T) {
-	t.Parallel()
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: `resource "checkly_alert_channel" "opsgenie_ac" {
-				opsgenie {
-					name     = "opsalert"
-					api_key  = "key1"
-					region   = "EU"
-					priority = "P1"
-				}
-			}`,
-		},
-	})
-}
-
-func TestAccPagerduty(t *testing.T) {
-	t.Parallel()
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: `resource "checkly_alert_channel" "pagerduty_ac" {
-				pagerduty {
-					account      = "checkly"
-					service_key  = "key1"
-					service_name = "pdalert"
-				}
-			}`,
-		},
-	})
-}
-
-func TestAccWebhook(t *testing.T) {
-	t.Parallel()
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: `resource "checkly_alert_channel" "webhook_ac" {
-				webhook {
-				  name   = "webhhookalerts"
-				  method = "get"
-				  headers  = {
-					X-HEADER-1 = "foo"
-				  }
-				  query_parameters = {
-					query1 = "bar"
-				  }
-				  template       = "tmpl"
-				  url            = "https://example.com/webhook"
-				  webhook_secret = "foo-secret"
-				}
-			  }`,
-		},
-	})
-}
-
-func TestAccFail(t *testing.T) {
-	t.Parallel()
-	cases := []struct {
-		Config string
-		Error  string
-	}{
-		{
-			Config: `resource "checkly_alert_channel" "t1" {
-				email {	}
-			}`,
-			Error: `The argument "address" is required`,
-		},
-		{
-			Config: `resource "checkly_alert_channel" "t1" {
-				sms {
-				}
-			}`,
-			Error: `The argument "number" is required`,
-		},
-		{
-			Config: `resource "checkly_alert_channel" "t1" {
-				slack {
-				}
-			}`,
-			Error: `The argument "channel" is required`,
-		},
-		{
-			Config: `resource "checkly_alert_channel" "t1" {
-				slack {
-				}
-			}`,
-			Error: `Missing required argument`,
-		},
-		{
-			Config: `resource "checkly_alert_channel" "t1" {
-				webhook {
-				}
-			}`,
-			Error: `The argument "name" is required`,
-		},
-		{
-			Config: `resource "checkly_alert_channel" "t1" {
-				webhook {
-				}
-			}`,
-			Error: `The argument "url" is required`,
-		},
-		{
-			Config: `resource "checkly_alert_channel" "t1" {
-				opsgenie {
-				}
-			}`,
-			Error: `The argument "api_key" is required`,
-		},
-		{
-			Config: `resource "checkly_alert_channel" "t1" {
-				opsgenie {
-				}
-			}`,
-			Error: `The argument "priority" is required`,
-		},
-		{
-			Config: `resource "checkly_alert_channel" "t1" {
-				opsgenie {
-				}
-			}`,
-			Error: `The argument "region" is required`,
-		},
-		{
-			Config: `resource "checkly_alert_channel" "t1" {
-				pagerduty {
-				}
-			}`,
-			Error: `The argument "service_key" is required`,
-		},
-	}
-	for key, tc := range cases {
-		t.Run(fmt.Sprintf("%d", key), func(t *testing.T) {
-			accTestCase(t, []resource.TestStep{
-				{
-					Config:      tc.Config,
-					ExpectError: regexp.MustCompile(tc.Error),
-				},
-			})
-		})
-	}
-}
diff --git a/checkly/resource_check.go b/checkly/resource_check.go
deleted file mode 100644
index 7d390b8..0000000
--- a/checkly/resource_check.go
+++ /dev/null
@@ -1,1115 +0,0 @@
-package checkly
-
-import (
-	"context"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"sort"
-	"strings"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	"github.com/checkly/checkly-go-sdk"
-)
-
-// tfMap is a shorthand alias for convenience; Terraform uses this type a *lot*.
-type tfMap = map[string]interface{}
-
-func resourceCheck() *schema.Resource {
-	return &schema.Resource{
-		Create: resourceCheckCreate,
-		Read:   resourceCheckRead,
-		Update: resourceCheckUpdate,
-		Delete: resourceCheckDelete,
-		Importer: &schema.ResourceImporter{
-			StateContext: schema.ImportStatePassthroughContext,
-		},
-		Description: "Checks allows you to monitor key webapp flows, backend API's and set up alerting, so you get a notification when things break or slow down.",
-		Schema: map[string]*schema.Schema{
-			"name": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "The name of the check.",
-			},
-			"type": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "The type of the check. Possible values are `API`, `BROWSER`, and `MULTI_STEP`.",
-			},
-			"frequency": {
-				Type:     schema.TypeInt,
-				Required: true,
-				ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
-					v := val.(int)
-					valid := false
-					validFreqs := []int{0, 1, 2, 5, 10, 15, 30, 60, 120, 180, 360, 720, 1440}
-					for _, i := range validFreqs {
-						if v == i {
-							valid = true
-						}
-					}
-					if !valid {
-						errs = append(errs, fmt.Errorf("%q must be one of %v, got %d", key, validFreqs, v))
-					}
-					return warns, errs
-				},
-				Description: "The frequency in minutes to run the check. Possible values are `0`, `1`, `2`, `5`, `10`, `15`, `30`, `60`, `120`, `180`, `360`, `720`, and `1440`.",
-			},
-			"frequency_offset": {
-				Type:        schema.TypeInt,
-				Optional:    true,
-				Description: "This property only valid for API high frequency checks. To create a hight frequency check, the property `frequency` must be `0` and `frequency_offset` could be `10`, `20` or `30`.",
-			},
-			"activated": {
-				Type:        schema.TypeBool,
-				Required:    true,
-				Description: "Determines if the check is running or not. Possible values `true`, and `false`.",
-			},
-			"muted": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Description: "Determines if any notifications will be sent out when a check fails/degrades/recovers.",
-			},
-			"should_fail": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Description: "Allows to invert the behaviour of when a check is considered to fail. Allows for validating error status like 404.",
-			},
-			"run_parallel": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Description: "Determines if the check should run in all selected locations in parallel or round-robin.",
-			},
-			"locations": {
-				Type:     schema.TypeSet,
-				Optional: true,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-				Description: "An array of one or more data center locations where to run the this check. (Default [\"us-east-1\"])",
-			},
-			"script": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Default:     "",
-				Description: "A valid piece of Node.js JavaScript code describing a browser interaction with the Puppeteer/Playwright framework or a reference to an external JavaScript file.",
-			},
-			"degraded_response_time": {
-				Type:     schema.TypeInt,
-				Optional: true,
-				Default:  15000,
-				ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
-					// https://checklyhq.com/docs/api-checks/limits/
-					v := val.(int)
-					if v < 0 || v > 30000 {
-						errs = append(errs, fmt.Errorf("%q must be 0-30000 ms, got %d", key, v))
-					}
-					return warns, errs
-				},
-				Description: "The response time in milliseconds starting from which a check should be considered degraded. Possible values are between 0 and 30000. (Default `15000`).",
-			},
-			"max_response_time": {
-				Type:     schema.TypeInt,
-				Optional: true,
-				Default:  30000,
-				ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
-					v := val.(int)
-					// https://checklyhq.com/docs/api-checks/limits/
-					if v < 0 || v > 30000 {
-						errs = append(errs, fmt.Errorf("%q must be 0-30000 ms, got: %d", key, v))
-					}
-					return warns, errs
-				},
-				Description: "The response time in milliseconds starting from which a check should be considered failing. Possible values are between 0 and 30000. (Default `30000`).",
-			},
-			"environment_variables": {
-				Type:        schema.TypeMap,
-				Optional:    true,
-				Deprecated:  "The property `environment_variables` is deprecated and will be removed in a future version. Consider using the new `environment_variable` list.",
-				Description: "Key/value pairs for setting environment variables during check execution. These are only relevant for browser checks. Use global environment variables whenever possible.",
-			},
-			"environment_variable": {
-				Type:        schema.TypeList,
-				Optional:    true,
-				Description: "Key/value pairs for setting environment variables during check execution, add locked = true to keep value hidden, add secret = true to create a secret variable. These are only relevant for browser checks. Use global environment variables whenever possible.",
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"key": {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						"value": {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						"locked": {
-							Type:     schema.TypeBool,
-							Optional: true,
-							Default:  false,
-						},
-						"secret": {
-							Type:     schema.TypeBool,
-							Optional: true,
-							Default:  false,
-						},
-					},
-				},
-			},
-			"double_check": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Description: "Setting this to `true` will trigger a retry when a check fails from the failing region and another, randomly selected region before marking the check as failed.",
-				Deprecated:  "The property `double_check` is deprecated and will be removed in a future version. To enable retries for failed check runs, use the `retry_strategy` property instead.",
-			},
-			"tags": {
-				Type:     schema.TypeSet,
-				Optional: true,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-				Description: "A list of tags for organizing and filtering checks.",
-			},
-			"ssl_check": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Deprecated:  "The property `ssl_check` is deprecated and it's ignored by the Checkly Public API. It will be removed in a future version.",
-				Description: "Determines if the SSL certificate should be validated for expiry.",
-			},
-			"ssl_check_domain": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Description: "A valid fully qualified domain name (FQDN) to check its SSL certificate.",
-			},
-			"setup_snippet_id": {
-				Type:        schema.TypeInt,
-				Optional:    true,
-				Description: "An ID reference to a snippet to use in the setup phase of an API check.",
-			},
-			"teardown_snippet_id": {
-				Type:        schema.TypeInt,
-				Optional:    true,
-				Description: "An ID reference to a snippet to use in the teardown phase of an API check.",
-			},
-			"local_setup_script": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Description: "A valid piece of Node.js code to run in the setup phase.",
-			},
-			"local_teardown_script": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Description: "A valid piece of Node.js code to run in the teardown phase.",
-			},
-			"runtime_id": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Default:     nil,
-				Description: "The id of the runtime to use for this check.",
-			},
-			"alert_channel_subscription": {
-				Type:        schema.TypeList,
-				Optional:    true,
-				Description: "An array of channel IDs and whether they're activated or not. If you don't set at least one alert subscription for your check, we won't be able to alert you in case something goes wrong with it.",
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"channel_id": {
-							Type:     schema.TypeInt,
-							Required: true,
-						},
-						"activated": {
-							Type:     schema.TypeBool,
-							Required: true,
-						},
-					},
-				},
-			},
-			"private_locations": {
-				Type:     schema.TypeSet,
-				Optional: true,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-				DefaultFunc: func() (interface{}, error) {
-					return []tfMap{}, nil
-				},
-				Description: "An array of one or more private locations slugs.",
-			},
-			"alert_settings": {
-				Type:     schema.TypeList,
-				Optional: true,
-				Computed: true,
-				MaxItems: 1,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"escalation_type": {
-							Type:        schema.TypeString,
-							Optional:    true,
-							Description: "Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`.",
-						},
-						"run_based_escalation": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Computed: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"failed_run_threshold": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Description: "After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`).",
-									},
-								},
-							},
-						},
-						"time_based_escalation": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Computed: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"minutes_failing_threshold": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Description: "After how many minutes after a check starts failing an alert should be sent. Possible values are `5`, `10`, `15`, and `30`. (Default `5`).",
-									},
-								},
-							},
-						},
-						"reminders": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Computed: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"amount": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Description: "How many reminders to send out after the initial alert notification. Possible values are `0`, `1`, `2`, `3`, `4`, `5`, and `100000`",
-									},
-									"interval": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Default:     5,
-										Description: "Possible values are `5`, `10`, `15`, and `30`. (Default `5`).",
-									},
-								},
-							},
-						},
-						"parallel_run_failure_threshold": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Computed: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"enabled": {
-										Type:        schema.TypeBool,
-										Optional:    true,
-										Default:     false,
-										Description: "Applicable only for checks scheduled in parallel in multiple locations.",
-									},
-									"percentage": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Default:     10,
-										Description: "Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `100`, and `100`. (Default `10`).",
-									},
-								},
-							},
-						},
-						"ssl_certificates": {
-							Type:       schema.TypeSet,
-							Optional:   true,
-							Deprecated: "This property is deprecated and it's ignored by the Checkly Public API. It will be removed in a future version.",
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"enabled": {
-										Type:        schema.TypeBool,
-										Optional:    true,
-										Description: "Determines if alert notifications should be sent for expiring SSL certificates. Possible values `true`, and `false`. (Default `false`).",
-									},
-									"alert_threshold": {
-										Type:     schema.TypeInt,
-										Optional: true,
-										ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
-											v := val.(int)
-											valid := false
-											validFreqs := []int{3, 7, 14, 30}
-											for _, i := range validFreqs {
-												if v == i {
-													valid = true
-												}
-											}
-											if !valid {
-												errs = append(errs, fmt.Errorf("%q must be one of %v, got: %d", key, validFreqs, v))
-											}
-											return warns, errs
-										},
-										Description: "How long before SSL certificate expiry to send alerts. Possible values `3`, `7`, `14`, `30`. (Default `3`).",
-									},
-								},
-								Description: "At what interval the reminders should be sent.",
-							},
-						},
-					},
-				},
-			},
-			"use_global_alert_settings": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Description: "When true, the account level alert settings will be used, not the alert setting defined on this check.",
-			},
-			"request": {
-				Type:     schema.TypeSet,
-				Optional: true,
-				MaxItems: 1,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"method": {
-							Type:        schema.TypeString,
-							Optional:    true,
-							Default:     "GET",
-							Description: "The HTTP method to use for this API check. Possible values are `GET`, `POST`, `PUT`, `HEAD`, `DELETE`, `PATCH`. (Default `GET`).",
-						},
-						"url": {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						"follow_redirects": {
-							Type:     schema.TypeBool,
-							Optional: true,
-						},
-						"skip_ssl": {
-							Type:     schema.TypeBool,
-							Optional: true,
-						},
-						"headers": {
-							Type:     schema.TypeMap,
-							Optional: true,
-							Computed: true,
-							DefaultFunc: func() (interface{}, error) {
-								return []tfMap{}, nil
-							},
-						},
-						"query_parameters": {
-							Type:     schema.TypeMap,
-							Optional: true,
-							Computed: true,
-							DefaultFunc: func() (interface{}, error) {
-								return []tfMap{}, nil
-							},
-						},
-						"body": {
-							Type:        schema.TypeString,
-							Optional:    true,
-							Description: "The body of the request.",
-						},
-						"body_type": {
-							Type:        schema.TypeString,
-							Optional:    true,
-							Default:     "NONE",
-							Description: "The `Content-Type` header of the request. Possible values `NONE`, `JSON`, `FORM`, `RAW`, and `GRAPHQL`.",
-							ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) {
-								v := value.(string)
-								isValid := false
-								options := []string{"NONE", "JSON", "FORM", "RAW", "GRAPHQL"}
-								for _, option := range options {
-									if v == option {
-										isValid = true
-									}
-								}
-								if !isValid {
-									errs = append(errs, fmt.Errorf("%q must be one of %v, got %s", key, options, v))
-								}
-								return warns, errs
-							},
-						},
-						"assertion": {
-							Type:     schema.TypeSet,
-							Optional: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"source": {
-										Type:        schema.TypeString,
-										Required:    true,
-										Description: "The source of the asserted value. Possible values `STATUS_CODE`, `JSON_BODY`, `HEADERS`, `TEXT_BODY`, and `RESPONSE_TIME`.",
-									},
-									"property": {
-										Type:     schema.TypeString,
-										Optional: true,
-									},
-									"comparison": {
-										Type:        schema.TypeString,
-										Required:    true,
-										Description: "The type of comparison to be executed between expected and actual value of the assertion. Possible values `EQUALS`, `NOT_EQUALS`, `HAS_KEY`, `NOT_HAS_KEY`, `HAS_VALUE`, `NOT_HAS_VALUE`, `IS_EMPTY`, `NOT_EMPTY`, `GREATER_THAN`, `LESS_THAN`, `CONTAINS`, `NOT_CONTAINS`, `IS_NULL`, and `NOT_NULL`.",
-									},
-									"target": {
-										Type:     schema.TypeString,
-										Optional: true,
-									},
-								},
-							},
-							Description: "A request can have multiple assertions.",
-						},
-						"basic_auth": {
-							Type:     schema.TypeSet,
-							MaxItems: 1,
-							Optional: true,
-							Computed: true,
-							DefaultFunc: func() (interface{}, error) {
-								return []tfMap{}, nil
-							},
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"username": {
-										Type:     schema.TypeString,
-										Required: true,
-									},
-									"password": {
-										Type:     schema.TypeString,
-										Required: true,
-									},
-								},
-							},
-							Description: "Set up HTTP basic authentication (username & password).",
-						},
-						"ip_family": {
-							Type:        schema.TypeString,
-							Optional:    true,
-							Default:     "IPv4",
-							Description: "IP Family to be used when executing the api check. The value can be either IPv4 or IPv6.",
-							ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) {
-								v := value.(string)
-								isValid := false
-								options := []string{"IPv4", "IPv6"}
-								for _, option := range options {
-									if v == option {
-										isValid = true
-									}
-								}
-								if !isValid {
-									errs = append(errs, fmt.Errorf("%q must be one of %v, got %s", key, options, v))
-								}
-								return warns, errs
-							},
-						},
-					},
-				},
-				Description: "An API check might have one request config.",
-			},
-			"group_id": {
-				Type:        schema.TypeInt,
-				Optional:    true,
-				Description: "The id of the check group this check is part of.",
-			},
-			"group_order": {
-				Type:        schema.TypeInt,
-				Optional:    true,
-				Description: "The position of this check in a check group. It determines in what order checks are run when a group is triggered from the API or from CI/CD.",
-			},
-			"retry_strategy": {
-				Type:     schema.TypeSet,
-				Optional: true,
-				Computed: true,
-				MaxItems: 1,
-				DefaultFunc: func() (interface{}, error) {
-					return []tfMap{}, nil
-				},
-				Description: "A strategy for retrying failed check runs.",
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"type": {
-							Type:        schema.TypeString,
-							Required:    true,
-							Description: "Determines which type of retry strategy to use. Possible values are `FIXED`, `LINEAR`, or `EXPONENTIAL`.",
-						},
-						"base_backoff_seconds": {
-							Type:        schema.TypeInt,
-							Optional:    true,
-							Default:     60,
-							Description: "The number of seconds to wait before the first retry attempt.",
-						},
-						"max_retries": {
-							Type:        schema.TypeInt,
-							Optional:    true,
-							Default:     2,
-							Description: "The maximum number of times to retry the check. Value must be between 1 and 10.",
-						},
-						"max_duration_seconds": {
-							Type:        schema.TypeInt,
-							Optional:    true,
-							Default:     600,
-							Description: "The total amount of time to continue retrying the check (maximum 600 seconds).",
-						},
-						"same_region": {
-							Type:        schema.TypeBool,
-							Optional:    true,
-							Default:     true,
-							Description: "Whether retries should be run in the same region as the initial check run.",
-						},
-					},
-				},
-			},
-		},
-	}
-}
-
-func resourceCheckCreate(d *schema.ResourceData, client interface{}) error {
-	check, err := checkFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("translation error: %w", err)
-	}
-
-	validationErr := validateRuntimeSupport(check, client)
-	if validationErr != nil {
-		return validationErr
-	}
-
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	newCheck, err := client.(checkly.Client).CreateCheck(ctx, check)
-
-	if err != nil {
-		checkJSON, _ := json.Marshal(check)
-		return fmt.Errorf("API error 1: %w, Check: %s", err, string(checkJSON))
-	}
-	d.SetId(newCheck.ID)
-	return resourceCheckRead(d, client)
-}
-
-func resourceCheckRead(d *schema.ResourceData, client interface{}) error {
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	check, err := client.(checkly.Client).GetCheck(ctx, d.Id())
-	if err != nil {
-		if strings.Contains(err.Error(), "404") {
-			//if resource is deleted remotely, then mark it as
-			//successfully gone by unsetting it's ID
-			d.SetId("")
-			return nil
-		}
-		return fmt.Errorf("API error 2: %w", err)
-	}
-	return resourceDataFromCheck(check, d)
-}
-
-func resourceCheckUpdate(d *schema.ResourceData, client interface{}) error {
-	check, err := checkFromResourceData(d)
-
-	if err != nil {
-		return fmt.Errorf("translation error: %w", err)
-	}
-
-	validationErr := validateRuntimeSupport(check, client)
-	if validationErr != nil {
-		return validationErr
-	}
-
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	_, err = client.(checkly.Client).UpdateCheck(ctx, check.ID, check)
-	if err != nil {
-		checkJSON, _ := json.Marshal(check)
-		return fmt.Errorf("API error 3: Couldn't update check, Error: %w, \nCheck: %s", err, checkJSON)
-	}
-	d.SetId(check.ID)
-	return resourceCheckRead(d, client)
-}
-
-func resourceCheckDelete(d *schema.ResourceData, client interface{}) error {
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	if err := client.(checkly.Client).DeleteCheck(ctx, d.Id()); err != nil {
-		return fmt.Errorf("API error 4: Couldn't delete Check %s, Error: %w", d.Id(), err)
-	}
-	return nil
-}
-
-func resourceDataFromCheck(c *checkly.Check, d *schema.ResourceData) error {
-	d.Set("name", c.Name)
-	d.Set("type", c.Type)
-	d.Set("activated", c.Activated)
-	d.Set("muted", c.Muted)
-	d.Set("should_fail", c.ShouldFail)
-	d.Set("run_parallel", c.RunParallel)
-	d.Set("locations", c.Locations)
-	d.Set("script", c.Script)
-	d.Set("degraded_response_time", c.DegradedResponseTime)
-	d.Set("max_response_time", c.MaxResponseTime)
-	d.Set("double_check", c.DoubleCheck)
-	d.Set("setup_snippet_id", c.SetupSnippetID)
-	d.Set("teardown_snippet_id", c.TearDownSnippetID)
-	d.Set("local_setup_script", c.LocalSetupScript)
-	d.Set("local_teardown_script", c.LocalTearDownScript)
-
-	sort.Strings(c.Tags)
-	d.Set("tags", c.Tags)
-
-	d.Set("frequency", c.Frequency)
-	if c.Frequency == 0 {
-		d.Set("frequency_offset", c.FrequencyOffset)
-	}
-
-	if c.RuntimeID != nil {
-		d.Set("runtime_id", *c.RuntimeID)
-	}
-
-	// ssl_check_domain is only supported for Browser checks
-	if c.Type == "BROWSER" && c.SSLCheckDomain != "" {
-		d.Set("ssl_check_domain", c.SSLCheckDomain)
-	}
-
-	environmentVariables := environmentVariablesFromSet(d.Get("environment_variable").([]interface{}))
-	if len(environmentVariables) > 0 {
-		d.Set("environment_variable", c.EnvironmentVariables)
-	} else if err := d.Set("environment_variables", setFromEnvVars(c.EnvironmentVariables)); err != nil {
-		return fmt.Errorf("error setting environment variables for resource %s: %s", d.Id(), err)
-	}
-
-	if err := d.Set("alert_settings", setFromAlertSettings(c.AlertSettings)); err != nil {
-		return fmt.Errorf("error setting alert settings for resource %s: %w", d.Id(), err)
-	}
-	d.Set("use_global_alert_settings", c.UseGlobalAlertSettings)
-
-	if c.Type == checkly.TypeAPI {
-		err := d.Set("request", setFromRequest(c.Request))
-		if err != nil {
-			return fmt.Errorf("error setting request for resource %s: %w", d.Id(), err)
-		}
-	}
-	d.Set("group_id", c.GroupID)
-	d.Set("group_order", c.GroupOrder)
-	d.Set("private_locations", c.PrivateLocations)
-	d.Set("alert_channel_subscription", c.AlertChannelSubscriptions)
-	d.Set("retry_strategy", setFromRetryStrategy(c.RetryStrategy))
-	d.SetId(d.Id())
-	return nil
-}
-
-func setFromEnvVars(evs []checkly.EnvironmentVariable) tfMap {
-	var s = tfMap{}
-	for _, ev := range evs {
-		s[ev.Key] = ev.Value
-	}
-	return s
-}
-
-func setFromAlertSettings(as checkly.AlertSettings) []tfMap {
-	if as.EscalationType == checkly.RunBased {
-		return []tfMap{
-			{
-				"escalation_type": as.EscalationType,
-				"run_based_escalation": []tfMap{
-					{
-						"failed_run_threshold": as.RunBasedEscalation.FailedRunThreshold,
-					},
-				},
-				"reminders": []tfMap{
-					{
-						"amount":   as.Reminders.Amount,
-						"interval": as.Reminders.Interval,
-					},
-				},
-				"parallel_run_failure_threshold": []tfMap{
-					{
-						"enabled":    as.ParallelRunFailureThreshold.Enabled,
-						"percentage": as.ParallelRunFailureThreshold.Percentage,
-					},
-				},
-			},
-		}
-	} else {
-		return []tfMap{
-			{
-				"escalation_type": as.EscalationType,
-				"time_based_escalation": []tfMap{
-					{
-						"minutes_failing_threshold": as.TimeBasedEscalation.MinutesFailingThreshold,
-					},
-				},
-				"reminders": []tfMap{
-					{
-						"amount":   as.Reminders.Amount,
-						"interval": as.Reminders.Interval,
-					},
-				},
-				"parallel_run_failure_threshold": []tfMap{
-					{
-						"enabled":    as.ParallelRunFailureThreshold.Enabled,
-						"percentage": as.ParallelRunFailureThreshold.Percentage,
-					},
-				},
-			},
-		}
-	}
-}
-
-func setFromRequest(r checkly.Request) []tfMap {
-	s := tfMap{}
-	s["method"] = r.Method
-	s["url"] = r.URL
-	s["follow_redirects"] = r.FollowRedirects
-	s["skip_ssl"] = r.SkipSSL
-	s["body"] = r.Body
-	s["body_type"] = r.BodyType
-	s["headers"] = mapFromKeyValues(r.Headers)
-	s["query_parameters"] = mapFromKeyValues(r.QueryParameters)
-	s["assertion"] = setFromAssertions(r.Assertions)
-	s["basic_auth"] = setFromBasicAuth(r.BasicAuth)
-	s["ip_family"] = r.IPFamily
-	return []tfMap{s}
-}
-
-func setFromAssertions(assertions []checkly.Assertion) []tfMap {
-	s := make([]tfMap, len(assertions))
-	for i, a := range assertions {
-		as := tfMap{}
-		as["source"] = a.Source
-		as["property"] = a.Property
-		as["comparison"] = a.Comparison
-		as["target"] = a.Target
-		s[i] = as
-	}
-	return s
-}
-
-func mapFromKeyValues(kvs []checkly.KeyValue) tfMap {
-	var s = tfMap{}
-	for _, item := range kvs {
-		s[item.Key] = item.Value
-	}
-	return s
-}
-
-func setFromBasicAuth(b *checkly.BasicAuth) []tfMap {
-	if b == nil {
-		return []tfMap{}
-	}
-	return []tfMap{
-		{
-			"username": b.Username,
-			"password": b.Password,
-		},
-	}
-}
-
-func setFromRetryStrategy(rs *checkly.RetryStrategy) []tfMap {
-	if rs == nil {
-		return []tfMap{}
-	}
-	return []tfMap{
-		{
-			"type":                 rs.Type,
-			"base_backoff_seconds": rs.BaseBackoffSeconds,
-			"max_retries":          rs.MaxRetries,
-			"max_duration_seconds": rs.MaxDurationSeconds,
-			"same_region":          rs.SameRegion,
-		},
-	}
-}
-
-func checkFromResourceData(d *schema.ResourceData) (checkly.Check, error) {
-	check := checkly.Check{
-		ID:                        d.Id(),
-		Name:                      d.Get("name").(string),
-		Type:                      d.Get("type").(string),
-		Frequency:                 d.Get("frequency").(int),
-		Activated:                 d.Get("activated").(bool),
-		Muted:                     d.Get("muted").(bool),
-		ShouldFail:                d.Get("should_fail").(bool),
-		RunParallel:               d.Get("run_parallel").(bool),
-		Locations:                 stringsFromSet(d.Get("locations").(*schema.Set)),
-		Script:                    d.Get("script").(string),
-		DegradedResponseTime:      d.Get("degraded_response_time").(int),
-		MaxResponseTime:           d.Get("max_response_time").(int),
-		DoubleCheck:               d.Get("double_check").(bool),
-		Tags:                      stringsFromSet(d.Get("tags").(*schema.Set)),
-		SSLCheck:                  d.Get("ssl_check").(bool),
-		SSLCheckDomain:            d.Get("ssl_check_domain").(string),
-		SetupSnippetID:            int64(d.Get("setup_snippet_id").(int)),
-		TearDownSnippetID:         int64(d.Get("teardown_snippet_id").(int)),
-		LocalSetupScript:          d.Get("local_setup_script").(string),
-		LocalTearDownScript:       d.Get("local_teardown_script").(string),
-		AlertSettings:             alertSettingsFromSet(d.Get("alert_settings").([]interface{})),
-		UseGlobalAlertSettings:    d.Get("use_global_alert_settings").(bool),
-		GroupID:                   int64(d.Get("group_id").(int)),
-		GroupOrder:                d.Get("group_order").(int),
-		AlertChannelSubscriptions: alertChannelSubscriptionsFromSet(d.Get("alert_channel_subscription").([]interface{})),
-		RetryStrategy:             retryStrategyFromSet(d.Get("retry_strategy").(*schema.Set)),
-	}
-
-	runtimeId := d.Get("runtime_id").(string)
-	if runtimeId == "" {
-		check.RuntimeID = nil
-	} else {
-		check.RuntimeID = &runtimeId
-	}
-
-	environmentVariables, err := getResourceEnvironmentVariables(d)
-	if err != nil {
-		return checkly.Check{}, err
-	}
-	check.EnvironmentVariables = environmentVariables
-
-	privateLocations := stringsFromSet(d.Get("private_locations").(*schema.Set))
-	check.PrivateLocations = &privateLocations
-
-	if check.Type == checkly.TypeAPI {
-		// this will prevent subsequent apply from causing a tf config change in browser checks
-		check.Request = requestFromSet(d.Get("request").(*schema.Set))
-		check.FrequencyOffset = d.Get("frequency_offset").(int)
-
-		if check.Frequency == 0 && (check.FrequencyOffset != 10 && check.FrequencyOffset != 20 && check.FrequencyOffset != 30) {
-			return check, errors.New("when property frequency is 0, frequency_offset must be 10, 20 or 30")
-		}
-
-		if check.SSLCheckDomain != "" {
-			return check, errors.New("ssl_check_domain is allowed only for Browser checks")
-		}
-	}
-
-	if check.Type == checkly.TypeBrowser && check.Frequency == 0 {
-		return check, errors.New("property frequency could only be 0 for API checks")
-	}
-
-	return check, nil
-}
-
-func stringsFromSet(s *schema.Set) []string {
-	r := make([]string, s.Len())
-	for i, item := range s.List() {
-		r[i] = item.(string)
-	}
-	return r
-}
-
-func assertionsFromSet(s *schema.Set) []checkly.Assertion {
-	r := make([]checkly.Assertion, s.Len())
-	for i, item := range s.List() {
-		res := item.(tfMap)
-		r[i] = checkly.Assertion{
-			Source:     res["source"].(string),
-			Property:   res["property"].(string),
-			Comparison: res["comparison"].(string),
-			Target:     res["target"].(string),
-		}
-	}
-	return r
-}
-
-func basicAuthFromSet(s *schema.Set) *checkly.BasicAuth {
-	if s.Len() == 0 {
-		return nil
-	}
-	res := s.List()[0].(tfMap)
-	return &checkly.BasicAuth{
-		Username: res["username"].(string),
-		Password: res["password"].(string),
-	}
-}
-
-func alertSettingsFromSet(s []interface{}) checkly.AlertSettings {
-	if len(s) == 0 {
-		return checkly.AlertSettings{
-			EscalationType: checkly.RunBased,
-			RunBasedEscalation: checkly.RunBasedEscalation{
-				FailedRunThreshold: 1,
-			},
-		}
-	}
-	res := s[0].(tfMap)
-	alertSettings := checkly.AlertSettings{
-		EscalationType:              res["escalation_type"].(string),
-		Reminders:                   remindersFromSet(res["reminders"].([]interface{})),
-		ParallelRunFailureThreshold: parallelRunFailureThresholdFromSet(res["parallel_run_failure_threshold"].([]interface{})),
-	}
-
-	if alertSettings.EscalationType == checkly.RunBased {
-		alertSettings.RunBasedEscalation = runBasedEscalationFromSet(res["run_based_escalation"].([]interface{}))
-	} else {
-		alertSettings.TimeBasedEscalation = timeBasedEscalationFromSet(res["time_based_escalation"].([]interface{}))
-	}
-
-	return alertSettings
-}
-
-func retryStrategyFromSet(s *schema.Set) *checkly.RetryStrategy {
-	if s.Len() == 0 {
-		return nil
-	}
-	res := s.List()[0].(tfMap)
-	return &checkly.RetryStrategy{
-		Type:               res["type"].(string),
-		BaseBackoffSeconds: res["base_backoff_seconds"].(int),
-		MaxRetries:         res["max_retries"].(int),
-		MaxDurationSeconds: res["max_duration_seconds"].(int),
-		SameRegion:         res["same_region"].(bool),
-	}
-}
-
-func alertChannelSubscriptionsFromSet(s []interface{}) []checkly.AlertChannelSubscription {
-	res := []checkly.AlertChannelSubscription{}
-	if len(s) == 0 {
-		return res
-	}
-	for _, it := range s {
-		tm := it.(tfMap)
-		chid := tm["channel_id"].(int)
-		activated := tm["activated"].(bool)
-		res = append(res, checkly.AlertChannelSubscription{
-			Activated: activated,
-			ChannelID: int64(chid),
-		})
-	}
-	return res
-}
-
-func environmentVariablesFromSet(s []interface{}) []checkly.EnvironmentVariable {
-	res := []checkly.EnvironmentVariable{}
-	if len(s) == 0 {
-		return res
-	}
-	for _, it := range s {
-		tm := it.(tfMap)
-		key := tm["key"].(string)
-		value := tm["value"].(string)
-		locked := tm["locked"].(bool)
-		secret := tm["secret"].(bool)
-		res = append(res, checkly.EnvironmentVariable{
-			Key:    key,
-			Value:  value,
-			Locked: locked,
-			Secret: secret,
-		})
-	}
-
-	return res
-}
-
-func runBasedEscalationFromSet(s []interface{}) checkly.RunBasedEscalation {
-	if len(s) == 0 {
-		return checkly.RunBasedEscalation{}
-	}
-	res := s[0].(tfMap)
-	return checkly.RunBasedEscalation{
-		FailedRunThreshold: res["failed_run_threshold"].(int),
-	}
-}
-
-func timeBasedEscalationFromSet(s []interface{}) checkly.TimeBasedEscalation {
-	if len(s) == 0 {
-		return checkly.TimeBasedEscalation{}
-	}
-	res := s[0].(tfMap)
-	return checkly.TimeBasedEscalation{
-		MinutesFailingThreshold: res["minutes_failing_threshold"].(int),
-	}
-}
-
-func remindersFromSet(s []interface{}) checkly.Reminders {
-	if len(s) == 0 {
-		return checkly.Reminders{}
-	}
-	res := s[0].(tfMap)
-	return checkly.Reminders{
-		Amount:   res["amount"].(int),
-		Interval: res["interval"].(int),
-	}
-}
-
-func parallelRunFailureThresholdFromSet(s []interface{}) checkly.ParallelRunFailureThreshold {
-	if len(s) == 0 {
-		return checkly.ParallelRunFailureThreshold{}
-	}
-	res := s[0].(tfMap)
-	return checkly.ParallelRunFailureThreshold{
-		Enabled:    res["enabled"].(bool),
-		Percentage: res["percentage"].(int),
-	}
-}
-
-func requestFromSet(s *schema.Set) checkly.Request {
-	if s.Len() == 0 {
-		return checkly.Request{}
-	}
-	res := s.List()[0].(tfMap)
-	return checkly.Request{
-		Method:          res["method"].(string),
-		URL:             res["url"].(string),
-		FollowRedirects: res["follow_redirects"].(bool),
-		SkipSSL:         res["skip_ssl"].(bool),
-		Body:            res["body"].(string),
-		BodyType:        res["body_type"].(string),
-		Headers:         keyValuesFromMap(res["headers"].(tfMap)),
-		QueryParameters: keyValuesFromMap(res["query_parameters"].(tfMap)),
-		Assertions:      assertionsFromSet(res["assertion"].(*schema.Set)),
-		BasicAuth:       basicAuthFromSet(res["basic_auth"].(*schema.Set)),
-		IPFamily:        res["ip_family"].(string),
-	}
-}
-
-func envVarsFromMap(m map[string]interface{}) []checkly.EnvironmentVariable {
-	r := make([]checkly.EnvironmentVariable, 0, len(m))
-	for k, v := range m {
-		s, ok := v.(string)
-		if !ok {
-			panic(fmt.Errorf("could not convert environment variable value %v to string", v))
-		}
-
-		r = append(r, checkly.EnvironmentVariable{
-			Key:   k,
-			Value: s,
-		})
-
-	}
-	return r
-}
-
-func keyValuesFromMap(m map[string]interface{}) []checkly.KeyValue {
-	r := make([]checkly.KeyValue, 0, len(m))
-	for k, v := range m {
-		s, ok := v.(string)
-		if !ok {
-			panic(fmt.Errorf("could not convert environment variable value %v to string", v))
-		}
-		r = append(r, checkly.KeyValue{
-			Key:   k,
-			Value: s,
-		})
-	}
-	return r
-}
-
-func getResourceEnvironmentVariables(d *schema.ResourceData) ([]checkly.EnvironmentVariable, error) {
-	deprecatedEnvironmentVariables := envVarsFromMap(d.Get("environment_variables").(tfMap))
-	environmentVariables := environmentVariablesFromSet(d.Get("environment_variable").([]interface{}))
-
-	if len(environmentVariables) > 0 && len(deprecatedEnvironmentVariables) > 0 {
-		return nil, errors.New("can't use both \"environment_variables\" and \"environment_variable\" on checkly_check_group resource")
-	}
-
-	if len(environmentVariables) > 0 {
-		return environmentVariables, nil
-	}
-
-	return deprecatedEnvironmentVariables, nil
-}
-
-func validateRuntimeSupport(check checkly.Check, client interface{}) error {
-	// If the check has a runtime ID set, then validate that the runtime supports multistep.
-	// Note that if the runtime ID is coming from the account defaults or group, then we don't validate it.
-	// Adding validation there as well would be a nice improvement, though.
-	if check.Type == "MULTI_STEP" && check.RuntimeID != nil {
-		ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-		defer cancel()
-		checkRuntime, err := client.(checkly.Client).GetRuntime(ctx, *check.RuntimeID)
-
-		if err != nil {
-			return fmt.Errorf("API error while fetching runtimes: %w", err)
-		}
-
-		if !checkRuntime.MultiStepSupport {
-			return fmt.Errorf("runtime %s does not support MULTI_STEP checks", *check.RuntimeID)
-		}
-	}
-	return nil
-}
diff --git a/checkly/resource_check_group.go b/checkly/resource_check_group.go
deleted file mode 100644
index e43df9c..0000000
--- a/checkly/resource_check_group.go
+++ /dev/null
@@ -1,621 +0,0 @@
-package checkly
-
-import (
-	"context"
-	"fmt"
-	"sort"
-	"strconv"
-	"strings"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	checkly "github.com/checkly/checkly-go-sdk"
-)
-
-func resourceCheckGroup() *schema.Resource {
-	return &schema.Resource{
-		Create: resourceCheckGroupCreate,
-		Read:   resourceCheckGroupRead,
-		Update: resourceCheckGroupUpdate,
-		Delete: resourceCheckGroupDelete,
-		Importer: &schema.ResourceImporter{
-			StateContext: schema.ImportStatePassthroughContext,
-		},
-		Description: "Check groups allow  you to group together a set of related checks, which can also share default settings for various attributes.",
-		Schema: map[string]*schema.Schema{
-			"name": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "The name of the check group.",
-			},
-			"concurrency": {
-				Type:        schema.TypeInt,
-				Required:    true,
-				Description: "Determines how many checks are run concurrently when triggering a check group from CI/CD or through the API.",
-			},
-			"activated": {
-				Type:        schema.TypeBool,
-				Required:    true,
-				Description: "Determines if the checks in the group are running or not.",
-			},
-			"muted": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Description: "Determines if any notifications will be sent out when a check in this group fails and/or recovers.",
-			},
-			"run_parallel": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Description: "Determines if the checks in the group should run in all selected locations in parallel or round-robin.",
-			},
-			"locations": {
-				Type:     schema.TypeSet,
-				Optional: true,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-				Description: "An array of one or more data center locations where to run the checks.",
-			},
-			"private_locations": {
-				Type:     schema.TypeSet,
-				Optional: true,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-				DefaultFunc: func() (interface{}, error) {
-					return []tfMap{}, nil
-				},
-				Description: "An array of one or more private locations slugs.",
-			},
-			"environment_variables": {
-				Type:        schema.TypeMap,
-				Optional:    true,
-				Deprecated:  "The property `environment_variables` is deprecated and will be removed in a future version. Consider using the new `environment_variable` list.",
-				Description: "Key/value pairs for setting environment variables during check execution. These are only relevant for browser checks. Use global environment variables whenever possible.",
-			},
-			"environment_variable": {
-				Type:        schema.TypeList,
-				Optional:    true,
-				Description: "Key/value pairs for setting environment variables during check execution, add locked = true to keep value hidden, add secret = true to create a secret variable. These are only relevant for browser checks. Use global environment variables whenever possible.",
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"key": {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						"value": {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						"locked": {
-							Type:     schema.TypeBool,
-							Optional: true,
-							Default:  false,
-						},
-						"secret": {
-							Type:     schema.TypeBool,
-							Optional: true,
-							Default:  false,
-						},
-					},
-				},
-			},
-			"double_check": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Description: "Setting this to `true` will trigger a retry when a check fails from the failing region and another, randomly selected region before marking the check as failed.",
-				Deprecated:  "The property `double_check` is deprecated and will be removed in a future version. To enable retries for failed check runs, use the `retry_strategy` property instead.",
-			},
-			"tags": {
-				Type:     schema.TypeSet,
-				Optional: true,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-				Description: "Tags for organizing and filtering checks.",
-			},
-			"setup_snippet_id": {
-				Type:        schema.TypeInt,
-				Optional:    true,
-				Description: "An ID reference to a snippet to use in the setup phase of an API check.",
-			},
-			"teardown_snippet_id": {
-				Type:        schema.TypeInt,
-				Optional:    true,
-				Description: "An ID reference to a snippet to use in the teardown phase of an API check.",
-			},
-			"local_setup_script": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Description: "A valid piece of Node.js code to run in the setup phase of an API check in this group.",
-			},
-			"local_teardown_script": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Description: "A valid piece of Node.js code to run in the teardown phase of an API check in this group.",
-			},
-			"runtime_id": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Default:     nil,
-				Description: "The id of the runtime to use for this group.",
-			},
-			"alert_channel_subscription": {
-				Type:     schema.TypeList,
-				Optional: true,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"channel_id": {
-							Type:     schema.TypeInt,
-							Required: true,
-						},
-						"activated": {
-							Type:     schema.TypeBool,
-							Required: true,
-						},
-					},
-				},
-			},
-			"alert_settings": {
-				Type:     schema.TypeList,
-				Optional: true,
-				Computed: true,
-				MaxItems: 1,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"escalation_type": {
-							Type:        schema.TypeString,
-							Optional:    true,
-							Default:     checkly.RunBased,
-							Description: "Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`.",
-						},
-						"run_based_escalation": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Computed: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"failed_run_threshold": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Description: "After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`).",
-									},
-								},
-							},
-						},
-						"time_based_escalation": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Computed: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"minutes_failing_threshold": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Description: "After how many minutes after a check starts failing an alert should be sent. Possible values are `5`, `10`, `15`, and `30`. (Default `5`).",
-									},
-								},
-							},
-						},
-						"reminders": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Computed: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"amount": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Description: "How many reminders to send out after the initial alert notification. Possible values are `0`, `1`, `2`, `3`, `4`, `5`, and `100000`",
-									},
-									"interval": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Default:     5,
-										Description: "Possible values are `5`, `10`, `15`, and `30`. (Default `5`).",
-									},
-								},
-							},
-						},
-						"parallel_run_failure_threshold": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Computed: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"enabled": {
-										Type:        schema.TypeBool,
-										Optional:    true,
-										Default:     false,
-										Description: "Applicable only for checks scheduled in parallel in multiple locations.",
-									},
-									"percentage": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Default:     10,
-										Description: "Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `100`, and `100`. (Default `10`).",
-									},
-								},
-							},
-						},
-						"ssl_certificates": {
-							Type:       schema.TypeSet,
-							Optional:   true,
-							Deprecated: "This property is deprecated and it's ignored by the Checkly Public API. It will be removed in a future version.",
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"enabled": {
-										Type:        schema.TypeBool,
-										Optional:    true,
-										Description: "Determines if alert notifications should be sent for expiring SSL certificates.",
-									},
-									"alert_threshold": {
-										Type:     schema.TypeInt,
-										Optional: true,
-										ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
-											v := val.(int)
-											valid := false
-											validFreqs := []int{3, 7, 14, 30}
-											for _, i := range validFreqs {
-												if v == i {
-													valid = true
-												}
-											}
-											if !valid {
-												errs = append(errs, fmt.Errorf("%q must be one of %v, got: %d", key, validFreqs, v))
-											}
-											return warns, errs
-										},
-										Description: "At what moment in time to start alerting on SSL certificates. Possible values `3`, `7`, `14`, `30`. (Default `3`).",
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-			"use_global_alert_settings": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Description: "When true, the account level alert settings will be used, not the alert setting defined on this check group.",
-			},
-			"api_check_defaults": {
-				Type:     schema.TypeSet,
-				MaxItems: 1,
-				Optional: true,
-				Computed: true,
-				DefaultFunc: func() (interface{}, error) {
-					return []tfMap{
-						tfMap{
-							"url":              "",
-							"headers":          []tfMap{},
-							"query_parameters": []tfMap{},
-							"basic_auth":       tfMap{},
-						}}, nil
-				},
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"url": {
-							Type:        schema.TypeString,
-							Required:    true,
-							Description: "The base url for this group which you can reference with the `GROUP_BASE_URL` variable in all group checks.",
-						},
-						"headers": {
-							Type:     schema.TypeMap,
-							Optional: true,
-							Computed: true,
-							DefaultFunc: func() (interface{}, error) {
-								return []tfMap{}, nil
-							},
-						},
-						"query_parameters": {
-							Type:     schema.TypeMap,
-							Optional: true,
-							Computed: true,
-							DefaultFunc: func() (interface{}, error) {
-								return []tfMap{}, nil
-							},
-						},
-						"assertion": {
-							Type:     schema.TypeSet,
-							Optional: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"source": {
-										Type:        schema.TypeString,
-										Required:    true,
-										Description: "The source of the asserted value. Possible values `STATUS_CODE`, `JSON_BODY`, `HEADERS`, `TEXT_BODY`, and `RESPONSE_TIME`.",
-									},
-									"property": {
-										Type:     schema.TypeString,
-										Optional: true,
-									},
-									"comparison": {
-										Type:        schema.TypeString,
-										Required:    true,
-										Description: "The type of comparison to be executed between expected and actual value of the assertion. Possible values `EQUALS`, `NOT_EQUALS`, `HAS_KEY`, `NOT_HAS_KEY`, `HAS_VALUE`, `NOT_HAS_VALUE`, `IS_EMPTY`, `NOT_EMPTY`, `GREATER_THAN`, `LESS_THAN`, `CONTAINS`, `NOT_CONTAINS`, `IS_NULL`, and `NOT_NULL`.",
-									},
-									"target": {
-										Type:     schema.TypeString,
-										Required: true,
-									},
-								},
-							},
-						},
-						"basic_auth": {
-							Type:     schema.TypeSet,
-							MaxItems: 1,
-							Optional: true,
-							Computed: true,
-							DefaultFunc: func() (interface{}, error) {
-								return []tfMap{}, nil
-							},
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"username": {
-										Type:     schema.TypeString,
-										Required: true,
-									},
-									"password": {
-										Type:     schema.TypeString,
-										Required: true,
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-			"retry_strategy": {
-				Type:     schema.TypeSet,
-				Optional: true,
-				Computed: true,
-				MaxItems: 1,
-				DefaultFunc: func() (interface{}, error) {
-					return []tfMap{}, nil
-				},
-				Description: "A strategy for retrying failed check runs.",
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"type": {
-							Type:        schema.TypeString,
-							Required:    true,
-							Description: "Determines which type of retry strategy to use. Possible values are `FIXED`, `LINEAR`, or `EXPONENTIAL`.",
-						},
-						"base_backoff_seconds": {
-							Type:        schema.TypeInt,
-							Optional:    true,
-							Default:     60,
-							Description: "The number of seconds to wait before the first retry attempt.",
-						},
-						"max_retries": {
-							Type:        schema.TypeInt,
-							Optional:    true,
-							Default:     2,
-							Description: "The maximum number of times to retry the check. Value must be between 1 and 10.",
-						},
-						"max_duration_seconds": {
-							Type:        schema.TypeInt,
-							Optional:    true,
-							Default:     600,
-							Description: "The total amount of time to continue retrying the check (maximum 600 seconds).",
-						},
-						"same_region": {
-							Type:        schema.TypeBool,
-							Optional:    true,
-							Default:     true,
-							Description: "Whether retries should be run in the same region as the initial check run.",
-						},
-					},
-				},
-			},
-		},
-	}
-}
-
-func resourceCheckGroupCreate(d *schema.ResourceData, client interface{}) error {
-	group, err := checkGroupFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	gotGroup, err := client.(checkly.Client).CreateGroup(ctx, group)
-	if err != nil {
-		return fmt.Errorf("API error11: %w", err)
-	}
-	d.SetId(fmt.Sprintf("%d", gotGroup.ID))
-	return resourceCheckGroupRead(d, client)
-}
-
-func resourceCheckGroupRead(d *schema.ResourceData, client interface{}) error {
-	ID, err := strconv.ParseInt(d.Id(), 10, 64)
-	if err != nil {
-		return fmt.Errorf("ID %s is not numeric: %w", d.Id(), err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	group, err := client.(checkly.Client).GetGroup(ctx, ID)
-	if err != nil {
-		if strings.Contains(err.Error(), "404") {
-			//if resource is deleted remotely, then mark it as
-			//successfully gone by unsetting it's ID
-			d.SetId("")
-			return nil
-		}
-		return fmt.Errorf("API error12: %w", err)
-	}
-	return resourceDataFromCheckGroup(group, d)
-}
-
-func resourceCheckGroupUpdate(d *schema.ResourceData, client interface{}) error {
-	group, err := checkGroupFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	_, err = client.(checkly.Client).UpdateGroup(ctx, group.ID, group)
-	if err != nil {
-		return fmt.Errorf("API error13: %w", err)
-	}
-	d.SetId(fmt.Sprintf("%d", group.ID))
-	return resourceCheckGroupRead(d, client)
-}
-
-func resourceCheckGroupDelete(d *schema.ResourceData, client interface{}) error {
-	ID, err := strconv.ParseInt(d.Id(), 10, 64)
-	if err != nil {
-		return fmt.Errorf("ID %s is not numeric: %w", d.Id(), err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	if err := client.(checkly.Client).DeleteGroup(ctx, ID); err != nil {
-		return fmt.Errorf("API error14: %w", err)
-	}
-	return nil
-}
-
-func resourceDataFromCheckGroup(g *checkly.Group, d *schema.ResourceData) error {
-	d.Set("name", g.Name)
-	d.Set("concurrency", g.Concurrency)
-	d.Set("activated", g.Activated)
-	d.Set("muted", g.Muted)
-	d.Set("run_parallel", g.RunParallel)
-	d.Set("locations", g.Locations)
-	d.Set("double_check", g.DoubleCheck)
-	d.Set("setup_snippet_id", g.SetupSnippetID)
-	d.Set("teardown_snippet_id", g.TearDownSnippetID)
-	d.Set("local_setup_script", g.LocalSetupScript)
-	d.Set("local_teardown_script", g.LocalTearDownScript)
-	d.Set("alert_channel_subscription", g.AlertChannelSubscriptions)
-	d.Set("private_locations", g.PrivateLocations)
-
-	sort.Strings(g.Tags)
-	d.Set("tags", g.Tags)
-
-	environmentVariables := environmentVariablesFromSet(d.Get("environment_variable").([]interface{}))
-	if len(environmentVariables) > 0 {
-		d.Set("environment_variable", g.EnvironmentVariables)
-	} else if err := d.Set("environment_variables", setFromEnvVars(g.EnvironmentVariables)); err != nil {
-		return fmt.Errorf("error setting environment variables for resource %s: %s", d.Id(), err)
-	}
-
-	if g.RuntimeID != nil {
-		d.Set("runtime_id", *g.RuntimeID)
-	}
-
-	if err := d.Set("alert_settings", setFromAlertSettings(g.AlertSettings)); err != nil {
-		return fmt.Errorf("error setting alert settings for resource %s: %s", d.Id(), err)
-	}
-	d.Set("use_global_alert_settings", g.UseGlobalAlertSettings)
-
-	if err := d.Set("api_check_defaults", setFromAPICheckDefaults(g.APICheckDefaults)); err != nil {
-		return fmt.Errorf("error setting request for resource %s: %s", d.Id(), err)
-	}
-
-	d.Set("retry_strategy", setFromRetryStrategy(g.RetryStrategy))
-
-	d.SetId(d.Id())
-	return nil
-}
-
-func checkGroupFromResourceData(d *schema.ResourceData) (checkly.Group, error) {
-	ID, err := strconv.ParseInt(d.Id(), 10, 64)
-	if err != nil {
-		if d.Id() != "" {
-			return checkly.Group{}, err
-		}
-		ID = 0
-	}
-
-	group := checkly.Group{
-		ID:                        ID,
-		Name:                      d.Get("name").(string),
-		Concurrency:               d.Get("concurrency").(int),
-		Activated:                 d.Get("activated").(bool),
-		Muted:                     d.Get("muted").(bool),
-		RunParallel:               d.Get("run_parallel").(bool),
-		Locations:                 stringsFromSet(d.Get("locations").(*schema.Set)),
-		DoubleCheck:               d.Get("double_check").(bool),
-		Tags:                      stringsFromSet(d.Get("tags").(*schema.Set)),
-		SetupSnippetID:            int64(d.Get("setup_snippet_id").(int)),
-		TearDownSnippetID:         int64(d.Get("teardown_snippet_id").(int)),
-		LocalSetupScript:          d.Get("local_setup_script").(string),
-		LocalTearDownScript:       d.Get("local_teardown_script").(string),
-		AlertSettings:             alertSettingsFromSet(d.Get("alert_settings").([]interface{})),
-		UseGlobalAlertSettings:    d.Get("use_global_alert_settings").(bool),
-		APICheckDefaults:          apiCheckDefaultsFromSet(d.Get("api_check_defaults").(*schema.Set)),
-		AlertChannelSubscriptions: alertChannelSubscriptionsFromSet(d.Get("alert_channel_subscription").([]interface{})),
-		RetryStrategy:             retryStrategyFromSet(d.Get("retry_strategy").(*schema.Set)),
-	}
-
-	runtimeId := d.Get("runtime_id").(string)
-	if runtimeId == "" {
-		group.RuntimeID = nil
-	} else {
-		group.RuntimeID = &runtimeId
-	}
-
-	environmentVariables, err := getResourceEnvironmentVariables(d)
-	if err != nil {
-		return checkly.Group{}, err
-	}
-	group.EnvironmentVariables = environmentVariables
-
-	privateLocations := stringsFromSet(d.Get("private_locations").(*schema.Set))
-	group.PrivateLocations = &privateLocations
-
-	return group, nil
-}
-
-func setFromAPICheckDefaults(a checkly.APICheckDefaults) []tfMap {
-	s := tfMap{}
-	s["url"] = a.BaseURL
-	s["headers"] = mapFromKeyValues(a.Headers)
-	s["query_parameters"] = mapFromKeyValues(a.QueryParameters)
-	s["assertion"] = setFromAssertions(a.Assertions)
-	s["basic_auth"] = checkGroupSetFromBasicAuth(a.BasicAuth)
-	return []tfMap{s}
-}
-
-func apiCheckDefaultsFromSet(s *schema.Set) checkly.APICheckDefaults {
-	if s.Len() == 0 {
-		return checkly.APICheckDefaults{}
-	}
-	res := s.List()[0].(tfMap)
-
-	return checkly.APICheckDefaults{
-		BaseURL:         res["url"].(string),
-		Headers:         keyValuesFromMap(res["headers"].(tfMap)),
-		QueryParameters: keyValuesFromMap(res["query_parameters"].(tfMap)),
-		Assertions:      assertionsFromSet(res["assertion"].(*schema.Set)),
-		BasicAuth:       checkGroupBasicAuthFromSet(res["basic_auth"].(*schema.Set)),
-	}
-}
-
-func checkGroupSetFromBasicAuth(b checkly.BasicAuth) []tfMap {
-	if b.Username == "" && b.Password == "" {
-		return []tfMap{}
-	}
-	return []tfMap{
-		{
-			"username": b.Username,
-			"password": b.Password,
-		},
-	}
-}
-
-func checkGroupBasicAuthFromSet(s *schema.Set) checkly.BasicAuth {
-	if s.Len() == 0 {
-		return checkly.BasicAuth{
-			Username: "",
-			Password: "",
-		}
-	}
-	res := s.List()[0].(tfMap)
-	return checkly.BasicAuth{
-		Username: res["username"].(string),
-		Password: res["password"].(string),
-	}
-}
diff --git a/checkly/resource_check_group_test.go b/checkly/resource_check_group_test.go
deleted file mode 100644
index eabc14a..0000000
--- a/checkly/resource_check_group_test.go
+++ /dev/null
@@ -1,427 +0,0 @@
-package checkly
-
-import (
-	"regexp"
-	"testing"
-
-	"github.com/google/go-cmp/cmp"
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-
-	"github.com/checkly/checkly-go-sdk"
-)
-
-func TestEncodeDecodeGroupResource(t *testing.T) {
-	res := resourceCheckGroup()
-	data := res.TestResourceData()
-	resourceDataFromCheckGroup(&wantGroup, data)
-	gotGroup, err := checkGroupFromResourceData(data)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if !cmp.Equal(wantGroup, gotGroup) {
-		t.Error(cmp.Diff(wantGroup, gotGroup))
-	}
-}
-
-var wantGroup = checkly.Group{
-	Name:             "test",
-	Activated:        true,
-	Muted:            false,
-	Tags:             []string{"auto"},
-	Locations:        []string{"eu-west-1"},
-	PrivateLocations: &[]string{},
-	Concurrency:      3,
-	APICheckDefaults: checkly.APICheckDefaults{
-		BaseURL: "example.com/api/test",
-		Headers: []checkly.KeyValue{
-			{
-				Key:   "X-Test",
-				Value: "foo",
-			},
-		},
-		QueryParameters: []checkly.KeyValue{
-			{
-				Key:   "query",
-				Value: "foo",
-			},
-		},
-		Assertions: []checkly.Assertion{
-			{
-				Source:     checkly.StatusCode,
-				Comparison: checkly.Equals,
-				Target:     "200",
-			},
-		},
-		BasicAuth: checkly.BasicAuth{
-			Username: "user",
-			Password: "pass",
-		},
-	},
-	EnvironmentVariables: []checkly.EnvironmentVariable{
-		{
-			Key:   "ENVTEST",
-			Value: "Hello world",
-		},
-	},
-	DoubleCheck:            true,
-	UseGlobalAlertSettings: false,
-	AlertSettings: checkly.AlertSettings{
-		EscalationType: checkly.RunBased,
-		RunBasedEscalation: checkly.RunBasedEscalation{
-			FailedRunThreshold: 1,
-		},
-		Reminders: checkly.Reminders{
-			Amount:   0,
-			Interval: 5,
-		},
-	},
-	LocalSetupScript:          "setup-test",
-	LocalTearDownScript:       "teardown-test",
-	AlertChannelSubscriptions: []checkly.AlertChannelSubscription{},
-}
-
-func TestAccCheckGroupEmptyConfig(t *testing.T) {
-	config := `resource "checkly_check_group" "test" {}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "name" is required`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "concurrency" is required`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "activated" is required`),
-		},
-	})
-}
-
-func TestAccCheckGroupInvalid(t *testing.T) {
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      testCheckGroup_invalid,
-			ExpectError: regexp.MustCompile(`Inappropriate value for attribute "locations"`),
-		},
-		{
-			Config:      testCheckGroup_invalid,
-			ExpectError: regexp.MustCompile(`Inappropriate value for attribute "muted"`),
-		},
-		{
-			Config:      testCheckGroup_invalid,
-			ExpectError: regexp.MustCompile(`Inappropriate value for attribute "activated"`),
-		},
-		{
-			Config:      testCheckGroup_invalid,
-			ExpectError: regexp.MustCompile(`The argument "concurrency" is required`),
-		},
-		{
-			Config:      testCheckGroup_invalid,
-			ExpectError: regexp.MustCompile(`Missing required argument`),
-		},
-	})
-}
-
-func TestAccCheckGroupBasic(t *testing.T) {
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: testCheckGroup_basic,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"name",
-					"test",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"activated",
-					"true",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"muted",
-					"false",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"concurrency",
-					"3",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"locations.#",
-					"2",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"locations.*",
-					"us-east-1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"locations.*",
-					"eu-central-1",
-				),
-			),
-		},
-	})
-}
-
-func TestAccCheckGroupWithApiDefaults(t *testing.T) {
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: testCheckGroup_withApiDefaults,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"name",
-					"test",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.*.url",
-					"http://api.example.com/",
-				),
-			),
-		},
-	})
-}
-
-func TestAccCheckGroupFull(t *testing.T) {
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: testCheckGroup_full,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"name",
-					"test",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"activated",
-					"true",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"muted",
-					"false",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"concurrency",
-					"3",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"double_check",
-					"true",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"use_global_alert_settings",
-					"false",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"locations.#",
-					"2",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"locations.*",
-					"us-east-1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"locations.*",
-					"eu-central-1",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check_group.test",
-					"environment_variables.FOO",
-					"BAR",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"alert_settings.*.escalation_type",
-					"RUN_BASED",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"alert_settings.*.reminders.#",
-					"1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"alert_settings.*.reminders.*.amount",
-					"2",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"alert_settings.*.reminders.*.interval",
-					"5",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"alert_settings.*.run_based_escalation.#",
-					"1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"alert_settings.*.run_based_escalation.*.failed_run_threshold",
-					"1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.#",
-					"1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.*.assertion.#",
-					"1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.*.assertion.*.comparison",
-					"EQUALS",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.*.assertion.*.property",
-					"",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.*.assertion.*.source",
-					"STATUS_CODE",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.*.assertion.*.target",
-					"200",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.*.basic_auth.#",
-					"1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.*.basic_auth.*.password",
-					"pass",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.*.basic_auth.*.username",
-					"user",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.*.headers.X-Test",
-					"foo",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.*.query_parameters.query",
-					"foo",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check_group.test",
-					"api_check_defaults.*.url",
-					"http://example.com/",
-				),
-			),
-		},
-	})
-}
-
-const testCheckGroup_invalid = `
-	resource "checkly_check_group" "test" {
-		name = "test"
-		activated = "invalid"
-		muted = "invalid"
-		locations = "invalid"
-	}
-`
-
-const testCheckGroup_basic = `
-	resource "checkly_check_group" "test" {
-		name        = "test"
-		activated   = true
-		muted       = false
-		concurrency = 3
-		locations   = [
-			"us-east-1",
-			"eu-central-1",
-		]
-	}
-`
-
-const testCheckGroup_withApiDefaults = `
-	resource "checkly_check_group" "test" {
-		name        = "test"
-		activated   = true
-		muted       = false
-		concurrency = 3
-		locations   = [
-			"eu-west-1",
-			"eu-west-2"
-		]
-		api_check_defaults {
-			url = "http://api.example.com/"
-		}
-	}
-`
-
-const testCheckGroup_full = `
-  resource "checkly_check_group" "test" {
-	name                      = "test"
-	activated                 = true
-	muted                     = false
-	concurrency               = 3
-	double_check              = true
-	use_global_alert_settings = false
-	locations = [ "us-east-1", "eu-central-1" ]
-	api_check_defaults {
-	  url = "http://example.com/"
-	  headers = {
-		X-Test = "foo"
-	  }
-	  query_parameters = {
-		query = "foo"
-	  }
-	  assertion {
-		source     = "STATUS_CODE"
-		property   = ""
-		comparison = "EQUALS"
-		target     = "200"
-	  }
-	  basic_auth {
-		username = "user"
-		password = "pass"
-	  }
-	}
-	environment_variables = {
-	  FOO = "BAR"
-	}
-	alert_settings {
-	  escalation_type = "RUN_BASED"
-	  run_based_escalation {
-		failed_run_threshold = 1
-	  }
-	  reminders {
-		amount   = 2
-		interval = 5
-	  }
-		parallel_run_failure_threshold {
-		enabled = false
-		percentage = 10
-		}
-	}
-	local_setup_script    = "setup-test"
-	local_teardown_script = "teardown-test"
-  }
-`
diff --git a/checkly/resource_check_test.go b/checkly/resource_check_test.go
deleted file mode 100644
index f388f22..0000000
--- a/checkly/resource_check_test.go
+++ /dev/null
@@ -1,698 +0,0 @@
-package checkly
-
-import (
-	"net/http"
-	"regexp"
-	"testing"
-
-	"github.com/google/go-cmp/cmp"
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-
-	"github.com/checkly/checkly-go-sdk"
-)
-
-func TestAccCheckRequiredFields(t *testing.T) {
-	config := `resource "checkly_check" "test" {}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "type" is required, but no definition was found.`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "name" is required, but no definition was found.`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "activated" is required, but no definition was found.`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "frequency" is required, but no definition was found.`),
-		},
-	})
-}
-
-func TestAccBrowserCheckInvalidInputs(t *testing.T) {
-	config := `resource "checkly_check" "test" {
-		name                      = 1
-		type                      = "BROWSER"
-		activated                 = "invalid"
-		should_fail               = "invalid"
-		double_check              = "invalid"
-		use_global_alert_settings = "invalid"
-		locations = "invalid"
-		script = 4
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`Inappropriate value for attribute "activated"`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "frequency" is required`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`Inappropriate value for attribute "should_fail"`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`Inappropriate value for attribute "use_global_alert_settings"`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`Inappropriate value for attribute "double_check"`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`Inappropriate value for attribute "locations"`),
-		},
-	})
-}
-
-func TestAccBrowserCheckMissingScript(t *testing.T) {
-	config := `resource "checkly_check" "test" {
-		type = "BROWSER"
-		activated = true
-		frequency = 10
-		name = "browser check"
-		locations = [ "us-west-1" ]
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`API error 1: unexpected response status 400`),
-		},
-	})
-}
-
-func TestAccBrowserCheckBasic(t *testing.T) {
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: browserCheck_basic,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"name",
-					"Browser Check",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"type",
-					"BROWSER",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"activated",
-					"true",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"script",
-					"console.log('test')",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"locations.#",
-					"2",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"locations.*",
-					"us-east-1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"locations.*",
-					"eu-central-1",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"tags.#",
-					"2",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"tags.*",
-					"browser",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"tags.*",
-					"e2e",
-				),
-				resource.TestCheckNoResourceAttr(
-					"checkly_check.test",
-					"request",
-				),
-			),
-		},
-	})
-}
-
-func TestAccApiCheckBasic(t *testing.T) {
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: apiCheck_basic,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"name",
-					"API Check 1",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"activated",
-					"true",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"locations.*",
-					"eu-central-1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"locations.*",
-					"us-east-1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.method",
-					"GET",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.url",
-					"https://api.checklyhq.com/public-stats",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.assertion.*.comparison",
-					"EQUALS",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.assertion.*.property",
-					"",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.assertion.*.source",
-					"STATUS_CODE",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.assertion.*.target",
-					"200",
-				),
-			),
-		},
-	})
-}
-
-func TestAccMultiStepCheckRuntimeValidation(t *testing.T) {
-	unsupportedRuntime := `resource "checkly_check" "test" {
-		name = "test"
-		type = "MULTI_STEP"
-		activated = true
-		frequency = 5
-		locations = ["eu-central-1"]
-		script = "console.log('test')"
-		runtime_id = "2023.02"
-	}`
-	noSpecifiedRuntime := `resource "checkly_check" "test" {
-		name = "test"
-		type = "MULTI_STEP"
-		activated = true
-		frequency = 5
-		locations = ["eu-central-1"]
-		script = "console.log('test')"
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      unsupportedRuntime,
-			ExpectError: regexp.MustCompile("Error: runtime 2023.02 does not support MULTI_STEP checks"),
-		},
-		{
-			Config: noSpecifiedRuntime,
-			Check: resource.TestCheckNoResourceAttr(
-				"checkly_check.test",
-				"runtime_id",
-			),
-		},
-	})
-}
-
-func TestAccMultiStepCheckBasic(t *testing.T) {
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: multiStepCheck_basic,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"name",
-					"MultiStep Check",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"type",
-					"MULTI_STEP",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"runtime_id",
-					"2023.09",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"activated",
-					"true",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"script",
-					"console.log('test')",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"locations.#",
-					"2",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"locations.*",
-					"us-east-1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"locations.*",
-					"eu-central-1",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"tags.#",
-					"2",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"tags.*",
-					"browser",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"tags.*",
-					"e2e",
-				),
-				resource.TestCheckNoResourceAttr(
-					"checkly_check.test",
-					"request",
-				),
-			),
-		},
-	})
-}
-
-func TestAccApiCheckFull(t *testing.T) {
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: apiCheck_full,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"degraded_response_time",
-					"15000",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"max_response_time",
-					"30000",
-				),
-				resource.TestCheckNoResourceAttr(
-					"checkly_check.test",
-					"environment_variables",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					`"locations.#"`,
-					"3",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					`"request.*.headers.X-CUSTOM-1"`,
-					"1",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.headers.X-CUSTOM-2",
-					"FOO",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.query_parameters.param1",
-					"123",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.query_parameters.param2",
-					"bar",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.basic_auth.*.username",
-					"user",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.basic_auth.*.password",
-					"pass",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.assertion.#",
-					"3",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.assertion.*.comparison",
-					"EQUALS",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.assertion.*.comparison",
-					"GREATER_THAN",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.assertion.*.target",
-					"200",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.assertion.*.target",
-					"no-cache",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.assertion.*.target",
-					"100",
-				),
-			),
-		},
-	})
-}
-
-func TestAccApiCheckMore(t *testing.T) {
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: apiCheck_post,
-			Check: resource.ComposeTestCheckFunc(
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.method",
-					"POST",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.body",
-					`{\"message\":\"hello checkly\",\"messageId\":1}`,
-				),
-				testCheckResourceAttrExpr(
-					"checkly_check.test",
-					"request.*.body_type",
-					"JSON",
-				),
-			),
-		},
-		{
-			Config: apiCheck_withEmptyBasicAuth,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_check.test",
-					"name",
-					"api check with empty basic_auth",
-				),
-			),
-		},
-	})
-}
-
-var wantCheck = checkly.Check{
-	Name:                 "My test check",
-	Type:                 checkly.TypeAPI,
-	Frequency:            1,
-	Activated:            true,
-	Muted:                false,
-	ShouldFail:           false,
-	Locations:            []string{"eu-west-1"},
-	PrivateLocations:     &[]string{},
-	Script:               "foo",
-	DegradedResponseTime: 15000,
-	MaxResponseTime:      30000,
-	EnvironmentVariables: []checkly.EnvironmentVariable{
-		{
-			Key:   "ENVTEST",
-			Value: "Hello world",
-		},
-	},
-	DoubleCheck: false,
-	Tags: []string{
-		"foo",
-		"bar",
-	},
-	SSLCheck:            false,
-	LocalSetupScript:    "bogus",
-	LocalTearDownScript: "bogus",
-	AlertSettings: checkly.AlertSettings{
-		EscalationType: checkly.RunBased,
-		RunBasedEscalation: checkly.RunBasedEscalation{
-			FailedRunThreshold: 1,
-		},
-		Reminders: checkly.Reminders{
-			Interval: 5,
-		},
-	},
-	UseGlobalAlertSettings: false,
-	Request: checkly.Request{
-		Method: http.MethodGet,
-		URL:    "http://example.com",
-		Headers: []checkly.KeyValue{
-			{
-				Key:   "X-Test",
-				Value: "foo",
-			},
-		},
-		QueryParameters: []checkly.KeyValue{
-			{
-				Key:   "query",
-				Value: "foo",
-			},
-		},
-		Assertions: []checkly.Assertion{
-			{
-				Source:     checkly.StatusCode,
-				Comparison: checkly.Equals,
-				Target:     "200",
-			},
-		},
-		Body:     "",
-		BodyType: "NONE",
-		BasicAuth: &checkly.BasicAuth{
-			Username: "example",
-			Password: "pass",
-		},
-	},
-}
-
-func TestEncodeDecodeResource(t *testing.T) {
-	res := resourceCheck()
-	data := res.TestResourceData()
-	wantCheck.AlertChannelSubscriptions = []checkly.AlertChannelSubscription{}
-	resourceDataFromCheck(&wantCheck, data)
-	got, err := checkFromResourceData(data)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if !cmp.Equal(wantCheck, got) {
-		t.Error(cmp.Diff(wantCheck, got))
-	}
-}
-
-const browserCheck_basic = `
-	resource "checkly_check" "test" {
-		name                      = "Browser Check"
-		type                      = "BROWSER"
-		activated                 = true
-		should_fail               = false
-		frequency                 = 720
-		double_check              = true
-		use_global_alert_settings = true
-		locations                 = [ "us-east-1", "eu-central-1" ]
-		tags                      = [ "browser", "e2e" ]
-		script                    = "console.log('test')"
-	}
-`
-const multiStepCheck_basic = `
-	resource "checkly_check" "test" {
-		name                      = "MultiStep Check"
-		type                      = "MULTI_STEP"
-		activated                 = true
-		should_fail               = false
-		frequency                 = 720
-		double_check              = true
-		use_global_alert_settings = true
-		locations                 = [ "us-east-1", "eu-central-1" ]
-		tags                      = [ "api", "multi-step" ]
-		runtime_id				  = "2023.09"
-		script                    = "console.log('test')"
-	}
-`
-
-const apiCheck_basic = `
-	resource "checkly_check" "test" {
-	  name                      = "API Check 1"
-	  type                      = "API"
-	  frequency                 = 60
-	  activated                 = true
-	  muted                     = true
-	  double_check              = true
-	  max_response_time         = 18000
-	  locations                 = [ "us-east-1", "eu-central-1" ]
-	  use_global_alert_settings = true
-	  request {
-		method     = "GET"
-		url        = "https://api.checklyhq.com/public-stats"
-		assertion {
-		  comparison = "EQUALS"
-		  property   = ""
-		  source     = "STATUS_CODE"
-		  target     = "200"
-		}
-	  }
-	}
-`
-
-const apiCheck_full = `
-  resource "checkly_check" "test" {
-	name                   = "apiCheck_full"
-	type                   = "API"
-	frequency              = 120
-	activated              = true
-	muted                  = true
-	double_check           = true
-	degraded_response_time = 15000
-	max_response_time      = 30000
-	environment_variables  = null
-	locations = [
-	  "eu-central-1",
-	  "us-east-1",
-	  "ap-northeast-1"
-	]
-	request {
-	  method           = "GET"
-	  url              = "https://api.checklyhq.com/public-stats"
-	  follow_redirects = true
-	  headers = {
-		X-CUSTOM-1 = 1
-		X-CUSTOM-2 = "foo"
-	  }
-	  query_parameters = {
-		param1 = 123
-		param2 = "bar"
-	  }
-	  basic_auth {
-		username = "user"
-		password = "pass"
-	  }
-	  assertion {
-		comparison = "EQUALS"
-		property   = ""
-		source     = "STATUS_CODE"
-		target     = "200"
-	  }
-	  assertion {
-		comparison = "EQUALS"
-		property   = "cache-control"
-		source     = "HEADERS"
-		target     = "no-cache"
-	  }
-	  assertion {
-		comparison = "GREATER_THAN"
-		property   = "$.apiCheckResults"
-		source     = "JSON_BODY"
-		target     = "100"
-	  }
-	}
-
-	alert_settings {
-	  escalation_type = "RUN_BASED"
-	  reminders {
-		amount   = 0
-		interval = 5
-	  }
-	  run_based_escalation {
-		failed_run_threshold = 1
-	  }
-		parallel_run_failure_threshold {
-		enabled = false
-		percentage = 10
-		}
-	}
-  }
-`
-
-const apiCheck_post = `
-  resource "checkly_check" "test" {
-	name         = "apiCheck_post"
-	type         = "API"
-	activated    = true
-	double_check = true
-	frequency    = 720
-	locations = [ "eu-central-1", "us-east-2" ]
-	max_response_time     = 18000
-	muted                 = true
-	environment_variables = null
-	request {
-	  method           = "POST"
-	  url              = "https://jsonplaceholder.typicode.com/posts"
-	  headers = {
-		Content-type = "application/json; charset=UTF-8"
-	  }
-	  body      = "{\"message\":\"hello checkly\",\"messageId\":1}"
-	  body_type = "JSON"
-	}
-	use_global_alert_settings = true
-  }
-`
-
-const apiCheck_withEmptyBasicAuth = `
-  resource "checkly_check" "test" {
-	name                   = "api check with empty basic_auth"
-	type                   = "API"
-	activated              = true
-	should_fail            = false
-	frequency              = 1
-	degraded_response_time = 3000
-	max_response_time      = 6000
-	tags = [
-	  "testing",
-	  "bug"
-	]
-	locations = [ "eu-central-1" ]
-	request {
-	  follow_redirects = false
-	  url              = "https://api.checklyhq.com/public-stats"
-	  basic_auth {
-		username = ""
-		password = ""
-	  }
-	  assertion {
-		source     = "STATUS_CODE"
-		property   = ""
-		comparison = "EQUALS"
-		target     = "200"
-	  }
-	}
-  }
-`
diff --git a/checkly/resource_dashboard.go b/checkly/resource_dashboard.go
deleted file mode 100644
index 68679c2..0000000
--- a/checkly/resource_dashboard.go
+++ /dev/null
@@ -1,275 +0,0 @@
-package checkly
-
-import (
-	"context"
-	"fmt"
-	"strings"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	checkly "github.com/checkly/checkly-go-sdk"
-)
-
-func validateOptions(options []int) func(val interface{}, key string) (warns []string, errs []error) {
-	return func(val interface{}, key string) (warns []string, errs []error) {
-		v := val.(int)
-		valid := false
-		for _, i := range options {
-			if v == i {
-				valid = true
-			}
-		}
-		if !valid {
-			errs = append(errs, fmt.Errorf("%q must be one of %v, got: %d", key, options, v))
-		}
-		return warns, errs
-	}
-}
-
-func resourceDashboard() *schema.Resource {
-	return &schema.Resource{
-		Create: resourceDashboardCreate,
-		Read:   resourceDashboardRead,
-		Update: resourceDashboardUpdate,
-		Delete: resourceDashboardDelete,
-		Importer: &schema.ResourceImporter{
-			StateContext: schema.ImportStatePassthroughContext,
-		},
-		Schema: map[string]*schema.Schema{
-			"custom_url": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "A subdomain name under 'checklyhq.com'. Needs to be unique across all users.",
-			},
-			"custom_domain": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Default:     nil,
-				Description: "A custom user domain, e.g. 'status.example.com'. See the docs on updating your DNS and SSL usage.",
-			},
-			"logo": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Default:     "",
-				Description: "A URL pointing to an image file to use for the dashboard logo.",
-			},
-			"favicon": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Default:     "",
-				Description: "A URL pointing to an image file to use as browser favicon.",
-			},
-			"link": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Default:     "",
-				Description: "A link to for the dashboard logo.",
-			},
-			"description": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Default:     "",
-				Description: "HTML <meta> description for the dashboard.",
-			},
-			"header": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Default:     "",
-				Description: "A piece of text displayed at the top of your dashboard.",
-			},
-			"width": {
-				Type:     schema.TypeString,
-				Optional: true,
-				Default:  "FULL",
-				ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) {
-					full := "FULL"
-					px960 := "960PX"
-					v := value.(string)
-					if v != full && v != px960 {
-						errs = append(errs, fmt.Errorf("%q must  %s and  %s, got: %s", key, full, px960, v))
-					}
-					return warns, errs
-				},
-				Description: "Determines whether to use the full screen or focus in the center. Possible values `FULL` and `960PX`.",
-			},
-			"refresh_rate": {
-				Type:         schema.TypeInt,
-				Optional:     true,
-				Default:      60,
-				ValidateFunc: validateOptions([]int{60, 300, 600}),
-				Description:  "How often to refresh the dashboard in seconds. Possible values `60`, '300' and `600`.",
-			},
-			"paginate": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Default:     true,
-				Description: "Determines if pagination is on or off.",
-			},
-			"checks_per_page": {
-				Type:        schema.TypeInt,
-				Optional:    true,
-				Default:     15,
-				Description: "Determines how many checks to show per page.",
-			},
-			"pagination_rate": {
-				Type:         schema.TypeInt,
-				Optional:     true,
-				Default:      60,
-				ValidateFunc: validateOptions([]int{30, 60, 300}),
-				Description:  "How often to trigger pagination in seconds. Possible values `30`, `60` and `300`.",
-			},
-			"tags": {
-				Type:     schema.TypeSet,
-				Optional: true,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-				Description: "A list of one or more tags that filter which checks to display on the dashboard.",
-			},
-			"hide_tags": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Default:     false,
-				Description: "Show or hide the tags on the dashboard.",
-			},
-			"use_tags_and_operator": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Default:     false,
-				Description: "Set when to use AND operator for fetching dashboard tags.",
-			},
-			"is_private": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Default:     false,
-				Description: "Set your dashboard as private and generate key.",
-			},
-			// moving to TypeString here https://github.com/hashicorp/terraform-plugin-sdk/issues/792
-			"key": {
-				Type:        schema.TypeString,
-				Computed:    true,
-				Sensitive:   true,
-				Description: "The access key when the dashboard is private.",
-			},
-		},
-	}
-}
-
-func dashboardFromResourceData(d *schema.ResourceData) (checkly.Dashboard, error) {
-	a := checkly.Dashboard{
-		CustomDomain:       d.Get("custom_domain").(string),
-		CustomUrl:          d.Get("custom_url").(string),
-		Logo:               d.Get("logo").(string),
-		Favicon:            d.Get("favicon").(string),
-		Link:               d.Get("link").(string),
-		Description:        d.Get("description").(string),
-		Header:             d.Get("header").(string),
-		RefreshRate:        d.Get("refresh_rate").(int),
-		Paginate:           d.Get("paginate").(bool),
-		ChecksPerPage:      d.Get("checks_per_page").(int),
-		PaginationRate:     d.Get("pagination_rate").(int),
-		HideTags:           d.Get("hide_tags").(bool),
-		Width:              d.Get("width").(string),
-		UseTagsAndOperator: d.Get("use_tags_and_operator").(bool),
-		IsPrivate:          d.Get("is_private").(bool),
-		Tags:               stringsFromSet(d.Get("tags").(*schema.Set)),
-	}
-
-	fmt.Printf("%v", a)
-
-	return a, nil
-}
-
-func resourceDataFromDashboard(s *checkly.Dashboard, d *schema.ResourceData) error {
-	d.Set("custom_domain", s.CustomDomain)
-	d.Set("custom_url", s.CustomUrl)
-	d.Set("logo", s.Logo)
-	d.Set("favicon", s.Favicon)
-	d.Set("link", s.Link)
-	d.Set("description", s.Description)
-	d.Set("header", s.Header)
-	d.Set("refresh_rate", s.RefreshRate)
-	d.Set("paginate", s.Paginate)
-	d.Set("checks_per_page", s.ChecksPerPage)
-	d.Set("pagination_rate", s.PaginationRate)
-	d.Set("hide_tags", s.HideTags)
-	d.Set("tags", s.Tags)
-	d.Set("width", s.Width)
-	d.Set("use_tags_and_operator", s.UseTagsAndOperator)
-	d.Set("is_private", s.IsPrivate)
-
-	// if the dashboard is private, we either do nothing
-	// or set the key to a new value if there is any
-	if s.IsPrivate {
-		if len(s.Keys) > 0 {
-			d.Set("key", s.Keys[0].RawKey)
-		}
-	} else {
-		// if the dashboard is public, remove the key
-		d.Set("key", nil)
-	}
-
-	return nil
-}
-
-func resourceDashboardCreate(d *schema.ResourceData, client interface{}) error {
-	dashboard, err := dashboardFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("resourceDashboardCreate: translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	result, err := client.(checkly.Client).CreateDashboard(ctx, dashboard)
-
-	if err != nil {
-		return fmt.Errorf("CreateDashboard: API error: %w", err)
-	}
-
-	d.SetId(result.DashboardID)
-
-	// we cannot take the detour through resourceDashboardRead since
-	// we would not get the keys back from an additional GET call
-	return resourceDataFromDashboard(result, d)
-}
-
-func resourceDashboardUpdate(d *schema.ResourceData, client interface{}) error {
-	dashboard, err := dashboardFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("resourceDashboardUpdate: translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	result, err := client.(checkly.Client).UpdateDashboard(ctx, d.Id(), dashboard)
-	if err != nil {
-		return fmt.Errorf("resourceDashboardUpdate: API error: %w", err)
-	}
-	d.SetId(result.DashboardID)
-
-	// we cannot take the detour through resourceDashboardRead since
-	// we would not get the keys back from an additional GET call
-	return resourceDataFromDashboard(result, d)
-}
-
-func resourceDashboardDelete(d *schema.ResourceData, client interface{}) error {
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	err := client.(checkly.Client).DeleteDashboard(ctx, d.Id())
-	if err != nil {
-		return fmt.Errorf("resourceDashboardDelete: API error: %w", err)
-	}
-	return nil
-}
-
-func resourceDashboardRead(d *schema.ResourceData, client interface{}) error {
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	dashboard, err := client.(checkly.Client).GetDashboard(ctx, d.Id())
-	defer cancel()
-	if err != nil {
-		if strings.Contains(err.Error(), "404") {
-			d.SetId("")
-			return nil
-		}
-		return fmt.Errorf("resourceDashboardRead: API error: %w", err)
-	}
-	return resourceDataFromDashboard(dashboard, d)
-}
diff --git a/checkly/resource_environment_variable.go b/checkly/resource_environment_variable.go
deleted file mode 100644
index fb55897..0000000
--- a/checkly/resource_environment_variable.go
+++ /dev/null
@@ -1,118 +0,0 @@
-package checkly
-
-import (
-	"context"
-	"fmt"
-	"strings"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	checkly "github.com/checkly/checkly-go-sdk"
-)
-
-func resourceEnvironmentVariable() *schema.Resource {
-	return &schema.Resource{
-		Create: resourceEnvironmentVariableCreate,
-		Read:   resourceEnvironmentVariableRead,
-		Update: resourceEnvironmentVariableUpdate,
-		Delete: resourceEnvironmentVariableDelete,
-		Importer: &schema.ResourceImporter{
-			State: schema.ImportStatePassthrough,
-		},
-		Schema: map[string]*schema.Schema{
-			"key": {
-				Type:     schema.TypeString,
-				Required: true,
-			},
-			"value": {
-				Type:     schema.TypeString,
-				Required: true,
-			},
-			"locked": {
-				Type:     schema.TypeBool,
-				Optional: true,
-				Default:  false,
-			},
-			"secret": {
-				Type:     schema.TypeBool,
-				Optional: true,
-				Default:  false,
-			},
-		},
-	}
-}
-
-func resourceEnvironmentVariableCreate(d *schema.ResourceData, client interface{}) error {
-	envVar, err := environmentVariableFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("resourceEnvironmentVariableCreate: translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	_, err = client.(checkly.Client).CreateEnvironmentVariable(ctx, envVar)
-	if err != nil {
-		return fmt.Errorf("CreateEnvironmentVariable: API error: %w", err)
-	}
-	d.SetId(envVar.Key)
-	return resourceEnvironmentVariableRead(d, client)
-}
-
-func environmentVariableFromResourceData(d *schema.ResourceData) (checkly.EnvironmentVariable, error) {
-	return checkly.EnvironmentVariable{
-		Key:    d.Get("key").(string),
-		Value:  d.Get("value").(string),
-		Locked: d.Get("locked").(bool),
-		Secret: d.Get("secret").(bool),
-	}, nil
-}
-
-func resourceDataFromEnvironmentVariable(s *checkly.EnvironmentVariable, d *schema.ResourceData) error {
-	d.Set("key", s.Key)
-	if !s.Secret {
-		d.Set("value", s.Value)
-	}
-	d.Set("locked", s.Locked)
-	d.Set("secret", s.Secret)
-	return nil
-}
-
-func resourceEnvironmentVariableRead(d *schema.ResourceData, client interface{}) error {
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	envVar, err := client.(checkly.Client).GetEnvironmentVariable(ctx, d.Id())
-	if err != nil {
-		if strings.Contains(err.Error(), "404") {
-			//if resource is deleted remotely, then mark it as
-			//successfully gone by unsetting it's ID
-			d.SetId("")
-			return nil
-		}
-		return fmt.Errorf("resourceEnvironmentVariableRead: API error: %w", err)
-	}
-	return resourceDataFromEnvironmentVariable(envVar, d)
-}
-
-func resourceEnvironmentVariableUpdate(d *schema.ResourceData, client interface{}) error {
-	envVar, err := environmentVariableFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("resourceEnvironmentVariableUpdate: translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	_, err = client.(checkly.Client).UpdateEnvironmentVariable(ctx, d.Id(), envVar)
-	if err != nil {
-		return fmt.Errorf("resourceEnvironmentVariableUpdate: API error: %w", err)
-	}
-
-	return resourceEnvironmentVariableRead(d, client)
-}
-
-func resourceEnvironmentVariableDelete(d *schema.ResourceData, client interface{}) error {
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	err := client.(checkly.Client).DeleteEnvironmentVariable(ctx, d.Id())
-	if err != nil {
-		return fmt.Errorf("resourceEnvironmentVariableDelete: API error: %w", err)
-	}
-	return nil
-}
diff --git a/checkly/resource_environment_variable_test.go b/checkly/resource_environment_variable_test.go
deleted file mode 100644
index 09fbccf..0000000
--- a/checkly/resource_environment_variable_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package checkly
-
-import (
-	"regexp"
-	"testing"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-)
-
-func TestAccEnvVarCheckRequiredFields(t *testing.T) {
-	config := `resource "checkly_environment_variable" "test" {}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "key" is required`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "value" is required`),
-		},
-	})
-}
-
-func TestAccEnvVarSuccess(t *testing.T) {
-	config := `resource "checkly_environment_variable" "test" {
-		key     = "API_URL"
-		value   = "https://api.checklyhq.com"
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: config,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_environment_variable.test",
-					"key",
-					"API_URL",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_environment_variable.test",
-					"value",
-					"https://api.checklyhq.com",
-				),
-			),
-		},
-	})
-}
-
-func TestAccSecretEnvVarSuccess(t *testing.T) {
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: `resource "checkly_environment_variable" "test" {
-				key     = "SECRET"
-				value   = "https://api.checklyhq.com"
-				secret  = true
-			}`,
-		},
-	})
-}
diff --git a/checkly/resource_heartbeat.go b/checkly/resource_heartbeat.go
deleted file mode 100644
index 3b2fa0b..0000000
--- a/checkly/resource_heartbeat.go
+++ /dev/null
@@ -1,428 +0,0 @@
-package checkly
-
-import (
-	"context"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"sort"
-	"strings"
-	"time"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	"github.com/checkly/checkly-go-sdk"
-)
-
-func resourceHeartbeat() *schema.Resource {
-	return &schema.Resource{
-		Create: resourceHeartbeatCreate,
-		Read:   resourceHeartbeatRead,
-		Update: resourceHeartbeatUpdate,
-		Delete: resourceHeartbeatDelete,
-		Importer: &schema.ResourceImporter{
-			StateContext: schema.ImportStatePassthroughContext,
-		},
-		Description: "Heartbeats allows you to monitor your cron jobs and set up alerting, so you get a notification when things break or slow down.",
-		Schema: map[string]*schema.Schema{
-			"name": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "The name of the check.",
-			},
-			"activated": {
-				Type:        schema.TypeBool,
-				Required:    true,
-				Description: "Determines if the check is running or not. Possible values `true`, and `false`.",
-			},
-			"muted": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Description: "Determines if any notifications will be sent out when a check fails/degrades/recovers.",
-			},
-			"tags": {
-				Type:     schema.TypeSet,
-				Optional: true,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-				Description: "A list of tags for organizing and filtering checks.",
-			},
-			"alert_settings": {
-				Type:     schema.TypeList,
-				Optional: true,
-				Computed: true,
-				MaxItems: 1,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"escalation_type": {
-							Type:        schema.TypeString,
-							Optional:    true,
-							Description: "Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`.",
-						},
-						"run_based_escalation": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Computed: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"failed_run_threshold": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Description: "After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`).",
-									},
-								},
-							},
-						},
-						"time_based_escalation": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Computed: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"minutes_failing_threshold": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Description: "After how many minutes after a check starts failing an alert should be sent. Possible values are `5`, `10`, `15`, and `30`. (Default `5`).",
-									},
-								},
-							},
-						},
-						"reminders": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Computed: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"amount": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Description: "How many reminders to send out after the initial alert notification. Possible values are `0`, `1`, `2`, `3`, `4`, `5`, and `100000`",
-									},
-									"interval": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Default:     5,
-										Description: "Possible values are `5`, `10`, `15`, and `30`. (Default `5`).",
-									},
-								},
-							},
-						},
-						"parallel_run_failure_threshold": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Computed: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"enabled": {
-										Type:        schema.TypeBool,
-										Optional:    true,
-										Default:     false,
-										Description: "Applicable only for checks scheduled in parallel in multiple locations.",
-									},
-									"percentage": {
-										Type:        schema.TypeInt,
-										Optional:    true,
-										Default:     10,
-										Description: "Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `100`, and `100`. (Default `10`).",
-									},
-								},
-							},
-						},
-						"ssl_certificates": {
-							Type:       schema.TypeSet,
-							Optional:   true,
-							Deprecated: "This property is deprecated and it's ignored by the Checkly Public API. It will be removed in a future version.",
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"enabled": {
-										Type:        schema.TypeBool,
-										Optional:    true,
-										Description: "Determines if alert notifications should be sent for expiring SSL certificates. Possible values `true`, and `false`. (Default `false`).",
-									},
-									"alert_threshold": {
-										Type:     schema.TypeInt,
-										Optional: true,
-										ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
-											v := val.(int)
-											valid := false
-											validFreqs := []int{3, 7, 14, 30}
-											for _, i := range validFreqs {
-												if v == i {
-													valid = true
-												}
-											}
-											if !valid {
-												errs = append(errs, fmt.Errorf("%q must be one of %v, got: %d", key, validFreqs, v))
-											}
-											return warns, errs
-										},
-										Description: "How long before SSL certificate expiry to send alerts. Possible values `3`, `7`, `14`, `30`. (Default `3`).",
-									},
-								},
-								Description: "At what interval the reminders should be sent.",
-							},
-						},
-					},
-				},
-			},
-			"use_global_alert_settings": {
-				Type:        schema.TypeBool,
-				Optional:    true,
-				Description: "When true, the account level alert settings will be used, not the alert setting defined on this check.",
-			},
-			"heartbeat": {
-				Type:     schema.TypeSet,
-				Required: true,
-				MaxItems: 1,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"period": {
-							Type:        schema.TypeInt,
-							Required:    true,
-							Description: "How often you expect a ping to the ping URL.",
-						},
-						"period_unit": {
-							Type:     schema.TypeString,
-							Required: true,
-							ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) {
-								v := value.(string)
-								isValid := false
-								options := []string{"seconds", "minutes", "hours", "days"}
-								for _, option := range options {
-									if v == option {
-										isValid = true
-									}
-								}
-								if !isValid {
-									errs = append(errs, fmt.Errorf("%q must be one of %v, got %s", key, options, v))
-								}
-								return warns, errs
-							},
-							Description: "Possible values `seconds`, `minutes`, `hours` and `days`.",
-						},
-						"grace": {
-							Type:        schema.TypeInt,
-							Required:    true,
-							Description: "How long Checkly should wait before triggering any alerts when a ping does not arrive within the set period.",
-						},
-						"grace_unit": {
-							Type:     schema.TypeString,
-							Required: true,
-							ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) {
-								v := value.(string)
-								isValid := false
-								options := []string{"seconds", "minutes", "hours", "days"}
-								for _, option := range options {
-									if v == option {
-										isValid = true
-									}
-								}
-								if !isValid {
-									errs = append(errs, fmt.Errorf("%q must be one of %v, got %s", key, options, v))
-								}
-								return warns, errs
-							},
-							Description: "Possible values `seconds`, `minutes`, `hours` and `days`.",
-						},
-						"ping_token": {
-							Type:        schema.TypeString,
-							Optional:    true,
-							Computed:    true,
-							Description: "Custom token to generate your ping URL. Checkly will expect a ping to `https://ping.checklyhq.com/[PING_TOKEN]`.",
-						},
-					},
-				},
-			},
-			"alert_channel_subscription": {
-				Type:     schema.TypeList,
-				Optional: true,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"channel_id": {
-							Type:     schema.TypeInt,
-							Required: true,
-						},
-						"activated": {
-							Type:     schema.TypeBool,
-							Required: true,
-						},
-					},
-				},
-			},
-		},
-	}
-}
-
-func resourceHeartbeatCreate(d *schema.ResourceData, client interface{}) error {
-	check, err := heartbeatCheckFromResourceData(d)
-
-	if err != nil {
-		return fmt.Errorf("translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	newCheck, err := client.(checkly.Client).CreateHeartbeat(ctx, check)
-
-	if err != nil {
-		checkJSON, _ := json.Marshal(check)
-		return fmt.Errorf("API error 1: %w, Check: %s", err, string(checkJSON))
-	}
-	d.SetId(newCheck.ID)
-	return resourceHeartbeatRead(d, client)
-}
-
-func resourceHeartbeatRead(d *schema.ResourceData, client interface{}) error {
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	check, err := client.(checkly.Client).GetHeartbeatCheck(ctx, d.Id())
-	if err != nil {
-		if strings.Contains(err.Error(), "404") {
-			//if resource is deleted remotely, then mark it as
-			//successfully gone by unsetting it's ID
-			d.SetId("")
-			return nil
-		}
-		return fmt.Errorf("API error 2: %w", err)
-	}
-	return resourceDataFromHeartbeat(check, d)
-}
-
-func resourceHeartbeatUpdate(d *schema.ResourceData, client interface{}) error {
-	check, err := heartbeatCheckFromResourceData(d)
-
-	if err != nil {
-		return fmt.Errorf("translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	_, err = client.(checkly.Client).UpdateHeartbeat(ctx, check.ID, check)
-	if err != nil {
-		checkJSON, _ := json.Marshal(check)
-		return fmt.Errorf("API error 3: Couldn't update check, Error: %w, \nCheck: %s", err, checkJSON)
-	}
-	d.SetId(check.ID)
-	return resourceHeartbeatRead(d, client)
-}
-
-func resourceHeartbeatDelete(d *schema.ResourceData, client interface{}) error {
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	if err := client.(checkly.Client).Delete(ctx, d.Id()); err != nil {
-		return fmt.Errorf("API error 4: Couldn't delete Check %s, Error: %w", d.Id(), err)
-	}
-	return nil
-}
-
-func heartbeatCheckFromResourceData(d *schema.ResourceData) (checkly.HeartbeatCheck, error) {
-	check := checkly.HeartbeatCheck{
-		ID:                        d.Id(),
-		Name:                      d.Get("name").(string),
-		Activated:                 d.Get("activated").(bool),
-		Muted:                     d.Get("muted").(bool),
-		Tags:                      stringsFromSet(d.Get("tags").(*schema.Set)),
-		AlertSettings:             alertSettingsFromSet(d.Get("alert_settings").([]interface{})),
-		UseGlobalAlertSettings:    d.Get("use_global_alert_settings").(bool),
-		AlertChannelSubscriptions: alertChannelSubscriptionsFromSet(d.Get("alert_channel_subscription").([]interface{})),
-	}
-
-	// this will prevent subsequent apply from causing a tf config change in browser checks
-	check.Heartbeat = heartbeatFromSet(d.Get("heartbeat").(*schema.Set))
-
-	// Period / Grace validation
-	periodDaysInHours := 0
-	periodHours := 0
-	periodMinutes := 0
-	periodSseconds := 0
-	graceDaysInHours := 0
-	graceHours := 0
-	graceMinutes := 0
-	graceSseconds := 0
-
-	if check.Heartbeat.PeriodUnit == "days" {
-		periodDaysInHours = check.Heartbeat.Period * 24
-	} else if check.Heartbeat.PeriodUnit == "hours" {
-		periodHours = check.Heartbeat.Period
-	} else if check.Heartbeat.PeriodUnit == "minutes" {
-		periodMinutes = check.Heartbeat.Period
-	} else {
-		periodSseconds = check.Heartbeat.Period
-	}
-
-	if check.Heartbeat.GraceUnit == "days" {
-		graceDaysInHours = check.Heartbeat.Grace * 24
-	} else if check.Heartbeat.GraceUnit == "hours" {
-		graceHours = check.Heartbeat.Grace
-	} else if check.Heartbeat.GraceUnit == "minutes" {
-		graceMinutes = check.Heartbeat.Grace
-	} else {
-		graceSseconds = check.Heartbeat.Grace
-	}
-
-	now := time.Now().Local()
-	addedTimePeriod := time.Now().Local().Add(
-		time.Hour*time.Duration(periodDaysInHours+periodHours) +
-			time.Minute*time.Duration(periodMinutes) +
-			time.Second*time.Duration(periodSseconds))
-	addedTimeGrace := time.Now().Local().Add(
-		time.Hour*time.Duration(graceDaysInHours+graceHours) +
-			time.Minute*time.Duration(graceMinutes) +
-			time.Second*time.Duration(graceSseconds))
-
-	if addedTimePeriod.Sub(now).Hours()/float64(24) > 365 || addedTimePeriod.Sub(now).Seconds() < 30 {
-		return check, errors.New(fmt.Sprintf("period must be between 30 seconds and 365 days"))
-	}
-
-	if addedTimeGrace.Sub(now).Hours()/float64(24) > 365 {
-		return check, errors.New("grace must be less than 365 days")
-	}
-
-	return check, nil
-}
-
-func resourceDataFromHeartbeat(c *checkly.HeartbeatCheck, d *schema.ResourceData) error {
-	d.Set("name", c.Name)
-	d.Set("activated", c.Activated)
-	d.Set("muted", c.Muted)
-
-	sort.Strings(c.Tags)
-	d.Set("tags", c.Tags)
-	if err := d.Set("alert_settings", setFromAlertSettings(c.AlertSettings)); err != nil {
-		return fmt.Errorf("error setting alert settings for resource %s: %w", d.Id(), err)
-	}
-	d.Set("use_global_alert_settings", c.UseGlobalAlertSettings)
-
-	err := d.Set("heartbeat", setFromHeartbeat(c.Heartbeat))
-	if err != nil {
-		return fmt.Errorf("error setting heartbeat for resource %s: %w %v", d.Id(), err, c.Heartbeat)
-	}
-
-	d.Set("alert_channel_subscription", c.AlertChannelSubscriptions)
-	d.SetId(d.Id())
-
-	return nil
-}
-
-func setFromHeartbeat(r checkly.Heartbeat) []tfMap {
-	s := tfMap{}
-	s["period"] = r.Period
-	s["period_unit"] = r.PeriodUnit
-	s["grace_unit"] = r.GraceUnit
-	s["grace"] = r.Grace
-	s["ping_token"] = r.PingToken
-	return []tfMap{s}
-}
-
-func heartbeatFromSet(s *schema.Set) checkly.Heartbeat {
-	if s.Len() == 0 {
-		return checkly.Heartbeat{}
-	}
-	res := s.List()[0].(tfMap)
-	return checkly.Heartbeat{
-		Period:     res["period"].(int),
-		PeriodUnit: res["period_unit"].(string),
-		Grace:      res["grace"].(int),
-		GraceUnit:  res["grace_unit"].(string),
-		PingToken:  res["ping_token"].(string),
-	}
-}
diff --git a/checkly/resource_heartbeat_test.go b/checkly/resource_heartbeat_test.go
deleted file mode 100644
index 3d11882..0000000
--- a/checkly/resource_heartbeat_test.go
+++ /dev/null
@@ -1,192 +0,0 @@
-package checkly
-
-import (
-	"regexp"
-	"testing"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-)
-
-func TestAccHeartbeatRequiredFields(t *testing.T) {
-	config := `resource "checkly_heartbeat" "test" {}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "name" is required, but no definition was found.`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "activated" is required, but no definition was found.`),
-		},
-	})
-}
-
-func TestAccHeartbeatCheckInvalidInputs(t *testing.T) {
-	config := `resource "checkly_check" "test" {
-		name                      = 1
-		activated                 = "invalid"
-		use_global_alert_settings = "invalid"
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`Inappropriate value for attribute "activated"`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`Inappropriate value for attribute "use_global_alert_settings"`),
-		},
-	})
-}
-
-func TestAccHeartbeatCheckMissingHeartbeatBlock(t *testing.T) {
-	config := `resource "checkly_heartbeat" "test" {
-		activated = true
-		name = "heartbeat check"
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`At least 1 "heartbeat" blocks are required.`),
-		},
-	})
-}
-
-func TestAccHeartbeatCheckMissingHeartbeatFields(t *testing.T) {
-	config := `resource "checkly_heartbeat" "test" {
-		activated = true
-		name = "heartbeat check"
-		heartbeat {
-
-		}
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "grace" is required, but no definition was found.`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "grace_unit" is required, but no definition was found.`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "period" is required, but no definition was found.`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "period_unit" is required, but no definition was found.`),
-		},
-	})
-}
-
-func TestAccHeartbeatCheckPeriodTooBig(t *testing.T) {
-	config := `resource "checkly_heartbeat" "test" {
-		activated = true
-		name = "heartbeat check"
-		heartbeat {
-			period = 366
-			period_unit = "days"
-			grace = 0
-			grace_unit = "seconds"
-		}
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`translation error: period must be between 30 seconds and 365 days`),
-		},
-	})
-}
-
-func TestAccHeartbeatCheckPeriodTooSmall(t *testing.T) {
-	config := `resource "checkly_heartbeat" "test" {
-		activated = true
-		name = "heartbeat check"
-		heartbeat {
-			period = 5
-			period_unit = "seconds"
-			grace = 0
-			grace_unit = "seconds"
-		}
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`translation error: period must be between 30 seconds and 365 days`),
-		},
-	})
-}
-
-func TestAccHeartbeatCheckInvalidPeriodUnit(t *testing.T) {
-	config := `resource "checkly_heartbeat" "test" {
-		activated = true
-		name = "heartbeat check"
-		heartbeat {
-			period = 5
-			period_unit = "lightyear"
-			grace = 0
-			grace_unit = "seconds"
-		}
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`"heartbeat\.0\.period_unit" must be one of \[seconds minutes hours days\], got lightyear`),
-		},
-	})
-}
-
-func TestAccHeartbeatCheckInvalidGraceUnit(t *testing.T) {
-	config := `resource "checkly_heartbeat" "test" {
-		activated = true
-		name = "heartbeat check"
-		heartbeat {
-			period = 5
-			period_unit = "days"
-			grace = 0
-			grace_unit = "lightyear"
-		}
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`"heartbeat\.0\.grace_unit" must be one of \[seconds minutes hours days\], got lightyear`),
-		},
-	})
-}
-
-func TestAccHeartbeatCheckCreate(t *testing.T) {
-	config := `resource "checkly_heartbeat" "test" {
-		activated = true
-		name = "heartbeat check"
-		heartbeat {
-			period = 5
-			period_unit = "days"
-			grace = 0
-			grace_unit = "seconds"
-		}
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: config,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_heartbeat.test",
-					"name",
-					"heartbeat check",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_heartbeat.test",
-					"heartbeat.*.period",
-					"5",
-				),
-				testCheckResourceAttrExpr(
-					"checkly_heartbeat.test",
-					"heartbeat.*.period_unit",
-					"days",
-				),
-			),
-		},
-	})
-}
diff --git a/checkly/resource_maintenance_window.go b/checkly/resource_maintenance_window.go
deleted file mode 100644
index b8f5a32..0000000
--- a/checkly/resource_maintenance_window.go
+++ /dev/null
@@ -1,183 +0,0 @@
-package checkly
-
-import (
-	"context"
-	"fmt"
-	"strconv"
-	"strings"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	checkly "github.com/checkly/checkly-go-sdk"
-)
-
-func resourceMaintenanceWindow() *schema.Resource {
-	return &schema.Resource{
-		Create: resourceMaintenanceWindowCreate,
-		Read:   resourceMaintenanceWindowRead,
-		Update: resourceMaintenanceWindowUpdate,
-		Delete: resourceMaintenanceWindowDelete,
-		Importer: &schema.ResourceImporter{
-			StateContext: schema.ImportStatePassthroughContext,
-		},
-		Schema: map[string]*schema.Schema{
-			"name": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "The maintenance window name.",
-			},
-			"starts_at": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "The start date of the maintenance window.",
-			},
-			"ends_at": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "The end date of the maintenance window.",
-			},
-			"repeat_unit": {
-				Type:     schema.TypeString,
-				Optional: true,
-				Default:  nil,
-				ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) {
-					v := value.(string)
-					isValid := false
-					options := []string{"DAY", "WEEK", "MONTH"}
-					for _, option := range options {
-						if v == option {
-							isValid = true
-						}
-					}
-					if !isValid {
-						errs = append(errs, fmt.Errorf("%q must be one of %v, got %s", key, options, v))
-					}
-					return warns, errs
-				},
-				Description: "The repeat cadence for the maintenance window. Possible values `DAY`, `WEEK` and `MONTH`.",
-			},
-			"repeat_interval": {
-				Type:        schema.TypeInt,
-				Optional:    true,
-				Default:     nil,
-				Description: "The repeat interval of the maintenance window from the first occurrence.",
-			},
-			"repeat_ends_at": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Default:     nil,
-				Description: "The date on which the maintenance window should stop repeating.",
-			},
-			"tags": {
-				Type:     schema.TypeSet,
-				Optional: true,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-				DefaultFunc: func() (interface{}, error) {
-					return []tfMap{}, nil
-				},
-				Description: "The names of the checks and groups maintenance window should apply to.",
-			},
-		},
-	}
-}
-
-func maintenanceWindowsFromResourceData(d *schema.ResourceData) (checkly.MaintenanceWindow, error) {
-	ID, err := strconv.ParseInt(d.Id(), 10, 64)
-	if err != nil {
-		if d.Id() != "" {
-			return checkly.MaintenanceWindow{}, err
-		}
-		ID = 0
-	}
-	a := checkly.MaintenanceWindow{
-		ID:             ID,
-		Name:           d.Get("name").(string),
-		StartsAt:       d.Get("starts_at").(string),
-		EndsAt:         d.Get("ends_at").(string),
-		RepeatUnit:     d.Get("repeat_unit").(string),
-		RepeatEndsAt:   d.Get("repeat_ends_at").(string),
-		RepeatInterval: d.Get("repeat_interval").(int),
-		Tags:           stringsFromSet(d.Get("tags").(*schema.Set)),
-	}
-
-	fmt.Printf("%v", a)
-
-	return a, nil
-}
-
-func resourceDataFromMaintenanceWindows(s *checkly.MaintenanceWindow, d *schema.ResourceData) error {
-	d.Set("name", s.Name)
-	d.Set("starts_at", s.StartsAt)
-	d.Set("ends_at", s.EndsAt)
-	d.Set("repeat_unit", s.RepeatUnit)
-	d.Set("repeat_ends_at", s.RepeatEndsAt)
-	d.Set("repeat_interval", s.RepeatInterval)
-	d.Set("tags", s.Tags)
-	return nil
-}
-
-func resourceMaintenanceWindowCreate(d *schema.ResourceData, client interface{}) error {
-	mw, err := maintenanceWindowsFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("resourceMaintenanceWindowCreate: translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	result, err := client.(checkly.Client).CreateMaintenanceWindow(ctx, mw)
-
-	if err != nil {
-		return fmt.Errorf("CreateMaintenanceWindows: API error: %w", err)
-	}
-
-	d.SetId(fmt.Sprintf("%d", result.ID))
-	return resourceMaintenanceWindowRead(d, client)
-}
-
-func resourceMaintenanceWindowUpdate(d *schema.ResourceData, client interface{}) error {
-	mw, err := maintenanceWindowsFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("resourceMaintenanceWindowUpdate: translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	_, err = client.(checkly.Client).UpdateMaintenanceWindow(ctx, mw.ID, mw)
-	if err != nil {
-		return fmt.Errorf("resourceMaintenanceWindowUpdate: API error: %w", err)
-	}
-	d.SetId(fmt.Sprintf("%d", mw.ID))
-	return resourceMaintenanceWindowRead(d, client)
-}
-
-func resourceMaintenanceWindowDelete(d *schema.ResourceData, client interface{}) error {
-	ID, err := strconv.ParseInt(d.Id(), 10, 64)
-	if err != nil {
-		return fmt.Errorf("resourceMaintenanceWindowDelete: ID %s is not numeric: %w", d.Id(), err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	err = client.(checkly.Client).DeleteMaintenanceWindow(ctx, ID)
-	if err != nil {
-		return fmt.Errorf("resourceMaintenanceWindowDelete: API error: %w", err)
-	}
-	return nil
-}
-
-func resourceMaintenanceWindowRead(d *schema.ResourceData, client interface{}) error {
-	ID, err := strconv.ParseInt(d.Id(), 10, 64)
-	if err != nil {
-		return fmt.Errorf("resourceMaintenanceWindowRead: ID %s is not numeric: %w", d.Id(), err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	mw, err := client.(checkly.Client).GetMaintenanceWindow(ctx, ID)
-	defer cancel()
-	if err != nil {
-		if strings.Contains(err.Error(), "404") {
-			d.SetId("")
-			return nil
-		}
-		return fmt.Errorf("resourceMaintenanceWindowRead: API error: %w", err)
-	}
-	return resourceDataFromMaintenanceWindows(mw, d)
-}
diff --git a/checkly/resource_private_locations.go b/checkly/resource_private_locations.go
deleted file mode 100644
index d0e3f37..0000000
--- a/checkly/resource_private_locations.go
+++ /dev/null
@@ -1,123 +0,0 @@
-package checkly
-
-import (
-	"context"
-	"fmt"
-	"strings"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	checkly "github.com/checkly/checkly-go-sdk"
-)
-
-func resourcePrivateLocation() *schema.Resource {
-	return &schema.Resource{
-		Create: resourcePrivateLocationCreate,
-		Read:   resourcePrivateLocationRead,
-		Update: resourcePrivateLocationUpdate,
-		Delete: resourcePrivateLocationDelete,
-		Importer: &schema.ResourceImporter{
-			StateContext: schema.ImportStatePassthroughContext,
-		},
-		Schema: map[string]*schema.Schema{
-			"name": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "The private location name.",
-			},
-			"slug_name": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "Valid slug name.",
-			},
-			"icon": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Default:     "location",
-				Description: "Icon assigned to the private location.",
-			},
-			"keys": {
-				Type:      schema.TypeSet,
-				Computed:  true,
-				Sensitive: true,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-				Description: "Private location API keys.",
-			},
-		},
-	}
-}
-
-func privateLocationFromResourceData(d *schema.ResourceData) (checkly.PrivateLocation, error) {
-	return checkly.PrivateLocation{
-		Name:     d.Get("name").(string),
-		SlugName: d.Get("slug_name").(string),
-		Icon:     d.Get("icon").(string),
-	}, nil
-}
-
-func resourcePrivateLocationCreate(d *schema.ResourceData, client interface{}) error {
-	pl, err := privateLocationFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("resourcePrivateLocationCreate: translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	result, err := client.(checkly.Client).CreatePrivateLocation(ctx, pl)
-	if err != nil {
-		return fmt.Errorf("CreatePrivateLocation: API error: %w", err)
-	}
-	d.SetId(result.ID)
-
-	var keys = []string{result.Keys[0].RawKey}
-	d.Set("keys", keys)
-	return resourcePrivateLocationRead(d, client)
-}
-
-func resourceDataFromPrivateLocation(pl *checkly.PrivateLocation, d *schema.ResourceData) error {
-	d.Set("name", pl.Name)
-	d.Set("slug_name", pl.SlugName)
-	d.Set("icon", pl.Icon)
-	return nil
-}
-
-func resourcePrivateLocationUpdate(d *schema.ResourceData, client interface{}) error {
-	pl, err := privateLocationFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("resourcePrivateLocationUpdate: translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	_, err = client.(checkly.Client).UpdatePrivateLocation(ctx, d.Id(), pl)
-	if err != nil {
-		return fmt.Errorf("resourcePrivateLocationUpdate: API error: %w", err)
-	}
-	return resourcePrivateLocationRead(d, client)
-}
-
-func resourcePrivateLocationRead(d *schema.ResourceData, client interface{}) error {
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	pl, err := client.(checkly.Client).GetPrivateLocation(ctx, d.Id())
-	if err != nil {
-		if strings.Contains(err.Error(), "404") {
-			//if resource is deleted remotely, then mark it as
-			//successfully gone by unsetting it's ID
-			d.SetId("")
-			return nil
-		}
-		return fmt.Errorf("resourcePrivateLocationRead: %w", err)
-	}
-	return resourceDataFromPrivateLocation(pl, d)
-}
-
-func resourcePrivateLocationDelete(d *schema.ResourceData, client interface{}) error {
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	err := client.(checkly.Client).DeletePrivateLocation(ctx, d.Id())
-	if err != nil {
-		return fmt.Errorf("resourcePrivateLocationDelete: API error: %w", err)
-	}
-	return nil
-}
diff --git a/checkly/resource_private_locations_test.go b/checkly/resource_private_locations_test.go
deleted file mode 100644
index d5e5f4e..0000000
--- a/checkly/resource_private_locations_test.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package checkly
-
-import (
-	"regexp"
-	"testing"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-)
-
-func TestAccPrivateLocationCheckRequiredFields(t *testing.T) {
-	config := `resource "checkly_private_location" "test" {}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "name" is required`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "slug_name" is required`),
-		},
-	})
-}
-
-func TestAccPrivateLocationSuccess(t *testing.T) {
-	config := `resource "checkly_private_location" "test" {
-		name     = "New Private Location"
-		slug_name   = "new-private-location"
-		icon       	= "bell-fill"
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: config,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_private_location.test",
-					"name",
-					"New Private Location",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_private_location.test",
-					"slug_name",
-					"new-private-location",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_private_location.test",
-					"icon",
-					"bell-fill",
-				),
-			),
-		},
-	})
-}
-
-func TestAccPrivateLocationDefaultIcon(t *testing.T) {
-	config := `resource "checkly_private_location" "without_icon" {
-		name     = "New Private Location"
-		slug_name   = "new-private-location"
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: config,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_private_location.without_icon",
-					"name",
-					"New Private Location",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_private_location.without_icon",
-					"slug_name",
-					"new-private-location",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_private_location.without_icon",
-					"icon",
-					"location",
-				),
-			),
-		},
-	})
-}
diff --git a/checkly/resource_snippet.go b/checkly/resource_snippet.go
deleted file mode 100644
index 3ea903a..0000000
--- a/checkly/resource_snippet.go
+++ /dev/null
@@ -1,129 +0,0 @@
-package checkly
-
-import (
-	"context"
-	"fmt"
-	"strconv"
-	"strings"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	checkly "github.com/checkly/checkly-go-sdk"
-)
-
-func resourceSnippet() *schema.Resource {
-	return &schema.Resource{
-		Create: resourceSnippetCreate,
-		Read:   resourceSnippetRead,
-		Update: resourceSnippetUpdate,
-		Delete: resourceSnippetDelete,
-		Importer: &schema.ResourceImporter{
-			StateContext: schema.ImportStatePassthroughContext,
-		},
-		Schema: map[string]*schema.Schema{
-			"name": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "The name of the snippet",
-			},
-			"script": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "Your Node.js code that interacts with the API check lifecycle, or functions as a partial for browser checks.",
-			},
-		},
-	}
-}
-
-func resourceSnippetCreate(d *schema.ResourceData, client interface{}) error {
-	snippet, err := snippetFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("resourceSnippetCreate: translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	result, err := client.(checkly.Client).CreateSnippet(ctx, snippet)
-	if err != nil {
-		return fmt.Errorf("CreateSnippet: API error: %w", err)
-	}
-	d.SetId(fmt.Sprintf("%d", result.ID))
-	return resourceSnippetRead(d, client)
-}
-
-func snippetFromResourceData(d *schema.ResourceData) (checkly.Snippet, error) {
-	id, err := resourceIDToInt(d.Id())
-	if err != nil {
-		return checkly.Snippet{}, err
-	}
-	return checkly.Snippet{
-		ID:     id,
-		Name:   d.Get("name").(string),
-		Script: d.Get("script").(string),
-	}, nil
-}
-
-func resourceDataFromSnippet(s *checkly.Snippet, d *schema.ResourceData) error {
-	d.Set("name", s.Name)
-	d.Set("script", s.Script)
-	return nil
-}
-
-func resourceIDToInt(id string) (int64, error) {
-	if id == "" {
-		return 0, nil
-	}
-	res, err := strconv.ParseInt(id, 10, 64)
-	if err != nil {
-		return 0, err
-	}
-	return res, nil
-}
-
-func resourceSnippetRead(d *schema.ResourceData, client interface{}) error {
-	ID, err := strconv.ParseInt(d.Id(), 10, 64)
-	if err != nil {
-		return fmt.Errorf("resourceSnippetRead: ID %s is not numeric: %w", d.Id(), err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	snippet, err := client.(checkly.Client).GetSnippet(ctx, ID)
-	if err != nil {
-		if strings.Contains(err.Error(), "404") {
-			//if resource is deleted remotely, then mark it as
-			//successfully gone by unsetting it's ID
-			d.SetId("")
-			return nil
-		}
-		return fmt.Errorf("resourceSnippetRead: API error: %w", err)
-	}
-	return resourceDataFromSnippet(snippet, d)
-}
-
-func resourceSnippetUpdate(d *schema.ResourceData, client interface{}) error {
-	snippet, err := snippetFromResourceData(d)
-	if err != nil {
-		return fmt.Errorf("resourceSnippetUpdate: translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	_, err = client.(checkly.Client).UpdateSnippet(ctx, snippet.ID, snippet)
-	if err != nil {
-		return fmt.Errorf("resourceSnippetUpdate: API error: %w", err)
-	}
-	d.SetId(fmt.Sprintf("%d", snippet.ID))
-	return resourceSnippetRead(d, client)
-}
-
-func resourceSnippetDelete(d *schema.ResourceData, client interface{}) error {
-	ID, err := strconv.ParseInt(d.Id(), 10, 64)
-	if err != nil {
-		return fmt.Errorf("resourceSnippetDelete: ID %s is not numeric: %w", d.Id(), err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	err = client.(checkly.Client).DeleteSnippet(ctx, ID)
-	if err != nil {
-		return fmt.Errorf("resourceSnippetDelete: API error: %w", err)
-	}
-	return nil
-}
diff --git a/checkly/resource_snippets_test.go b/checkly/resource_snippets_test.go
deleted file mode 100644
index 08536db..0000000
--- a/checkly/resource_snippets_test.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package checkly
-
-import (
-	"regexp"
-	"testing"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-)
-
-func TestAccSnippetCheckRequiredFields(t *testing.T) {
-	config := `resource "checkly_snippet" "test" {}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "name" is required`),
-		},
-		{
-			Config:      config,
-			ExpectError: regexp.MustCompile(`The argument "script" is required`),
-		},
-	})
-}
-
-func TestAccSnippetSuccess(t *testing.T) {
-	config := `resource "checkly_snippet" "test" {
-		name     = "foo"
-		script   = "console.log('bar')"
-	}`
-	accTestCase(t, []resource.TestStep{
-		{
-			Config: config,
-			Check: resource.ComposeTestCheckFunc(
-				resource.TestCheckResourceAttr(
-					"checkly_snippet.test",
-					"name",
-					"foo",
-				),
-				resource.TestCheckResourceAttr(
-					"checkly_snippet.test",
-					"script",
-					"console.log('bar')",
-				),
-			),
-		},
-	})
-}
diff --git a/checkly/resource_trigger_check.go b/checkly/resource_trigger_check.go
deleted file mode 100644
index 18d60ee..0000000
--- a/checkly/resource_trigger_check.go
+++ /dev/null
@@ -1,124 +0,0 @@
-package checkly
-
-import (
-	"context"
-	"fmt"
-	"strconv"
-	"strings"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	checkly "github.com/checkly/checkly-go-sdk"
-)
-
-func resourceTriggerCheck() *schema.Resource {
-	return &schema.Resource{
-		Create: resourceTriggerCheckCreate,
-		Read:   resourceTriggerCheckRead,
-		Delete: resourceTriggerCheckDelete,
-		Update: resourceTriggerCheckUpdate,
-		Importer: &schema.ResourceImporter{
-			StateContext: schema.ImportStatePassthroughContext,
-		},
-		Schema: map[string]*schema.Schema{
-			"check_id": {
-				Type:        schema.TypeString,
-				Required:    true,
-				Description: "The id of the check that you want to attach the trigger to.",
-			},
-			"token": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Computed:    true,
-				Description: "The token value created to trigger the check",
-			},
-			"url": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Computed:    true,
-				Description: "The request URL to trigger the check run.",
-			},
-		},
-	}
-}
-
-func triggerCheckFromResourceData(data *schema.ResourceData) (checkly.TriggerCheck, error) {
-	ID, err := strconv.ParseInt(data.Id(), 10, 64)
-	if err != nil {
-		if data.Id() != "" {
-			return checkly.TriggerCheck{}, err
-		}
-		ID = 0
-	}
-	return checkly.TriggerCheck{
-		ID:      ID,
-		CheckId: data.Get("check_id").(string),
-		Token:   data.Get("token").(string),
-		URL:     data.Get("url").(string),
-	}, nil
-}
-
-func resourceDataFromTriggerCheck(trigger *checkly.TriggerCheck, data *schema.ResourceData) error {
-	data.Set("check_id", trigger.CheckId)
-	data.Set("token", trigger.Token)
-	data.Set("url", trigger.URL)
-	return nil
-}
-
-func resourceTriggerCheckCreate(data *schema.ResourceData, client interface{}) error {
-	trigger, err := triggerCheckFromResourceData(data)
-	if err != nil {
-		return fmt.Errorf("resourceTriggerCheckCreate: translation error: %w", err)
-	}
-
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	result, err := client.(checkly.Client).CreateTriggerCheck(ctx, trigger.CheckId)
-	if err != nil {
-		return fmt.Errorf("CreateTriggerCheck: API error: %w", err)
-	}
-
-	data.SetId(fmt.Sprintf("%d", result.ID))
-
-	return resourceTriggerCheckRead(data, client)
-}
-
-func resourceTriggerCheckDelete(data *schema.ResourceData, client interface{}) error {
-	trigger, err := triggerCheckFromResourceData(data)
-	if err != nil {
-		return fmt.Errorf("resourceTriggerCheckDelete: translation error: %w", err)
-	}
-
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	err = client.(checkly.Client).DeleteTriggerCheck(ctx, trigger.CheckId)
-	if err != nil {
-		return fmt.Errorf("DeleteTriggerCheck: API error: %w", err)
-	}
-
-	return nil
-}
-
-func resourceTriggerCheckRead(data *schema.ResourceData, client interface{}) error {
-	trigger, err := triggerCheckFromResourceData(data)
-	if err != nil {
-		return fmt.Errorf("resourceTriggerCheckRead: ID %s is not numeric: %w", data.Id(), err)
-	}
-
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	result, err := client.(checkly.Client).GetTriggerCheck(ctx, trigger.CheckId)
-	defer cancel()
-	if err != nil {
-		if strings.Contains(err.Error(), "404") {
-			data.SetId("")
-			return nil
-		}
-		return fmt.Errorf("GetTriggerCheck: API error: %w", err)
-	}
-
-	return resourceDataFromTriggerCheck(result, data)
-}
-
-func resourceTriggerCheckUpdate(data *schema.ResourceData, client interface{}) error {
-	return resourceTriggerCheckRead(data, client)
-}
diff --git a/checkly/resource_trigger_group.go b/checkly/resource_trigger_group.go
deleted file mode 100644
index 1b344df..0000000
--- a/checkly/resource_trigger_group.go
+++ /dev/null
@@ -1,123 +0,0 @@
-package checkly
-
-import (
-	"context"
-	"fmt"
-	"strconv"
-	"strings"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
-	checkly "github.com/checkly/checkly-go-sdk"
-)
-
-func resourceTriggerGroup() *schema.Resource {
-	return &schema.Resource{
-		Create: resourceTriggerGroupCreate,
-		Read:   resourceTriggerGroupRead,
-		Delete: resourceTriggerGroupDelete,
-		Update: resourceTriggerGroupUpdate,
-		Importer: &schema.ResourceImporter{
-			StateContext: schema.ImportStatePassthroughContext,
-		},
-		Schema: map[string]*schema.Schema{
-			"group_id": {
-				Type:        schema.TypeInt,
-				Required:    true,
-				Description: "The id of the group that you want to attach the trigger to.",
-			},
-			"token": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Computed:    true,
-				Description: "The token value created to trigger the group",
-			},
-			"url": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Computed:    true,
-				Description: "The request URL to trigger the group run.",
-			},
-		},
-	}
-}
-
-func triggerGroupFromResourceData(data *schema.ResourceData) (checkly.TriggerGroup, error) {
-	ID, err := strconv.ParseInt(data.Id(), 10, 64)
-	if err != nil {
-		if data.Id() != "" {
-			return checkly.TriggerGroup{}, err
-		}
-		ID = 0
-	}
-
-	return checkly.TriggerGroup{
-		ID:      ID,
-		GroupId: int64(data.Get("group_id").(int)),
-		Token:   data.Get("token").(string),
-	}, nil
-}
-
-func resourceDataFromTriggerGroup(trigger *checkly.TriggerGroup, data *schema.ResourceData) error {
-	data.Set("group_id", trigger.GroupId)
-	data.Set("token", trigger.Token)
-	data.Set("url", trigger.URL)
-	return nil
-}
-
-func resourceTriggerGroupCreate(data *schema.ResourceData, client interface{}) error {
-	tc, err := triggerGroupFromResourceData(data)
-	if err != nil {
-		return fmt.Errorf("resourceTriggerGroupCreate: translation error: %w", err)
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	result, err := client.(checkly.Client).CreateTriggerGroup(ctx, tc.GroupId)
-
-	if err != nil {
-		return fmt.Errorf("CreateTriggerGroup: API error: %w", err)
-	}
-
-	data.SetId(fmt.Sprintf("%d", result.ID))
-
-	return resourceTriggerGroupRead(data, client)
-}
-
-func resourceTriggerGroupDelete(data *schema.ResourceData, client interface{}) error {
-	tc, err := triggerGroupFromResourceData(data)
-	if err != nil {
-		return fmt.Errorf("resourceTriggerGroupDelete: translation error: %w", err)
-	}
-
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	defer cancel()
-	err = client.(checkly.Client).DeleteTriggerGroup(ctx, tc.GroupId)
-	if err != nil {
-		return fmt.Errorf("DeleteTriggerGroup: API error: %w", err)
-	}
-
-	return nil
-}
-
-func resourceTriggerGroupRead(data *schema.ResourceData, client interface{}) error {
-	trigger, err := triggerGroupFromResourceData(data)
-	if err != nil {
-		return fmt.Errorf("resourceTriggerGroupRead: ID %s is not numeric: %w", data.Id(), err)
-	}
-
-	ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout())
-	result, err := client.(checkly.Client).GetTriggerGroup(ctx, trigger.GroupId)
-	defer cancel()
-	if err != nil {
-		if strings.Contains(err.Error(), "404") {
-			data.SetId("")
-			return nil
-		}
-		return fmt.Errorf("GetTriggerGroup: API error: %w", err)
-	}
-	return resourceDataFromTriggerGroup(result, data)
-}
-
-func resourceTriggerGroupUpdate(data *schema.ResourceData, client interface{}) error {
-	return resourceTriggerCheckRead(data, client)
-}
diff --git a/docs/data-sources/static_ips.md b/docs/data-sources/static_ips.md
index c7c073a..5c61dc6 100644
--- a/docs/data-sources/static_ips.md
+++ b/docs/data-sources/static_ips.md
@@ -23,4 +23,4 @@ description: |-
 ### Read-Only
 
 - `addresses` (Set of String) Static IP addresses for Checkly's runner infrastructure.
-- `id` (String) ID of the static IPs data source.
+- `id` (String) The ID of this data source.
diff --git a/docs/index.md b/docs/index.md
index e487bc6..316481b 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -61,14 +61,14 @@ resource "checkly_check" "example_check" {
     "us-west-1"
   ]
 
-  request {
+  request = {
     url              = "https://api.example.com/"
     follow_redirects = true
-    assertion {
+    assertions = [{
       source     = "STATUS_CODE"
       comparison = "EQUALS"
       target     = "200"
-    }
+    }]
   }
 }
 ```
@@ -76,13 +76,10 @@ resource "checkly_check" "example_check" {
 <!-- schema generated by tfplugindocs -->
 ## Schema
 
-### Required
-
-- `api_key` (String)
-
 ### Optional
 
 - `account_id` (String)
+- `api_key` (String, Sensitive)
 - `api_url` (String)
 
 > For additional documentation and examples, check the Resources sections.
\ No newline at end of file
diff --git a/docs/resources/alert_channel.md b/docs/resources/alert_channel.md
index 2672f4f..4596edf 100644
--- a/docs/resources/alert_channel.md
+++ b/docs/resources/alert_channel.md
@@ -3,19 +3,19 @@
 page_title: "checkly_alert_channel Resource - terraform-provider-checkly"
 subcategory: ""
 description: |-
-  Allows you to define alerting channels for the checks and groups in your account
+  Allows you to define alerting channels for the checks and groups in your account.
 ---
 
 # checkly_alert_channel (Resource)
 
-Allows you to define alerting channels for the checks and groups in your account
+Allows you to define alerting channels for the checks and groups in your account.
 
 ## Example Usage
 
 ```terraform
 # An Email alert channel
 resource "checkly_alert_channel" "email_ac" {
-  email {
+  email = {
     address = "john@example.com"
   }
   send_recovery        = true
@@ -27,7 +27,7 @@ resource "checkly_alert_channel" "email_ac" {
 
 # A SMS alert channel
 resource "checkly_alert_channel" "sms_ac" {
-  sms {
+  sms = {
     name   = "john"
     number = "+5491100001111"
   }
@@ -37,7 +37,7 @@ resource "checkly_alert_channel" "sms_ac" {
 
 # A Slack alert channel
 resource "checkly_alert_channel" "slack_ac" {
-  slack {
+  slack = {
     channel = "#checkly-notifications"
     url     = "https://hooks.slack.com/services/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"
   }
@@ -45,7 +45,7 @@ resource "checkly_alert_channel" "slack_ac" {
 
 # An Opsgenie alert channel
 resource "checkly_alert_channel" "opsgenie_ac" {
-  opsgenie {
+  opsgenie = {
     name     = "opsalerts"
     api_key  = "fookey"
     region   = "fooregion"
@@ -55,7 +55,7 @@ resource "checkly_alert_channel" "opsgenie_ac" {
 
 # A Pagerduty alert channel
 resource "checkly_alert_channel" "pagerduty_ac" {
-  pagerduty {
+  pagerduty = {
     account      = "checkly"
     service_key  = "key1"
     service_name = "pdalert"
@@ -64,7 +64,7 @@ resource "checkly_alert_channel" "pagerduty_ac" {
 
 # A Webhook alert channel
 resource "checkly_alert_channel" "webhook_ac" {
-  webhook {
+  webhook = {
     name           = "foo"
     method         = "get"
     template       = "footemplate"
@@ -75,7 +75,7 @@ resource "checkly_alert_channel" "webhook_ac" {
 
 # A Firehydran alert channel integration
 resource "checkly_alert_channel" "firehydrant_ac" {
-  webhook {
+  webhook = {
     name         = "firehydrant"
     method       = "post"
     template     = <<EOT
@@ -98,15 +98,16 @@ resource "checkly_alert_channel" "firehydrant_ac" {
 resource "checkly_check" "example_check" {
   name = "Example check"
 
-  alert_channel_subscription {
-    channel_id = checkly_alert_channel.email_ac.id
-    activated  = true
-  }
-
-  alert_channel_subscription {
-    channel_id = checkly_alert_channel.sms_ac.id
-    activated  = true
-  }
+  alert_channel_subscriptions = [
+    {
+      channel_id = checkly_alert_channel.email_ac.id
+      activated  = true
+    },
+    {
+      channel_id = checkly_alert_channel.sms_ac.id
+      activated  = true
+    }
+  ]
 }
 ```
 
@@ -115,24 +116,24 @@ resource "checkly_check" "example_check" {
 
 ### Optional
 
-- `call` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--call))
-- `email` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--email))
-- `opsgenie` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--opsgenie))
-- `pagerduty` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--pagerduty))
+- `call` (Attributes) (see [below for nested schema](#nestedatt--call))
+- `email` (Attributes) (see [below for nested schema](#nestedatt--email))
+- `opsgenie` (Attributes) (see [below for nested schema](#nestedatt--opsgenie))
+- `pagerduty` (Attributes) (see [below for nested schema](#nestedatt--pagerduty))
 - `send_degraded` (Boolean) (Default `false`)
 - `send_failure` (Boolean) (Default `true`)
 - `send_recovery` (Boolean) (Default `true`)
-- `slack` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--slack))
-- `sms` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--sms))
+- `slack` (Attributes) (see [below for nested schema](#nestedatt--slack))
+- `sms` (Attributes) (see [below for nested schema](#nestedatt--sms))
 - `ssl_expiry` (Boolean) (Default `false`)
 - `ssl_expiry_threshold` (Number) Value must be between 1 and 30 (Default `30`)
-- `webhook` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--webhook))
+- `webhook` (Attributes) (see [below for nested schema](#nestedatt--webhook))
 
 ### Read-Only
 
 - `id` (String) The ID of this resource.
 
-<a id="nestedblock--call"></a>
+<a id="nestedatt--call"></a>
 ### Nested Schema for `call`
 
 Required:
@@ -141,7 +142,7 @@ Required:
 - `number` (String) The mobile number to receive the alerts
 
 
-<a id="nestedblock--email"></a>
+<a id="nestedatt--email"></a>
 ### Nested Schema for `email`
 
 Required:
@@ -149,7 +150,7 @@ Required:
 - `address` (String) The email address of this email alert channel.
 
 
-<a id="nestedblock--opsgenie"></a>
+<a id="nestedatt--opsgenie"></a>
 ### Nested Schema for `opsgenie`
 
 Required:
@@ -160,7 +161,7 @@ Required:
 - `region` (String)
 
 
-<a id="nestedblock--pagerduty"></a>
+<a id="nestedatt--pagerduty"></a>
 ### Nested Schema for `pagerduty`
 
 Required:
@@ -173,7 +174,7 @@ Optional:
 - `service_name` (String)
 
 
-<a id="nestedblock--slack"></a>
+<a id="nestedatt--slack"></a>
 ### Nested Schema for `slack`
 
 Required:
@@ -182,7 +183,7 @@ Required:
 - `url` (String) The Slack webhook URL
 
 
-<a id="nestedblock--sms"></a>
+<a id="nestedatt--sms"></a>
 ### Nested Schema for `sms`
 
 Required:
@@ -191,7 +192,7 @@ Required:
 - `number` (String) The mobile number to receive the alerts
 
 
-<a id="nestedblock--webhook"></a>
+<a id="nestedatt--webhook"></a>
 ### Nested Schema for `webhook`
 
 Required:
diff --git a/docs/resources/check.md b/docs/resources/check.md
index bfbddbe..b8a3ea2 100644
--- a/docs/resources/check.md
+++ b/docs/resources/check.md
@@ -3,12 +3,12 @@
 page_title: "checkly_check Resource - terraform-provider-checkly"
 subcategory: ""
 description: |-
-  Checks allows you to monitor key webapp flows, backend API's and set up alerting, so you get a notification when things break or slow down.
+  Check groups allow you to group together a set of related checks, which can also share default settings for various attributes.
 ---
 
 # checkly_check (Resource)
 
-Checks allows you to monitor key webapp flows, backend API's and set up alerting, so you get a notification when things break or slow down.
+Check groups allow you to group together a set of related checks, which can also share default settings for various attributes.
 
 ## Example Usage
 
@@ -26,15 +26,15 @@ resource "checkly_check" "example_check" {
     "us-west-1"
   ]
 
-  request {
+  request = {
     url              = "https://api.example.com/"
     follow_redirects = true
     skip_ssl         = false
-    assertion {
+    assertions = [{
       source     = "STATUS_CODE"
       comparison = "EQUALS"
       target     = "200"
-    }
+    }]
   }
 }
 
@@ -54,19 +54,19 @@ resource "checkly_check" "example_check_2" {
     "ap-south-1",
   ]
 
-  alert_settings {
+  alert_settings = {
     escalation_type = "RUN_BASED"
 
-    run_based_escalation {
+    run_based_escalation = {
       failed_run_threshold = 1
     }
 
-    reminders {
+    reminders = {
       amount = 1
     }
   }
 
-  retry_strategy {
+  retry_strategy = {
     type                 = "FIXED"
     base_backoff_seconds = 60
     max_duration_seconds = 600
@@ -74,7 +74,7 @@ resource "checkly_check" "example_check_2" {
     same_region          = false
   }
 
-  request {
+  request = {
     follow_redirects = true
     skip_ssl         = false
     url              = "http://api.example.com/"
@@ -87,21 +87,21 @@ resource "checkly_check" "example_check_2" {
       X-Bogus = "bogus"
     }
 
-    assertion {
+    assertion = {
       source     = "JSON_BODY"
       property   = "code"
       comparison = "HAS_VALUE"
       target     = "authentication.failed"
     }
 
-    assertion {
+    assertion = {
       source     = "STATUS_CODE"
       property   = ""
       comparison = "EQUALS"
       target     = "401"
     }
 
-    basic_auth {
+    basic_auth = {
       username = ""
       password = ""
     }
@@ -137,13 +137,13 @@ EOT
 
 # Connection checks with alert channels
 resource "checkly_alert_channel" "email_ac1" {
-  email {
+  email = {
     address = "info1@example.com"
   }
 }
 
 resource "checkly_alert_channel" "email_ac2" {
-  email {
+  email = {
     address = "info2@example.com"
   }
 }
@@ -152,15 +152,16 @@ resource "checkly_check" "example_check" {
   name = "Example check"
   # ...
 
-  alert_channel_subscription {
-    channel_id = checkly_alert_channel.email_ac1.id
-    activated  = true
-  }
-
-  alert_channel_subscription {
-    channel_id = checkly_alert_channel.email_ac2.id
-    activated  = true
-  }
+  alert_channel_subscriptions = [
+    {
+      channel_id = checkly_alert_channel.email_ac1.id
+      activated  = true
+    },
+    {
+      channel_id = checkly_alert_channel.email_ac2.id
+      activated  = true
+    }
+  ]
 }
 
 # An alternative syntax for add the script is by referencing an external file
@@ -196,23 +197,23 @@ resource "checkly_check" "example_check" {
 
 ### Optional
 
-- `alert_channel_subscription` (Block List) An array of channel IDs and whether they're activated or not. If you don't set at least one alert subscription for your check, we won't be able to alert you in case something goes wrong with it. (see [below for nested schema](#nestedblock--alert_channel_subscription))
-- `alert_settings` (Block List, Max: 1) (see [below for nested schema](#nestedblock--alert_settings))
+- `alert_channel_subscription` (Attributes List) An array of channel IDs and whether they're activated or not. If you don't set at least one alert subscription for your check, we won't be able to alert you in case something goes wrong with it. (see [below for nested schema](#nestedatt--alert_channel_subscription))
+- `alert_settings` (Attributes) (see [below for nested schema](#nestedatt--alert_settings))
 - `degraded_response_time` (Number) The response time in milliseconds starting from which a check should be considered degraded. Possible values are between 0 and 30000. (Default `15000`).
 - `double_check` (Boolean, Deprecated) Setting this to `true` will trigger a retry when a check fails from the failing region and another, randomly selected region before marking the check as failed.
-- `environment_variable` (Block List) Key/value pairs for setting environment variables during check execution, add locked = true to keep value hidden, add secret = true to create a secret variable. These are only relevant for browser checks. Use global environment variables whenever possible. (see [below for nested schema](#nestedblock--environment_variable))
+- `environment_variable` (Attributes List) Introduce additional environment variables to the check execution environment. Only relevant for browser checks. Prefer global environment variables when possible. (see [below for nested schema](#nestedatt--environment_variable))
 - `environment_variables` (Map of String, Deprecated) Key/value pairs for setting environment variables during check execution. These are only relevant for browser checks. Use global environment variables whenever possible.
-- `frequency_offset` (Number) This property only valid for API high frequency checks. To create a hight frequency check, the property `frequency` must be `0` and `frequency_offset` could be `10`, `20` or `30`.
+- `frequency_offset` (Number) This property is only valid for high frequency API checks. To create a high frequency check, the property `frequency` must be `0` and `frequency_offset` could be `10`, `20` or `30`.
 - `group_id` (Number) The id of the check group this check is part of.
 - `group_order` (Number) The position of this check in a check group. It determines in what order checks are run when a group is triggered from the API or from CI/CD.
 - `local_setup_script` (String) A valid piece of Node.js code to run in the setup phase.
 - `local_teardown_script` (String) A valid piece of Node.js code to run in the teardown phase.
-- `locations` (Set of String) An array of one or more data center locations where to run the this check. (Default ["us-east-1"])
+- `locations` (Set of String) An array of one or more data center locations where to run the checks.
 - `max_response_time` (Number) The response time in milliseconds starting from which a check should be considered failing. Possible values are between 0 and 30000. (Default `30000`).
 - `muted` (Boolean) Determines if any notifications will be sent out when a check fails/degrades/recovers.
 - `private_locations` (Set of String) An array of one or more private locations slugs.
-- `request` (Block Set, Max: 1) An API check might have one request config. (see [below for nested schema](#nestedblock--request))
-- `retry_strategy` (Block Set, Max: 1) A strategy for retrying failed check runs. (see [below for nested schema](#nestedblock--retry_strategy))
+- `request` (Attributes) (see [below for nested schema](#nestedatt--request))
+- `retry_strategy` (Attributes) A strategy for retrying failed check runs. (see [below for nested schema](#nestedatt--retry_strategy))
 - `run_parallel` (Boolean) Determines if the check should run in all selected locations in parallel or round-robin.
 - `runtime_id` (String) The id of the runtime to use for this check.
 - `script` (String) A valid piece of Node.js JavaScript code describing a browser interaction with the Puppeteer/Playwright framework or a reference to an external JavaScript file.
@@ -220,7 +221,7 @@ resource "checkly_check" "example_check" {
 - `should_fail` (Boolean) Allows to invert the behaviour of when a check is considered to fail. Allows for validating error status like 404.
 - `ssl_check` (Boolean, Deprecated) Determines if the SSL certificate should be validated for expiry.
 - `ssl_check_domain` (String) A valid fully qualified domain name (FQDN) to check its SSL certificate.
-- `tags` (Set of String) A list of tags for organizing and filtering checks.
+- `tags` (Set of String) Tags for organizing and filtering checks.
 - `teardown_snippet_id` (Number) An ID reference to a snippet to use in the teardown phase of an API check.
 - `use_global_alert_settings` (Boolean) When true, the account level alert settings will be used, not the alert setting defined on this check.
 
@@ -228,7 +229,7 @@ resource "checkly_check" "example_check" {
 
 - `id` (String) The ID of this resource.
 
-<a id="nestedblock--alert_channel_subscription"></a>
+<a id="nestedatt--alert_channel_subscription"></a>
 ### Nested Schema for `alert_channel_subscription`
 
 Required:
@@ -237,28 +238,28 @@ Required:
 - `channel_id` (Number)
 
 
-<a id="nestedblock--alert_settings"></a>
+<a id="nestedatt--alert_settings"></a>
 ### Nested Schema for `alert_settings`
 
 Optional:
 
 - `escalation_type` (String) Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`.
-- `parallel_run_failure_threshold` (Block List) (see [below for nested schema](#nestedblock--alert_settings--parallel_run_failure_threshold))
-- `reminders` (Block List) (see [below for nested schema](#nestedblock--alert_settings--reminders))
-- `run_based_escalation` (Block List) (see [below for nested schema](#nestedblock--alert_settings--run_based_escalation))
-- `ssl_certificates` (Block Set, Deprecated) (see [below for nested schema](#nestedblock--alert_settings--ssl_certificates))
-- `time_based_escalation` (Block List) (see [below for nested schema](#nestedblock--alert_settings--time_based_escalation))
+- `parallel_run_failure_threshold` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--parallel_run_failure_threshold))
+- `reminders` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--reminders))
+- `run_based_escalation` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--run_based_escalation))
+- `ssl_certificates` (Attributes, Deprecated) At what interval the reminders should be sent. (see [below for nested schema](#nestedatt--alert_settings--ssl_certificates))
+- `time_based_escalation` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--time_based_escalation))
 
-<a id="nestedblock--alert_settings--parallel_run_failure_threshold"></a>
+<a id="nestedatt--alert_settings--parallel_run_failure_threshold"></a>
 ### Nested Schema for `alert_settings.parallel_run_failure_threshold`
 
 Optional:
 
 - `enabled` (Boolean) Applicable only for checks scheduled in parallel in multiple locations.
-- `percentage` (Number) Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `100`, and `100`. (Default `10`).
+- `percentage` (Number) Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `90`, and `100`. (Default `10`).
 
 
-<a id="nestedblock--alert_settings--reminders"></a>
+<a id="nestedatt--alert_settings--reminders"></a>
 ### Nested Schema for `alert_settings.reminders`
 
 Optional:
@@ -267,7 +268,7 @@ Optional:
 - `interval` (Number) Possible values are `5`, `10`, `15`, and `30`. (Default `5`).
 
 
-<a id="nestedblock--alert_settings--run_based_escalation"></a>
+<a id="nestedatt--alert_settings--run_based_escalation"></a>
 ### Nested Schema for `alert_settings.run_based_escalation`
 
 Optional:
@@ -275,7 +276,7 @@ Optional:
 - `failed_run_threshold` (Number) After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`).
 
 
-<a id="nestedblock--alert_settings--ssl_certificates"></a>
+<a id="nestedatt--alert_settings--ssl_certificates"></a>
 ### Nested Schema for `alert_settings.ssl_certificates`
 
 Optional:
@@ -284,7 +285,7 @@ Optional:
 - `enabled` (Boolean) Determines if alert notifications should be sent for expiring SSL certificates. Possible values `true`, and `false`. (Default `false`).
 
 
-<a id="nestedblock--alert_settings--time_based_escalation"></a>
+<a id="nestedatt--alert_settings--time_based_escalation"></a>
 ### Nested Schema for `alert_settings.time_based_escalation`
 
 Optional:
@@ -293,21 +294,21 @@ Optional:
 
 
 
-<a id="nestedblock--environment_variable"></a>
+<a id="nestedatt--environment_variable"></a>
 ### Nested Schema for `environment_variable`
 
 Required:
 
-- `key` (String)
-- `value` (String)
+- `key` (String) The name of the environment variable.
+- `value` (String, Sensitive) The value of the environment variable. By default the value is plain text and can be seen by any team member. It will also be present in check results and logs.
 
 Optional:
 
-- `locked` (Boolean)
-- `secret` (Boolean)
+- `locked` (Boolean) Locked environment variables are encrypted at rest and in flight on the Checkly backend and are only decrypted when needed. Their value is hidden by default, but can be accessed by team members with the appropriate permissions.
+- `secret` (Boolean) Secret environment variables are always encrypted and their value is never shown to any user. However, keep in mind that your Terraform state will still contain the value.
 
 
-<a id="nestedblock--request"></a>
+<a id="nestedatt--request"></a>
 ### Nested Schema for `request`
 
 Required:
@@ -316,8 +317,8 @@ Required:
 
 Optional:
 
-- `assertion` (Block Set) A request can have multiple assertions. (see [below for nested schema](#nestedblock--request--assertion))
-- `basic_auth` (Block Set, Max: 1) Set up HTTP basic authentication (username & password). (see [below for nested schema](#nestedblock--request--basic_auth))
+- `assertion` (Attributes List) (see [below for nested schema](#nestedatt--request--assertion))
+- `basic_auth` (Attributes) Credentials for Basic HTTP authentication. (see [below for nested schema](#nestedatt--request--basic_auth))
 - `body` (String) The body of the request.
 - `body_type` (String) The `Content-Type` header of the request. Possible values `NONE`, `JSON`, `FORM`, `RAW`, and `GRAPHQL`.
 - `follow_redirects` (Boolean)
@@ -327,31 +328,31 @@ Optional:
 - `query_parameters` (Map of String)
 - `skip_ssl` (Boolean)
 
-<a id="nestedblock--request--assertion"></a>
+<a id="nestedatt--request--assertion"></a>
 ### Nested Schema for `request.assertion`
 
 Required:
 
 - `comparison` (String) The type of comparison to be executed between expected and actual value of the assertion. Possible values `EQUALS`, `NOT_EQUALS`, `HAS_KEY`, `NOT_HAS_KEY`, `HAS_VALUE`, `NOT_HAS_VALUE`, `IS_EMPTY`, `NOT_EMPTY`, `GREATER_THAN`, `LESS_THAN`, `CONTAINS`, `NOT_CONTAINS`, `IS_NULL`, and `NOT_NULL`.
 - `source` (String) The source of the asserted value. Possible values `STATUS_CODE`, `JSON_BODY`, `HEADERS`, `TEXT_BODY`, and `RESPONSE_TIME`.
+- `target` (String)
 
 Optional:
 
 - `property` (String)
-- `target` (String)
 
 
-<a id="nestedblock--request--basic_auth"></a>
+<a id="nestedatt--request--basic_auth"></a>
 ### Nested Schema for `request.basic_auth`
 
 Required:
 
-- `password` (String)
+- `password` (String, Sensitive)
 - `username` (String)
 
 
 
-<a id="nestedblock--retry_strategy"></a>
+<a id="nestedatt--retry_strategy"></a>
 ### Nested Schema for `retry_strategy`
 
 Required:
diff --git a/docs/resources/check_group.md b/docs/resources/check_group.md
index 9fc618b..5a1fa31 100644
--- a/docs/resources/check_group.md
+++ b/docs/resources/check_group.md
@@ -3,12 +3,12 @@
 page_title: "checkly_check_group Resource - terraform-provider-checkly"
 subcategory: ""
 description: |-
-  Check groups allow  you to group together a set of related checks, which can also share default settings for various attributes.
+  Check groups allow you to group together a set of related checks, which can also share default settings for various attributes.
 ---
 
 # checkly_check_group (Resource)
 
-Check groups allow  you to group together a set of related checks, which can also share default settings for various attributes.
+Check groups allow you to group together a set of related checks, which can also share default settings for various attributes.
 
 ## Example Usage
 
@@ -25,7 +25,7 @@ resource "checkly_check_group" "test_group1" {
     "eu-west-1",
   ]
   concurrency = 3
-  api_check_defaults {
+  api_check_defaults = {
     url = "http://example.com/"
     headers = {
       X-Test = "foo"
@@ -35,48 +35,49 @@ resource "checkly_check_group" "test_group1" {
       query = "foo"
     }
 
-    assertion {
+    assertion = {
       source     = "STATUS_CODE"
       property   = ""
       comparison = "EQUALS"
       target     = "200"
     }
 
-    assertion {
+    assertion = {
       source     = "TEXT_BODY"
       property   = ""
       comparison = "CONTAINS"
       target     = "welcome"
     }
 
-    basic_auth {
+    basic_auth = {
       username = "user"
       password = "pass"
     }
   }
 
-  environment_variable {
-    key    = "TEST_ENV_VAR"
-    value  = "Hello world"
-    locked = false
-  }
-
-  environment_variable {
-    key    = "ADDITIONAL_ENV_VAR"
-    value  = "test value"
-    locked = true
-  }
+  environment_variables = [
+    {
+      key    = "TEST_ENV_VAR"
+      value  = "Hello world"
+      locked = false
+    },
+    {
+      key    = "ADDITIONAL_ENV_VAR"
+      value  = "test value"
+      locked = true
+    }
+  ]
 
   use_global_alert_settings = false
 
-  alert_settings {
+  alert_settings = {
     escalation_type = "RUN_BASED"
 
-    run_based_escalation {
+    run_based_escalation = {
       failed_run_threshold = 1
     }
 
-    reminders {
+    reminders = {
       amount   = 2
       interval = 5
     }
@@ -96,7 +97,7 @@ resource "checkly_check" "test_check1" {
     "us-west-1"
   ]
 
-  request {
+  request = {
     url = "https://api.example.com/"
   }
   group_id    = checkly_check_group.test_group1.id
@@ -106,13 +107,13 @@ resource "checkly_check" "test_check1" {
 
 # Using with alert channels
 resource "checkly_alert_channel" "email_ac1" {
-  email {
+  email = {
     address = "info@example.com"
   }
 }
 
 resource "checkly_alert_channel" "email_ac2" {
-  email {
+  email = {
     address = "info2@example.com"
   }
 }
@@ -122,15 +123,16 @@ resource "checkly_alert_channel" "email_ac2" {
 resource "checkly_check_group" "test_group1" {
   name = "My test group 1"
 
-  alert_channel_subscription {
-    channel_id = checkly_alert_channel.email_ac1.id
-    activated  = true
-  }
-
-  alert_channel_subscription {
-    channel_id = checkly_alert_channel.email_ac2.id
-    activated  = true
-  }
+  alert_channel_subscriptions = [
+    {
+      channel_id = checkly_alert_channel.email_ac1.id
+      activated  = true
+    },
+    {
+      channel_id = checkly_alert_channel.email_ac2.id
+      activated  = true
+    }
+  ]
 }
 ```
 
@@ -145,18 +147,18 @@ resource "checkly_check_group" "test_group1" {
 
 ### Optional
 
-- `alert_channel_subscription` (Block List) (see [below for nested schema](#nestedblock--alert_channel_subscription))
-- `alert_settings` (Block List, Max: 1) (see [below for nested schema](#nestedblock--alert_settings))
-- `api_check_defaults` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--api_check_defaults))
+- `alert_channel_subscription` (Attributes List) An array of channel IDs and whether they're activated or not. If you don't set at least one alert subscription for your check, we won't be able to alert you in case something goes wrong with it. (see [below for nested schema](#nestedatt--alert_channel_subscription))
+- `alert_settings` (Attributes) (see [below for nested schema](#nestedatt--alert_settings))
+- `api_check_defaults` (Attributes) (see [below for nested schema](#nestedatt--api_check_defaults))
 - `double_check` (Boolean, Deprecated) Setting this to `true` will trigger a retry when a check fails from the failing region and another, randomly selected region before marking the check as failed.
-- `environment_variable` (Block List) Key/value pairs for setting environment variables during check execution, add locked = true to keep value hidden, add secret = true to create a secret variable. These are only relevant for browser checks. Use global environment variables whenever possible. (see [below for nested schema](#nestedblock--environment_variable))
+- `environment_variable` (Attributes List) Introduce additional environment variables to the check execution environment. Only relevant for browser checks. Prefer global environment variables when possible. (see [below for nested schema](#nestedatt--environment_variable))
 - `environment_variables` (Map of String, Deprecated) Key/value pairs for setting environment variables during check execution. These are only relevant for browser checks. Use global environment variables whenever possible.
 - `local_setup_script` (String) A valid piece of Node.js code to run in the setup phase of an API check in this group.
 - `local_teardown_script` (String) A valid piece of Node.js code to run in the teardown phase of an API check in this group.
 - `locations` (Set of String) An array of one or more data center locations where to run the checks.
 - `muted` (Boolean) Determines if any notifications will be sent out when a check in this group fails and/or recovers.
 - `private_locations` (Set of String) An array of one or more private locations slugs.
-- `retry_strategy` (Block Set, Max: 1) A strategy for retrying failed check runs. (see [below for nested schema](#nestedblock--retry_strategy))
+- `retry_strategy` (Attributes) A strategy for retrying failed check runs. (see [below for nested schema](#nestedatt--retry_strategy))
 - `run_parallel` (Boolean) Determines if the checks in the group should run in all selected locations in parallel or round-robin.
 - `runtime_id` (String) The id of the runtime to use for this group.
 - `setup_snippet_id` (Number) An ID reference to a snippet to use in the setup phase of an API check.
@@ -168,7 +170,7 @@ resource "checkly_check_group" "test_group1" {
 
 - `id` (String) The ID of this resource.
 
-<a id="nestedblock--alert_channel_subscription"></a>
+<a id="nestedatt--alert_channel_subscription"></a>
 ### Nested Schema for `alert_channel_subscription`
 
 Required:
@@ -177,28 +179,28 @@ Required:
 - `channel_id` (Number)
 
 
-<a id="nestedblock--alert_settings"></a>
+<a id="nestedatt--alert_settings"></a>
 ### Nested Schema for `alert_settings`
 
 Optional:
 
 - `escalation_type` (String) Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`.
-- `parallel_run_failure_threshold` (Block List) (see [below for nested schema](#nestedblock--alert_settings--parallel_run_failure_threshold))
-- `reminders` (Block List) (see [below for nested schema](#nestedblock--alert_settings--reminders))
-- `run_based_escalation` (Block List) (see [below for nested schema](#nestedblock--alert_settings--run_based_escalation))
-- `ssl_certificates` (Block Set, Deprecated) (see [below for nested schema](#nestedblock--alert_settings--ssl_certificates))
-- `time_based_escalation` (Block List) (see [below for nested schema](#nestedblock--alert_settings--time_based_escalation))
+- `parallel_run_failure_threshold` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--parallel_run_failure_threshold))
+- `reminders` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--reminders))
+- `run_based_escalation` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--run_based_escalation))
+- `ssl_certificates` (Attributes, Deprecated) At what interval the reminders should be sent. (see [below for nested schema](#nestedatt--alert_settings--ssl_certificates))
+- `time_based_escalation` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--time_based_escalation))
 
-<a id="nestedblock--alert_settings--parallel_run_failure_threshold"></a>
+<a id="nestedatt--alert_settings--parallel_run_failure_threshold"></a>
 ### Nested Schema for `alert_settings.parallel_run_failure_threshold`
 
 Optional:
 
 - `enabled` (Boolean) Applicable only for checks scheduled in parallel in multiple locations.
-- `percentage` (Number) Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `100`, and `100`. (Default `10`).
+- `percentage` (Number) Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `90`, and `100`. (Default `10`).
 
 
-<a id="nestedblock--alert_settings--reminders"></a>
+<a id="nestedatt--alert_settings--reminders"></a>
 ### Nested Schema for `alert_settings.reminders`
 
 Optional:
@@ -207,7 +209,7 @@ Optional:
 - `interval` (Number) Possible values are `5`, `10`, `15`, and `30`. (Default `5`).
 
 
-<a id="nestedblock--alert_settings--run_based_escalation"></a>
+<a id="nestedatt--alert_settings--run_based_escalation"></a>
 ### Nested Schema for `alert_settings.run_based_escalation`
 
 Optional:
@@ -215,16 +217,16 @@ Optional:
 - `failed_run_threshold` (Number) After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`).
 
 
-<a id="nestedblock--alert_settings--ssl_certificates"></a>
+<a id="nestedatt--alert_settings--ssl_certificates"></a>
 ### Nested Schema for `alert_settings.ssl_certificates`
 
 Optional:
 
-- `alert_threshold` (Number) At what moment in time to start alerting on SSL certificates. Possible values `3`, `7`, `14`, `30`. (Default `3`).
-- `enabled` (Boolean) Determines if alert notifications should be sent for expiring SSL certificates.
+- `alert_threshold` (Number) How long before SSL certificate expiry to send alerts. Possible values `3`, `7`, `14`, `30`. (Default `3`).
+- `enabled` (Boolean) Determines if alert notifications should be sent for expiring SSL certificates. Possible values `true`, and `false`. (Default `false`).
 
 
-<a id="nestedblock--alert_settings--time_based_escalation"></a>
+<a id="nestedatt--alert_settings--time_based_escalation"></a>
 ### Nested Schema for `alert_settings.time_based_escalation`
 
 Optional:
@@ -233,7 +235,7 @@ Optional:
 
 
 
-<a id="nestedblock--api_check_defaults"></a>
+<a id="nestedatt--api_check_defaults"></a>
 ### Nested Schema for `api_check_defaults`
 
 Required:
@@ -242,12 +244,12 @@ Required:
 
 Optional:
 
-- `assertion` (Block Set) (see [below for nested schema](#nestedblock--api_check_defaults--assertion))
-- `basic_auth` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--api_check_defaults--basic_auth))
+- `assertion` (Attributes List) (see [below for nested schema](#nestedatt--api_check_defaults--assertion))
+- `basic_auth` (Attributes) Credentials for Basic HTTP authentication. (see [below for nested schema](#nestedatt--api_check_defaults--basic_auth))
 - `headers` (Map of String)
 - `query_parameters` (Map of String)
 
-<a id="nestedblock--api_check_defaults--assertion"></a>
+<a id="nestedatt--api_check_defaults--assertion"></a>
 ### Nested Schema for `api_check_defaults.assertion`
 
 Required:
@@ -261,31 +263,31 @@ Optional:
 - `property` (String)
 
 
-<a id="nestedblock--api_check_defaults--basic_auth"></a>
+<a id="nestedatt--api_check_defaults--basic_auth"></a>
 ### Nested Schema for `api_check_defaults.basic_auth`
 
 Required:
 
-- `password` (String)
+- `password` (String, Sensitive)
 - `username` (String)
 
 
 
-<a id="nestedblock--environment_variable"></a>
+<a id="nestedatt--environment_variable"></a>
 ### Nested Schema for `environment_variable`
 
 Required:
 
-- `key` (String)
-- `value` (String)
+- `key` (String) The name of the environment variable.
+- `value` (String, Sensitive) The value of the environment variable. By default the value is plain text and can be seen by any team member. It will also be present in check results and logs.
 
 Optional:
 
-- `locked` (Boolean)
-- `secret` (Boolean)
+- `locked` (Boolean) Locked environment variables are encrypted at rest and in flight on the Checkly backend and are only decrypted when needed. Their value is hidden by default, but can be accessed by team members with the appropriate permissions.
+- `secret` (Boolean) Secret environment variables are always encrypted and their value is never shown to any user. However, keep in mind that your Terraform state will still contain the value.
 
 
-<a id="nestedblock--retry_strategy"></a>
+<a id="nestedatt--retry_strategy"></a>
 ### Nested Schema for `retry_strategy`
 
 Required:
diff --git a/docs/resources/environment_variable.md b/docs/resources/environment_variable.md
index 4308265..8cba751 100644
--- a/docs/resources/environment_variable.md
+++ b/docs/resources/environment_variable.md
@@ -32,7 +32,7 @@ resource "checkly_environment_variable" "variable_2" {
 ### Required
 
 - `key` (String)
-- `value` (String)
+- `value` (String, Sensitive)
 
 ### Optional
 
diff --git a/docs/resources/heartbeat.md b/docs/resources/heartbeat.md
index 279c19c..b611007 100644
--- a/docs/resources/heartbeat.md
+++ b/docs/resources/heartbeat.md
@@ -16,7 +16,7 @@ Heartbeats allows you to monitor your cron jobs and set up alerting, so you get
 resource "checkly_heartbeat" "example-heartbeat" {
   name      = "Example heartbeat"
   activated = true
-  heartbeat {
+  heartbeat = {
     period      = 7
     period_unit = "days"
     grace       = 1
@@ -32,13 +32,13 @@ resource "checkly_heartbeat" "example-heartbeat" {
 ### Required
 
 - `activated` (Boolean) Determines if the check is running or not. Possible values `true`, and `false`.
-- `heartbeat` (Block Set, Min: 1, Max: 1) (see [below for nested schema](#nestedblock--heartbeat))
+- `heartbeat` (Attributes) (see [below for nested schema](#nestedatt--heartbeat))
 - `name` (String) The name of the check.
 
 ### Optional
 
-- `alert_channel_subscription` (Block List) (see [below for nested schema](#nestedblock--alert_channel_subscription))
-- `alert_settings` (Block List, Max: 1) (see [below for nested schema](#nestedblock--alert_settings))
+- `alert_channel_subscription` (Attributes List) An array of channel IDs and whether they're activated or not. If you don't set at least one alert subscription for your check, we won't be able to alert you in case something goes wrong with it. (see [below for nested schema](#nestedatt--alert_channel_subscription))
+- `alert_settings` (Attributes) (see [below for nested schema](#nestedatt--alert_settings))
 - `muted` (Boolean) Determines if any notifications will be sent out when a check fails/degrades/recovers.
 - `tags` (Set of String) A list of tags for organizing and filtering checks.
 - `use_global_alert_settings` (Boolean) When true, the account level alert settings will be used, not the alert setting defined on this check.
@@ -47,7 +47,7 @@ resource "checkly_heartbeat" "example-heartbeat" {
 
 - `id` (String) The ID of this resource.
 
-<a id="nestedblock--heartbeat"></a>
+<a id="nestedatt--heartbeat"></a>
 ### Nested Schema for `heartbeat`
 
 Required:
@@ -57,12 +57,12 @@ Required:
 - `period` (Number) How often you expect a ping to the ping URL.
 - `period_unit` (String) Possible values `seconds`, `minutes`, `hours` and `days`.
 
-Optional:
+Read-Only:
 
 - `ping_token` (String) Custom token to generate your ping URL. Checkly will expect a ping to `https://ping.checklyhq.com/[PING_TOKEN]`.
 
 
-<a id="nestedblock--alert_channel_subscription"></a>
+<a id="nestedatt--alert_channel_subscription"></a>
 ### Nested Schema for `alert_channel_subscription`
 
 Required:
@@ -71,28 +71,28 @@ Required:
 - `channel_id` (Number)
 
 
-<a id="nestedblock--alert_settings"></a>
+<a id="nestedatt--alert_settings"></a>
 ### Nested Schema for `alert_settings`
 
 Optional:
 
 - `escalation_type` (String) Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`.
-- `parallel_run_failure_threshold` (Block List) (see [below for nested schema](#nestedblock--alert_settings--parallel_run_failure_threshold))
-- `reminders` (Block List) (see [below for nested schema](#nestedblock--alert_settings--reminders))
-- `run_based_escalation` (Block List) (see [below for nested schema](#nestedblock--alert_settings--run_based_escalation))
-- `ssl_certificates` (Block Set, Deprecated) (see [below for nested schema](#nestedblock--alert_settings--ssl_certificates))
-- `time_based_escalation` (Block List) (see [below for nested schema](#nestedblock--alert_settings--time_based_escalation))
+- `parallel_run_failure_threshold` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--parallel_run_failure_threshold))
+- `reminders` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--reminders))
+- `run_based_escalation` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--run_based_escalation))
+- `ssl_certificates` (Attributes, Deprecated) At what interval the reminders should be sent. (see [below for nested schema](#nestedatt--alert_settings--ssl_certificates))
+- `time_based_escalation` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--time_based_escalation))
 
-<a id="nestedblock--alert_settings--parallel_run_failure_threshold"></a>
+<a id="nestedatt--alert_settings--parallel_run_failure_threshold"></a>
 ### Nested Schema for `alert_settings.parallel_run_failure_threshold`
 
 Optional:
 
 - `enabled` (Boolean) Applicable only for checks scheduled in parallel in multiple locations.
-- `percentage` (Number) Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `100`, and `100`. (Default `10`).
+- `percentage` (Number) Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `90`, and `100`. (Default `10`).
 
 
-<a id="nestedblock--alert_settings--reminders"></a>
+<a id="nestedatt--alert_settings--reminders"></a>
 ### Nested Schema for `alert_settings.reminders`
 
 Optional:
@@ -101,7 +101,7 @@ Optional:
 - `interval` (Number) Possible values are `5`, `10`, `15`, and `30`. (Default `5`).
 
 
-<a id="nestedblock--alert_settings--run_based_escalation"></a>
+<a id="nestedatt--alert_settings--run_based_escalation"></a>
 ### Nested Schema for `alert_settings.run_based_escalation`
 
 Optional:
@@ -109,7 +109,7 @@ Optional:
 - `failed_run_threshold` (Number) After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`).
 
 
-<a id="nestedblock--alert_settings--ssl_certificates"></a>
+<a id="nestedatt--alert_settings--ssl_certificates"></a>
 ### Nested Schema for `alert_settings.ssl_certificates`
 
 Optional:
@@ -118,7 +118,7 @@ Optional:
 - `enabled` (Boolean) Determines if alert notifications should be sent for expiring SSL certificates. Possible values `true`, and `false`. (Default `false`).
 
 
-<a id="nestedblock--alert_settings--time_based_escalation"></a>
+<a id="nestedatt--alert_settings--time_based_escalation"></a>
 ### Nested Schema for `alert_settings.time_based_escalation`
 
 Optional:
diff --git a/docs/resources/snippet.md b/docs/resources/snippet.md
index d9dbced..2dd64ba 100644
--- a/docs/resources/snippet.md
+++ b/docs/resources/snippet.md
@@ -43,7 +43,7 @@ EOT
 
 ### Required
 
-- `name` (String) The name of the snippet
+- `name` (String) The name of the snippet.
 - `script` (String) Your Node.js code that interacts with the API check lifecycle, or functions as a partial for browser checks.
 
 ### Read-Only
diff --git a/docs/resources/trigger_check.md b/docs/resources/trigger_check.md
index 06134eb..0fbf5eb 100644
--- a/docs/resources/trigger_check.md
+++ b/docs/resources/trigger_check.md
@@ -27,11 +27,11 @@ output "test_trigger_check_url" {
 
 ### Required
 
-- `check_id` (String) The id of the check that you want to attach the trigger to.
+- `check_id` (String) The ID of the check that you want to attach the trigger to.
 
 ### Optional
 
-- `token` (String) The token value created to trigger the check
+- `token` (String) The token value created to trigger the check.
 - `url` (String) The request URL to trigger the check run.
 
 ### Read-Only
diff --git a/docs/resources/trigger_group.md b/docs/resources/trigger_group.md
index 51e0dd0..b51da1a 100644
--- a/docs/resources/trigger_group.md
+++ b/docs/resources/trigger_group.md
@@ -27,11 +27,11 @@ output "test_trigger_group_url" {
 
 ### Required
 
-- `group_id` (Number) The id of the group that you want to attach the trigger to.
+- `group_id` (Number) The ID of the group that you want to attach the trigger to.
 
 ### Optional
 
-- `token` (String) The token value created to trigger the group
+- `token` (String) The token value created to trigger the group.
 - `url` (String) The request URL to trigger the group run.
 
 ### Read-Only
diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf
index 16499e0..05482bc 100644
--- a/examples/provider/provider.tf
+++ b/examples/provider/provider.tf
@@ -31,13 +31,13 @@ resource "checkly_check" "example_check" {
     "us-west-1"
   ]
 
-  request {
+  request = {
     url              = "https://api.example.com/"
     follow_redirects = true
-    assertion {
+    assertions = [{
       source     = "STATUS_CODE"
       comparison = "EQUALS"
       target     = "200"
-    }
+    }]
   }
-}
\ No newline at end of file
+}
diff --git a/examples/resources/checkly_alert_channel/resource.tf b/examples/resources/checkly_alert_channel/resource.tf
index b581b60..05e63d5 100644
--- a/examples/resources/checkly_alert_channel/resource.tf
+++ b/examples/resources/checkly_alert_channel/resource.tf
@@ -1,6 +1,6 @@
 # An Email alert channel
 resource "checkly_alert_channel" "email_ac" {
-  email {
+  email = {
     address = "john@example.com"
   }
   send_recovery        = true
@@ -12,7 +12,7 @@ resource "checkly_alert_channel" "email_ac" {
 
 # A SMS alert channel
 resource "checkly_alert_channel" "sms_ac" {
-  sms {
+  sms = {
     name   = "john"
     number = "+5491100001111"
   }
@@ -22,7 +22,7 @@ resource "checkly_alert_channel" "sms_ac" {
 
 # A Slack alert channel
 resource "checkly_alert_channel" "slack_ac" {
-  slack {
+  slack = {
     channel = "#checkly-notifications"
     url     = "https://hooks.slack.com/services/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"
   }
@@ -30,7 +30,7 @@ resource "checkly_alert_channel" "slack_ac" {
 
 # An Opsgenie alert channel
 resource "checkly_alert_channel" "opsgenie_ac" {
-  opsgenie {
+  opsgenie = {
     name     = "opsalerts"
     api_key  = "fookey"
     region   = "fooregion"
@@ -40,7 +40,7 @@ resource "checkly_alert_channel" "opsgenie_ac" {
 
 # A Pagerduty alert channel
 resource "checkly_alert_channel" "pagerduty_ac" {
-  pagerduty {
+  pagerduty = {
     account      = "checkly"
     service_key  = "key1"
     service_name = "pdalert"
@@ -49,7 +49,7 @@ resource "checkly_alert_channel" "pagerduty_ac" {
 
 # A Webhook alert channel
 resource "checkly_alert_channel" "webhook_ac" {
-  webhook {
+  webhook = {
     name           = "foo"
     method         = "get"
     template       = "footemplate"
@@ -60,7 +60,7 @@ resource "checkly_alert_channel" "webhook_ac" {
 
 # A Firehydran alert channel integration
 resource "checkly_alert_channel" "firehydrant_ac" {
-  webhook {
+  webhook = {
     name         = "firehydrant"
     method       = "post"
     template     = <<EOT
@@ -83,13 +83,14 @@ resource "checkly_alert_channel" "firehydrant_ac" {
 resource "checkly_check" "example_check" {
   name = "Example check"
 
-  alert_channel_subscription {
-    channel_id = checkly_alert_channel.email_ac.id
-    activated  = true
-  }
-
-  alert_channel_subscription {
-    channel_id = checkly_alert_channel.sms_ac.id
-    activated  = true
-  }
-}
\ No newline at end of file
+  alert_channel_subscriptions = [
+    {
+      channel_id = checkly_alert_channel.email_ac.id
+      activated  = true
+    },
+    {
+      channel_id = checkly_alert_channel.sms_ac.id
+      activated  = true
+    }
+  ]
+}
diff --git a/examples/resources/checkly_check/resource.tf b/examples/resources/checkly_check/resource.tf
index a976746..30ae4a4 100644
--- a/examples/resources/checkly_check/resource.tf
+++ b/examples/resources/checkly_check/resource.tf
@@ -11,15 +11,15 @@ resource "checkly_check" "example_check" {
     "us-west-1"
   ]
 
-  request {
+  request = {
     url              = "https://api.example.com/"
     follow_redirects = true
     skip_ssl         = false
-    assertion {
+    assertions = [{
       source     = "STATUS_CODE"
       comparison = "EQUALS"
       target     = "200"
-    }
+    }]
   }
 }
 
@@ -39,19 +39,19 @@ resource "checkly_check" "example_check_2" {
     "ap-south-1",
   ]
 
-  alert_settings {
+  alert_settings = {
     escalation_type = "RUN_BASED"
 
-    run_based_escalation {
+    run_based_escalation = {
       failed_run_threshold = 1
     }
 
-    reminders {
+    reminders = {
       amount = 1
     }
   }
 
-  retry_strategy {
+  retry_strategy = {
     type                 = "FIXED"
     base_backoff_seconds = 60
     max_duration_seconds = 600
@@ -59,7 +59,7 @@ resource "checkly_check" "example_check_2" {
     same_region          = false
   }
 
-  request {
+  request = {
     follow_redirects = true
     skip_ssl         = false
     url              = "http://api.example.com/"
@@ -72,21 +72,21 @@ resource "checkly_check" "example_check_2" {
       X-Bogus = "bogus"
     }
 
-    assertion {
+    assertion = {
       source     = "JSON_BODY"
       property   = "code"
       comparison = "HAS_VALUE"
       target     = "authentication.failed"
     }
 
-    assertion {
+    assertion = {
       source     = "STATUS_CODE"
       property   = ""
       comparison = "EQUALS"
       target     = "401"
     }
 
-    basic_auth {
+    basic_auth = {
       username = ""
       password = ""
     }
@@ -122,13 +122,13 @@ EOT
 
 # Connection checks with alert channels
 resource "checkly_alert_channel" "email_ac1" {
-  email {
+  email = {
     address = "info1@example.com"
   }
 }
 
 resource "checkly_alert_channel" "email_ac2" {
-  email {
+  email = {
     address = "info2@example.com"
   }
 }
@@ -137,15 +137,16 @@ resource "checkly_check" "example_check" {
   name = "Example check"
   # ...
 
-  alert_channel_subscription {
-    channel_id = checkly_alert_channel.email_ac1.id
-    activated  = true
-  }
-
-  alert_channel_subscription {
-    channel_id = checkly_alert_channel.email_ac2.id
-    activated  = true
-  }
+  alert_channel_subscriptions = [
+    {
+      channel_id = checkly_alert_channel.email_ac1.id
+      activated  = true
+    },
+    {
+      channel_id = checkly_alert_channel.email_ac2.id
+      activated  = true
+    }
+  ]
 }
 
 # An alternative syntax for add the script is by referencing an external file
@@ -166,4 +167,4 @@ resource "checkly_check" "example_check" {
 
 #   runtime_id = "2023.02"
 #   script = data.local_file.browser_script.content
-# }
\ No newline at end of file
+# }
diff --git a/examples/resources/checkly_check_group/resource.tf b/examples/resources/checkly_check_group/resource.tf
index d33af9d..2508567 100644
--- a/examples/resources/checkly_check_group/resource.tf
+++ b/examples/resources/checkly_check_group/resource.tf
@@ -10,7 +10,7 @@ resource "checkly_check_group" "test_group1" {
     "eu-west-1",
   ]
   concurrency = 3
-  api_check_defaults {
+  api_check_defaults = {
     url = "http://example.com/"
     headers = {
       X-Test = "foo"
@@ -20,48 +20,49 @@ resource "checkly_check_group" "test_group1" {
       query = "foo"
     }
 
-    assertion {
+    assertion = {
       source     = "STATUS_CODE"
       property   = ""
       comparison = "EQUALS"
       target     = "200"
     }
 
-    assertion {
+    assertion = {
       source     = "TEXT_BODY"
       property   = ""
       comparison = "CONTAINS"
       target     = "welcome"
     }
 
-    basic_auth {
+    basic_auth = {
       username = "user"
       password = "pass"
     }
   }
 
-  environment_variable {
-    key    = "TEST_ENV_VAR"
-    value  = "Hello world"
-    locked = false
-  }
-
-  environment_variable {
-    key    = "ADDITIONAL_ENV_VAR"
-    value  = "test value"
-    locked = true
-  }
+  environment_variables = [
+    {
+      key    = "TEST_ENV_VAR"
+      value  = "Hello world"
+      locked = false
+    },
+    {
+      key    = "ADDITIONAL_ENV_VAR"
+      value  = "test value"
+      locked = true
+    }
+  ]
 
   use_global_alert_settings = false
 
-  alert_settings {
+  alert_settings = {
     escalation_type = "RUN_BASED"
 
-    run_based_escalation {
+    run_based_escalation = {
       failed_run_threshold = 1
     }
 
-    reminders {
+    reminders = {
       amount   = 2
       interval = 5
     }
@@ -81,7 +82,7 @@ resource "checkly_check" "test_check1" {
     "us-west-1"
   ]
 
-  request {
+  request = {
     url = "https://api.example.com/"
   }
   group_id    = checkly_check_group.test_group1.id
@@ -91,13 +92,13 @@ resource "checkly_check" "test_check1" {
 
 # Using with alert channels
 resource "checkly_alert_channel" "email_ac1" {
-  email {
+  email = {
     address = "info@example.com"
   }
 }
 
 resource "checkly_alert_channel" "email_ac2" {
-  email {
+  email = {
     address = "info2@example.com"
   }
 }
@@ -107,14 +108,15 @@ resource "checkly_alert_channel" "email_ac2" {
 resource "checkly_check_group" "test_group1" {
   name = "My test group 1"
 
-  alert_channel_subscription {
-    channel_id = checkly_alert_channel.email_ac1.id
-    activated  = true
-  }
-
-  alert_channel_subscription {
-    channel_id = checkly_alert_channel.email_ac2.id
-    activated  = true
-  }
+  alert_channel_subscriptions = [
+    {
+      channel_id = checkly_alert_channel.email_ac1.id
+      activated  = true
+    },
+    {
+      channel_id = checkly_alert_channel.email_ac2.id
+      activated  = true
+    }
+  ]
 }
 
diff --git a/examples/resources/checkly_heartbeat/resource.tf b/examples/resources/checkly_heartbeat/resource.tf
index 714f617..8ca0c80 100644
--- a/examples/resources/checkly_heartbeat/resource.tf
+++ b/examples/resources/checkly_heartbeat/resource.tf
@@ -1,11 +1,11 @@
 resource "checkly_heartbeat" "example-heartbeat" {
   name      = "Example heartbeat"
   activated = true
-  heartbeat {
+  heartbeat = {
     period      = 7
     period_unit = "days"
     grace       = 1
     grace_unit  = "days"
   }
   use_global_alert_settings = true
-}
\ No newline at end of file
+}
diff --git a/go.mod b/go.mod
index d37322a..4dc47ad 100644
--- a/go.mod
+++ b/go.mod
@@ -1,109 +1,70 @@
 module github.com/checkly/terraform-provider-checkly
 
-go 1.22
+go 1.23.3
+
+require (
+	github.com/hashicorp/terraform-plugin-framework v1.13.0
+	github.com/hashicorp/terraform-plugin-framework-validators v0.15.0
+	github.com/hashicorp/terraform-plugin-go v0.25.0
+	github.com/hashicorp/terraform-plugin-log v0.9.0
+	github.com/hashicorp/terraform-plugin-testing v1.11.0
+)
 
 require (
-	github.com/aws/aws-sdk-go v1.44.122 // indirect
 	github.com/checkly/checkly-go-sdk v1.8.1
-	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
-	github.com/google/go-cmp v0.6.0
-	github.com/gruntwork-io/terratest v0.41.16
-	github.com/hashicorp/terraform-plugin-docs v0.19.4
-	github.com/hashicorp/terraform-plugin-sdk/v2 v2.12.0
+	github.com/google/go-cmp v0.6.0 // indirect
+	github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0 // indirect
 )
 
 require (
-	cloud.google.com/go v0.105.0 // indirect
-	cloud.google.com/go/compute v1.12.1 // indirect
-	cloud.google.com/go/compute/metadata v0.2.1 // indirect
-	cloud.google.com/go/iam v0.7.0 // indirect
-	cloud.google.com/go/storage v1.27.0 // indirect
-	github.com/BurntSushi/toml v1.2.1 // indirect
-	github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect
-	github.com/Masterminds/goutils v1.1.1 // indirect
-	github.com/Masterminds/semver/v3 v3.2.0 // indirect
-	github.com/Masterminds/sprig/v3 v3.2.3 // indirect
 	github.com/ProtonMail/go-crypto v1.1.0-alpha.2 // indirect
 	github.com/agext/levenshtein v1.2.3 // indirect
-	github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
 	github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
-	github.com/armon/go-radix v1.0.0 // indirect
-	github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
-	github.com/bgentry/speakeasy v0.1.0 // indirect
-	github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
 	github.com/cloudflare/circl v1.3.7 // indirect
-	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/fatih/color v1.16.0 // indirect
-	github.com/golang/protobuf v1.5.2 // indirect
-	github.com/google/uuid v1.3.0 // indirect
-	github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
-	github.com/googleapis/gax-go/v2 v2.7.0 // indirect
-	github.com/hashicorp/cli v1.1.6 // indirect
+	github.com/go-test/deep v1.0.7 // indirect
+	github.com/golang/protobuf v1.5.4 // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
 	github.com/hashicorp/go-checkpoint v0.5.0 // indirect
 	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
 	github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
-	github.com/hashicorp/go-getter v1.7.1 // indirect
-	github.com/hashicorp/go-hclog v1.2.0 // indirect
+	github.com/hashicorp/go-hclog v1.6.3 // indirect
 	github.com/hashicorp/go-multierror v1.1.1 // indirect
-	github.com/hashicorp/go-plugin v1.4.3 // indirect
-	github.com/hashicorp/go-safetemp v1.0.0 // indirect
+	github.com/hashicorp/go-plugin v1.6.2 // indirect
+	github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
 	github.com/hashicorp/go-uuid v1.0.3 // indirect
 	github.com/hashicorp/go-version v1.7.0 // indirect
-	github.com/hashicorp/hc-install v0.7.0 // indirect
-	github.com/hashicorp/hcl/v2 v2.11.1 // indirect
+	github.com/hashicorp/hc-install v0.9.0 // indirect
+	github.com/hashicorp/hcl/v2 v2.23.0 // indirect
 	github.com/hashicorp/logutils v1.0.0 // indirect
 	github.com/hashicorp/terraform-exec v0.21.0 // indirect
-	github.com/hashicorp/terraform-json v0.22.1 // indirect
-	github.com/hashicorp/terraform-plugin-go v0.8.0 // indirect
-	github.com/hashicorp/terraform-plugin-log v0.3.0 // indirect
-	github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896 // indirect
-	github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect
-	github.com/hashicorp/yamux v0.0.0-20190923154419-df201c70410d // indirect
-	github.com/huandu/xstrings v1.3.3 // indirect
-	github.com/imdario/mergo v0.3.15 // indirect
-	github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect
-	github.com/jmespath/go-jmespath v0.4.0 // indirect
-	github.com/klauspost/compress v1.15.11 // indirect
+	github.com/hashicorp/terraform-json v0.23.0 // indirect
+	github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
+	github.com/hashicorp/terraform-svchost v0.1.1 // indirect
+	github.com/hashicorp/yamux v0.1.1 // indirect
+	github.com/kr/pretty v0.3.0 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
-	github.com/mattn/go-runewidth v0.0.9 // indirect
-	github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect
 	github.com/mitchellh/copystructure v1.2.0 // indirect
-	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/go-testing-interface v1.14.1 // indirect
 	github.com/mitchellh/go-wordwrap v1.0.1 // indirect
-	github.com/mitchellh/mapstructure v1.4.3 // indirect
+	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/mitchellh/reflectwalk v1.0.2 // indirect
 	github.com/oklog/run v1.1.0 // indirect
-	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/posener/complete v1.2.3 // indirect
-	github.com/shopspring/decimal v1.3.1 // indirect
-	github.com/spf13/cast v1.5.0 // indirect
-	github.com/stretchr/testify v1.8.2 // indirect
-	github.com/tmccombs/hcl2json v0.3.3 // indirect
-	github.com/ulikunitz/xz v0.5.10 // indirect
+	github.com/rogpeppe/go-internal v1.12.0 // indirect
 	github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
-	github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect
-	github.com/vmihailenco/tagparser v0.1.1 // indirect
-	github.com/yuin/goldmark v1.7.1 // indirect
-	github.com/yuin/goldmark-meta v1.1.0 // indirect
-	github.com/zclconf/go-cty v1.14.4 // indirect
-	go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect
-	go.opencensus.io v0.24.0 // indirect
-	golang.org/x/crypto v0.21.0 // indirect
-	golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
-	golang.org/x/mod v0.17.0 // indirect
-	golang.org/x/net v0.23.0 // indirect
-	golang.org/x/oauth2 v0.1.0 // indirect
-	golang.org/x/sys v0.18.0 // indirect
-	golang.org/x/text v0.15.0 // indirect
-	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
-	google.golang.org/api v0.103.0 // indirect
-	google.golang.org/appengine v1.6.7 // indirect
+	github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
+	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
+	github.com/zclconf/go-cty v1.15.0 // indirect
+	golang.org/x/crypto v0.29.0 // indirect
+	golang.org/x/mod v0.21.0 // indirect
+	golang.org/x/net v0.28.0 // indirect
+	golang.org/x/sync v0.9.0 // indirect
+	golang.org/x/sys v0.27.0 // indirect
+	golang.org/x/text v0.20.0 // indirect
+	golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
+	google.golang.org/appengine v1.6.8 // indirect
 	google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c // indirect
-	google.golang.org/grpc v1.51.0 // indirect
-	google.golang.org/protobuf v1.28.1 // indirect
-	gopkg.in/yaml.v2 v2.4.0 // indirect
-	gopkg.in/yaml.v3 v3.0.1 // indirect
+	google.golang.org/grpc v1.67.1 // indirect
+	google.golang.org/protobuf v1.35.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 81364d0..d7f2401 100644
--- a/go.sum
+++ b/go.sum
@@ -1,1193 +1,228 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
-cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
-cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
-cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
-cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
-cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
-cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
-cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
-cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
-cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
-cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
-cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
-cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
-cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
-cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
-cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
-cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
-cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
-cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
-cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
-cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
-cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
-cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
-cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
-cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
-cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
-cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
-cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y=
-cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM=
-cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
-cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=
-cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
-cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=
-cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4=
-cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0=
-cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ=
-cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk=
-cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o=
-cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s=
-cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0=
-cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY=
-cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw=
-cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI=
-cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=
-cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=
-cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
-cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
-cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
-cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
-cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
-cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA=
-cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=
-cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=
-cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM=
-cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI=
-cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY=
-cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI=
-cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
-cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
-cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
-cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
-cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
-cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
-cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=
-cloud.google.com/go/compute v1.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0=
-cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
-cloud.google.com/go/compute/metadata v0.2.1 h1:efOwf5ymceDhK6PKMnnrTHP4pppY5L22mle96M1yP48=
-cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
-cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=
-cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4=
-cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0=
-cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs=
-cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc=
-cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM=
-cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ=
-cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo=
-cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE=
-cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I=
-cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ=
-cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo=
-cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA=
-cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
-cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
-cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo=
-cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ=
-cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4=
-cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0=
-cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8=
-cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU=
-cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU=
-cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y=
-cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg=
-cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk=
-cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w=
-cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk=
-cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg=
-cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM=
-cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA=
-cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o=
-cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A=
-cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0=
-cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0=
-cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=
-cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
-cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=
-cloud.google.com/go/iam v0.7.0 h1:k4MuwOsS7zGJJ+QfZ5vBK8SgHBAvYN/23BWsiihJ1vs=
-cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg=
-cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=
-cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=
-cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8=
-cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08=
-cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs=
-cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc=
-cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4=
-cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w=
-cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE=
-cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM=
-cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY=
-cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s=
-cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=
-cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=
-cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ=
-cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU=
-cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY=
-cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34=
-cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs=
-cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg=
-cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E=
-cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU=
-cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0=
-cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA=
-cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0=
-cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI=
-cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
-cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
-cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
-cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
-cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4=
-cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o=
-cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk=
-cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo=
-cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg=
-cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4=
-cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg=
-cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c=
-cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y=
-cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A=
-cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4=
-cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY=
-cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s=
-cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI=
-cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA=
-cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4=
-cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0=
-cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU=
-cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU=
-cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc=
-cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs=
-cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg=
-cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM=
-cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ=
-cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
-cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
-cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
-cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
-cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
-cloud.google.com/go/storage v1.27.0 h1:YOO045NZI9RKfCj1c5A/ZtuuENUc8OAW+gHdGnDgyMQ=
-cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
-cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
-cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=
-cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU=
-cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4=
-cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0=
-cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo=
-cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo=
-cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE=
-cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
-cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
-cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
 dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
 dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
-dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
-github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/Kunde21/markdownfmt/v3 v3.1.0 h1:KiZu9LKs+wFFBQKhrZJrFZwtLnCCWJahL+S+E/3VnM0=
-github.com/Kunde21/markdownfmt/v3 v3.1.0/go.mod h1:tPXN1RTyOzJwhfHoon9wUr4HGYmWgVxSQN6VBJDkrVc=
-github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
-github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
-github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
-github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
-github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
-github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
-github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
 github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
 github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
 github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg=
 github.com/ProtonMail/go-crypto v1.1.0-alpha.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
-github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
-github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
-github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
 github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
 github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
-github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f/go.mod h1:k8feO4+kXDxro6ErPXBRTJ/ro2mf0SsFG8s7doP9kJE=
-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
-github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
-github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I=
-github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
-github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
 github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
-github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
-github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
 github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
 github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
-github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
-github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
-github.com/aws/aws-sdk-go v1.44.122 h1:p6mw01WBaNpbdP2xrisz5tIkcNwzj/HysobNoaAHjgo=
-github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
-github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
-github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
-github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
-github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
+github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
 github.com/checkly/checkly-go-sdk v1.8.1 h1:s8TAlbruie1lxGVdkqwfimMBKnTrjso26yByJI1uoPI=
 github.com/checkly/checkly-go-sdk v1.8.1/go.mod h1:Pd6tBOggAe41NnCU5KwqA8JvD6J20/IctszT2E0AvHo=
-github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
 github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
-github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
-github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
 github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
 github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
 github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
-github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
-github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
 github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
 github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
-github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
-github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
-github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
-github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
-github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
 github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
 github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
-github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
-github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
 github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
 github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
-github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
 github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
 github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
-github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
-github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
 github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
-github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
-github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ=
-github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
-github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
-github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs=
-github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
-github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
-github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
-github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
-github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
-github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
-github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
-github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
-github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
-github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ=
-github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
-github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/gruntwork-io/terratest v0.41.16 h1:s3ZyyVLWwrZ3KD44VIVHidBZI0Kpr9RkdqY8VEYIEIU=
-github.com/gruntwork-io/terratest v0.41.16/go.mod h1:O6gajNBjO1wvc7Wl9WtbO+ORcdnhAV2GQiBE71ycwIk=
-github.com/hashicorp/cli v1.1.6 h1:CMOV+/LJfL1tXCOKrgAX0uRKnzjj/mpmqNXloRSy2K8=
-github.com/hashicorp/cli v1.1.6/go.mod h1:MPon5QYlgjjo0BSoAiN0ESeT5fRzDjVRp+uioJ0piz4=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
 github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
 github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
 github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
 github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
 github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
 github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI=
 github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs=
-github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY=
-github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
-github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
-github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
-github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
+github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
 github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
 github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
-github.com/hashicorp/go-plugin v1.4.3 h1:DXmvivbWD5qdiBts9TpBC7BYL1Aia5sxbRgQB+v6UZM=
-github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
-github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
-github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
+github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog=
+github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q=
+github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
+github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
 github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
 github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
 github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
 github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
 github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/hc-install v0.3.1/go.mod h1:3LCdWcCDS1gaHC9mhHCGbkYfoY6vdsKohGjugbZdZak=
-github.com/hashicorp/hc-install v0.7.0 h1:Uu9edVqjKQxxuD28mR5TikkKDd/p55S8vzPC1659aBk=
-github.com/hashicorp/hc-install v0.7.0/go.mod h1:ELmmzZlGnEcqoUMKUuykHaPCIR1sYLYX+KSggWSKZuA=
-github.com/hashicorp/hcl/v2 v2.9.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg=
-github.com/hashicorp/hcl/v2 v2.11.1 h1:yTyWcXcm9XB0TEkyU/JCRU6rYy4K+mgLtzn2wlrJbcc=
-github.com/hashicorp/hcl/v2 v2.11.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg=
+github.com/hashicorp/hc-install v0.9.0 h1:2dIk8LcvANwtv3QZLckxcjyF5w8KVtiMxu6G6eLhghE=
+github.com/hashicorp/hc-install v0.9.0/go.mod h1:+6vOP+mf3tuGgMApVYtmsnDoKWMDcFXeTxCACYZ8SFg=
+github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
+github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
 github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
 github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
-github.com/hashicorp/terraform-exec v0.16.0/go.mod h1:wB5JHmjxZ/YVNZuv9npAXKmz5pGyxy8PSi0GRR0+YjA=
 github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ=
 github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg=
-github.com/hashicorp/terraform-json v0.13.0/go.mod h1:y5OdLBCT+rxbwnpxZs9kGL7R9ExU76+cpdY8zHwoazk=
-github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7orfb5Ltvec=
-github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A=
-github.com/hashicorp/terraform-plugin-docs v0.19.4 h1:G3Bgo7J22OMtegIgn8Cd/CaSeyEljqjH3G39w28JK4c=
-github.com/hashicorp/terraform-plugin-docs v0.19.4/go.mod h1:4pLASsatTmRynVzsjEhbXZ6s7xBlUw/2Kt0zfrq8HxA=
-github.com/hashicorp/terraform-plugin-go v0.8.0 h1:MvY43PcDj9VlBjYifBWCO/6j1wf106xU8d5Tob/WRs0=
-github.com/hashicorp/terraform-plugin-go v0.8.0/go.mod h1:E3GuvfX0Pz2Azcl6BegD6t51StXsVZMOYQoGO8mkHM0=
-github.com/hashicorp/terraform-plugin-log v0.3.0 h1:NPENNOjaJSVX0f7JJTl4f/2JKRPQ7S2ZN9B4NSqq5kA=
-github.com/hashicorp/terraform-plugin-log v0.3.0/go.mod h1:EjueSP/HjlyFAsDqt+okpCPjkT4NDynAe32AeDC4vps=
-github.com/hashicorp/terraform-plugin-sdk/v2 v2.12.0 h1:rjJxyLUVA180BG0ZXTOree4x2RVvo2jigdYoT2rw5j0=
-github.com/hashicorp/terraform-plugin-sdk/v2 v2.12.0/go.mod h1:TPjMXvpPNWagHzYOmVPzzRRIBTuaLVukR+esL08tgzg=
-github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896 h1:1FGtlkJw87UsTMg5s8jrekrHmUPUJaMcu6ELiVhQrNw=
-github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896/go.mod h1:bzBPnUIkI0RxauU8Dqo+2KrZZ28Cf48s8V6IHt3p4co=
-github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0=
-github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg=
-github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
-github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
-github.com/hashicorp/yamux v0.0.0-20190923154419-df201c70410d h1:W+SIwDdl3+jXWeidYySAgzytE3piq6GumXeBjFBG67c=
-github.com/hashicorp/yamux v0.0.0-20190923154419-df201c70410d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
-github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
-github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
-github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
+github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2xoR+lppBkI=
+github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c=
+github.com/hashicorp/terraform-plugin-framework v1.13.0 h1:8OTG4+oZUfKgnfTdPTJwZ532Bh2BobF4H+yBiYJ/scw=
+github.com/hashicorp/terraform-plugin-framework v1.13.0/go.mod h1:j64rwMGpgM3NYXTKuxrCnyubQb/4VKldEKlcG8cvmjU=
+github.com/hashicorp/terraform-plugin-framework-validators v0.15.0 h1:RXMmu7JgpFjnI1a5QjMCBb11usrW2OtAG+iOTIj5c9Y=
+github.com/hashicorp/terraform-plugin-framework-validators v0.15.0/go.mod h1:Bh89/hNmqsEWug4/XWKYBwtnw3tbz5BAy1L1OgvbIaY=
+github.com/hashicorp/terraform-plugin-go v0.25.0 h1:oi13cx7xXA6QciMcpcFi/rwA974rdTxjqEhXJjbAyks=
+github.com/hashicorp/terraform-plugin-go v0.25.0/go.mod h1:+SYagMYadJP86Kvn+TGeV+ofr/R3g4/If0O5sO96MVw=
+github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
+github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
+github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0 h1:wyKCCtn6pBBL46c1uIIBNUOWlNfYXfXpVo16iDyLp8Y=
+github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0/go.mod h1:B0Al8NyYVr8Mp/KLwssKXG1RqnTk7FySqSn4fRuLNgw=
+github.com/hashicorp/terraform-plugin-testing v1.11.0 h1:MeDT5W3YHbONJt2aPQyaBsgQeAIckwPX41EUHXEn29A=
+github.com/hashicorp/terraform-plugin-testing v1.11.0/go.mod h1:WNAHQ3DcgV/0J+B15WTE6hDvxcUdkPPpnB1FR3M910U=
+github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
+github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM=
+github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
+github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
+github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
+github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
-github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
-github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
-github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
-github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o=
-github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
-github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
-github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
-github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
-github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
-github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
+github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
 github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
 github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
-github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
 github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
-github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
-github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
-github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
 github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
 github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
-github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 h1:ofNAzWCcyTALn2Zv40+8XitdzCgXY6e9qvXwN9W0YXg=
-github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
-github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
 github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
 github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
-github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
 github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
 github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
-github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
-github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
 github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
 github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
-github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
-github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
 github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758=
-github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs=
-github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
 github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
 github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
 github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
 github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
-github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
-github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
-github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
-github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
 github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
-github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
-github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
-github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/tmccombs/hcl2json v0.3.3 h1:+DLNYqpWE0CsOQiEZu+OZm5ZBImake3wtITYxQ8uLFQ=
-github.com/tmccombs/hcl2json v0.3.3/go.mod h1:Y2chtz2x9bAeRTvSibVRVgbLJhLJXKlUeIvjeVdnm4w=
-github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
-github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
 github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
 github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
-github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U=
-github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
-github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
-github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
-github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
+github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
+github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
+github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
+github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
 github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
 github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
-github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U=
-github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
-github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
-github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
-github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
-github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
-github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
-github.com/zclconf/go-cty v1.8.1/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
-github.com/zclconf/go-cty v1.9.1/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
-github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
-github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
-github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
-github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
-go.abhg.dev/goldmark/frontmatter v0.2.0 h1:P8kPG0YkL12+aYk2yU3xHv4tcXzeVnN+gU0tJ5JnxRw=
-go.abhg.dev/goldmark/frontmatter v0.2.0/go.mod h1:XqrEkZuM57djk7zrlRUB02x8I5J0px76YjkOzhB4YlU=
-go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
-go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
-go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
-go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
-go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ=
+github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
+github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
+github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
-golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
-golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
-golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
-golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
-golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
-golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
-golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
-golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
-golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
-golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
+golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
+golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
-golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
-golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
-golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
-golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
-golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
-golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
-golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
-golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
-golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
-golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
-golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
-golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
-golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
-golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y=
-golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
+golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
+golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
-golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
-golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
+golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
-golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
-golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
-golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
-golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
-golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
-golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
-golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
-google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
-google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
-google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
-google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
-google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
-google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
-google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
-google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
-google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
-google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
-google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
-google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
-google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
-google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
-google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
-google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
-google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
-google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
-google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
-google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
-google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
-google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
-google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
-google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
-google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
-google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
-google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
-google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g=
-google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
-google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
-google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=
-google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
-google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
-google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
-google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70=
-google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ=
-google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
-google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
-google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
-google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
-google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
-google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
-google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
-google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
-google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
-google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
-google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
-google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
-google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
-google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
-google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
-google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
-google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
-google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
-google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
-google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
-google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
-google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
-google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
-google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
-google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
-google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
-google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
-google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
-google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
-google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
-google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
-google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
-google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
-google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
-google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
-google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
-google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE=
-google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
-google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
-google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
-google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
-google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
-google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
-google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
-google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
-google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
-google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
-google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
-google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw=
-google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
-google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
-google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U=
-google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
-google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
-google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
+google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
+google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
 google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c h1:S34D59DS2GWOEwWNt4fYmTcFrtlOgukG2k9WsomZ7tg=
 google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
-google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
-google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
-google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
-google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
-google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
-google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
-google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
-google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
-google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
-google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
-google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
-google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
-google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
-google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
+google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
-google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
+google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
-rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
diff --git a/internal/provider/datasources/attributes/id_attribute.go b/internal/provider/datasources/attributes/id_attribute.go
new file mode 100644
index 0000000..17aab7a
--- /dev/null
+++ b/internal/provider/datasources/attributes/id_attribute.go
@@ -0,0 +1,10 @@
+package attributes
+
+import (
+	"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+)
+
+var IDAttributeSchema = schema.StringAttribute{
+	Computed:    true,
+	Description: "The ID of this data source.",
+}
diff --git a/internal/provider/datasources/static_ips_data_source.go b/internal/provider/datasources/static_ips_data_source.go
new file mode 100644
index 0000000..ea6bdf9
--- /dev/null
+++ b/internal/provider/datasources/static_ips_data_source.go
@@ -0,0 +1,154 @@
+package datasources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/attr"
+	"github.com/hashicorp/terraform-plugin-framework/datasource"
+	"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/datasources/attributes"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+)
+
+var (
+	_ datasource.DataSource              = (*StaticIPsDataSource)(nil)
+	_ datasource.DataSourceWithConfigure = (*StaticIPsDataSource)(nil)
+)
+
+type StaticIPsDataSource struct {
+	client checkly.Client
+}
+
+func NewStaticIPsDataSource() datasource.DataSource {
+	return &StaticIPsDataSource{}
+}
+
+type StaticIPsDataSourceModel struct {
+	ID        types.String `tfsdk:"id"`
+	Addresses types.Set    `tfsdk:"addresses"`
+	Locations types.Set    `tfsdk:"locations"`
+	IPFamily  types.String `tfsdk:"ip_family"`
+}
+
+func (d *StaticIPsDataSource) Metadata(
+	ctx context.Context,
+	req datasource.MetadataRequest,
+	resp *datasource.MetadataResponse,
+) {
+	resp.TypeName = req.ProviderTypeName + "_static_ips"
+}
+
+func (d *StaticIPsDataSource) Schema(
+	ctx context.Context,
+	req datasource.SchemaRequest,
+	resp *datasource.SchemaResponse,
+) {
+	resp.Schema = schema.Schema{
+		Description:         "", // TODO
+		MarkdownDescription: "", // TODO
+		Attributes: map[string]schema.Attribute{
+			"id": attributes.IDAttributeSchema,
+			"addresses": schema.SetAttribute{
+				ElementType: types.StringType,
+				Computed:    true,
+				Description: "Static IP addresses for Checkly's runner infrastructure.",
+			},
+			"locations": schema.SetAttribute{
+				ElementType: types.StringType,
+				Optional:    true,
+				Description: "Specify the locations you want to get static IPs for.",
+			},
+			"ip_family": schema.StringAttribute{
+				Optional: true,
+				Description: "Specify the IP families you want to get static " +
+					"IPs for. Only `IPv6` or `IPv4` are valid options.",
+				Validators: []validator.String{
+					stringvalidator.OneOf("IPv6", "IPv4"),
+				},
+			},
+		},
+	}
+}
+
+func (d *StaticIPsDataSource) Configure(
+	ctx context.Context,
+	req datasource.ConfigureRequest,
+	resp *datasource.ConfigureResponse,
+) {
+	client, diags := interop.ClientFromProviderData(req.ProviderData)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	d.client = client
+}
+
+func (d *StaticIPsDataSource) Read(
+	ctx context.Context,
+	req datasource.ReadRequest,
+	resp *datasource.ReadResponse,
+) {
+	var data StaticIPsDataSourceModel
+
+	resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	staticIPs, err := d.client.GetStaticIPs(ctx)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Reading Checkly Static IPs",
+			fmt.Sprintf("Could not retrieve static IPs, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	var haveLocationFilters bool
+	includeLocation := make(map[string]bool)
+	for _, el := range data.Locations.Elements() {
+		haveLocationFilters = true
+		includeLocation[el.(types.String).ValueString()] = true
+	}
+
+	ipFamilyFilter := data.IPFamily.ValueString()
+
+	only4 := ipFamilyFilter == "IPv4"
+	only6 := ipFamilyFilter == "IPv6"
+
+	var addressValues []attr.Value
+	for _, ip := range staticIPs {
+		switch {
+		case only4 && !ip.Address.Addr().Is4():
+			continue
+		case only6 && !ip.Address.Addr().Is6():
+			continue
+		case haveLocationFilters && !includeLocation[ip.Region]:
+			continue
+		}
+
+		addressValues = append(addressValues, types.StringValue(ip.Address.String()))
+	}
+
+	addresses, diags := types.SetValue(types.StringType, addressValues)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	data.ID = types.StringValue("checkly_static_ips_data_source_id")
+	data.Addresses = addresses
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
diff --git a/internal/provider/datasources/static_ips_data_source_test.go b/internal/provider/datasources/static_ips_data_source_test.go
new file mode 100644
index 0000000..f92361f
--- /dev/null
+++ b/internal/provider/datasources/static_ips_data_source_test.go
@@ -0,0 +1,174 @@
+package datasources_test
+
+import (
+	"regexp"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-framework/providerserver"
+	"github.com/hashicorp/terraform-plugin-go/tfprotov6"
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+
+	"github.com/checkly/terraform-provider-checkly/internal/provider"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/globalregistry"
+)
+
+func protoV6ProviderFactories() map[string]func() (tfprotov6.ProviderServer, error) {
+	return map[string]func() (tfprotov6.ProviderServer, error){
+		"checkly": providerserver.NewProtocol6WithError(provider.New("test", globalregistry.Registry)()),
+	}
+}
+
+func TestAccStaticIPsAll(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `
+					data "checkly_static_ips" "test" {}
+				`,
+				Check: resource.ComposeAggregateTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"data.checkly_static_ips.test",
+						"addresses.#",
+						"162",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccStaticIPsTwoRegionsOnly(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `
+					data "checkly_static_ips" "test" {
+    					locations = ["us-east-1","ap-southeast-1"]
+  					}
+				`,
+				Check: resource.ComposeAggregateTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"data.checkly_static_ips.test",
+						"addresses.#",
+						"20",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccStaticIPsIPv6Only(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `
+					data "checkly_static_ips" "test" {
+						ip_family = "IPv6"
+					}
+				`,
+				Check: resource.ComposeAggregateTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"data.checkly_static_ips.test",
+						"addresses.#",
+						"22",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccStaticIPsIPv4Only(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `
+					data "checkly_static_ips" "test" {
+						ip_family = "IPv4"
+ 					}
+				`,
+				Check: resource.ComposeAggregateTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"data.checkly_static_ips.test",
+						"addresses.#",
+						"140",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccStaticIPsIPv6AndOneRegionOnly(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `
+					data "checkly_static_ips" "test" {
+						ip_family = "IPv6"
+						locations = ["us-east-1"]
+					}
+				`,
+				Check: resource.ComposeAggregateTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"data.checkly_static_ips.test",
+						"addresses.#",
+						"1",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccStaticIPsIPv4AndOneRegionOnly(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `
+					data "checkly_static_ips" "test" {
+						ip_family = "IPv4"
+						locations = ["us-east-1"]
+					}
+				`,
+				Check: resource.ComposeAggregateTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"data.checkly_static_ips.test",
+						"addresses.#",
+						"12",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccStaticIPsInvalidIPFamily(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `
+					data "checkly_static_ips" "test" {
+						ip_family = "invalid"
+					}
+				`,
+				ExpectError: regexp.MustCompile(`Invalid Attribute Value Match`),
+			},
+		},
+	})
+}
diff --git a/internal/provider/globalregistry/registry.go b/internal/provider/globalregistry/registry.go
new file mode 100644
index 0000000..9346e54
--- /dev/null
+++ b/internal/provider/globalregistry/registry.go
@@ -0,0 +1,69 @@
+package globalregistry
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/datasource"
+	"github.com/hashicorp/terraform-plugin-framework/function"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+
+	"github.com/checkly/terraform-provider-checkly/internal/provider"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/datasources"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/resources"
+)
+
+var (
+	_ provider.Registry = (*registry)(nil)
+)
+
+type registry struct {
+	resources   []func() resource.Resource
+	dataSources []func() datasource.DataSource
+	functions   []func() function.Function
+}
+
+func (r *registry) Resources(ctx context.Context) []func() resource.Resource {
+	return r.resources
+}
+
+func (r *registry) DataSources(ctx context.Context) []func() datasource.DataSource {
+	return r.dataSources
+}
+
+func (r *registry) Functions(ctx context.Context) []func() function.Function {
+	return r.functions
+}
+
+func (r *registry) RegisterResource(factory ...func() resource.Resource) {
+	r.resources = append(r.resources, factory...)
+}
+
+func (r *registry) RegisterDataSource(factory ...func() datasource.DataSource) {
+	r.dataSources = append(r.dataSources, factory...)
+}
+
+func (r *registry) RegisterFunction(factory ...func() function.Function) {
+	r.functions = append(r.functions, factory...)
+}
+
+var Registry = new(registry)
+
+func init() {
+	Registry.RegisterResource(
+		resources.NewAlertChannelResource,
+		resources.NewCheckGroupResource,
+		resources.NewCheckResource,
+		resources.NewDashboardResource,
+		resources.NewEnvironmentVariableResource,
+		resources.NewHeartbeatResource,
+		resources.NewMaintenanceWindowsResource,
+		resources.NewPrivateLocationResource,
+		resources.NewSnippetResource,
+		resources.NewTriggerCheckResource,
+		resources.NewTriggerGroupResource,
+	)
+
+	Registry.RegisterDataSource(
+		datasources.NewStaticIPsDataSource,
+	)
+}
diff --git a/internal/provider/interop/convert.go b/internal/provider/interop/convert.go
new file mode 100644
index 0000000..107fdf3
--- /dev/null
+++ b/internal/provider/interop/convert.go
@@ -0,0 +1,453 @@
+package interop
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/attr"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
+)
+
+func AttributeTypes(attributes map[string]schema.Attribute) map[string]attr.Type {
+	result := make(map[string]attr.Type, len(attributes))
+
+	for name, attribute := range attributes {
+		result[name] = attribute.GetType()
+	}
+
+	return result
+}
+
+type Objecter[T any] struct {
+	attrTypes map[string]attr.Type
+}
+
+func ObjecterForSingleNestedAttribute[T any](attribute schema.SingleNestedAttribute) Objecter[T] {
+	return Objecter[T]{
+		attrTypes: AttributeTypes(attribute.Attributes),
+	}
+}
+
+func (o Objecter[T]) ObjectAsValue(ctx context.Context, from types.Object, into *T) diag.Diagnostics {
+	return from.As(ctx, into, basetypes.ObjectAsOptions{
+		UnhandledNullAsEmpty:    true,
+		UnhandledUnknownAsEmpty: true,
+	})
+}
+
+func (o Objecter[T]) ValueToObject(ctx context.Context, from *T) (types.Object, diag.Diagnostics) {
+	return types.ObjectValueFrom(ctx, o.attrTypes, from)
+}
+
+func (o Objecter[T]) UnknownObject() types.Object {
+	return types.ObjectUnknown(o.attrTypes)
+}
+
+func (o Objecter[T]) NullObject() types.Object {
+	return types.ObjectNull(o.attrTypes)
+}
+
+type Lister[T any] struct {
+	elemType attr.Type
+}
+
+func ListerForListNestedAttribute[T any](attribute schema.ListNestedAttribute) Lister[T] {
+	return Lister[T]{
+		elemType: attribute.NestedObject.Type(),
+	}
+}
+
+func (l Lister[T]) ListAsValue(ctx context.Context, from types.List, into *[]T) diag.Diagnostics {
+	if from.IsNull() {
+		return nil
+	}
+
+	return from.ElementsAs(ctx, into, true)
+}
+
+func (l Lister[T]) ValueToList(ctx context.Context, from []T) (types.List, diag.Diagnostics) {
+	return types.ListValueFrom(ctx, l.elemType, from)
+}
+
+func (l Lister[T]) UnknownList() types.List {
+	return types.ListUnknown(l.elemType)
+}
+
+func (l Lister[T]) NullList() types.List {
+	return types.ListNull(l.elemType)
+}
+
+type Setter[T any] struct {
+	elemType attr.Type
+}
+
+func SetterForSetAttribute[T any](attribute schema.SetAttribute) Setter[T] {
+	return Setter[T]{
+		elemType: attribute.ElementType,
+	}
+}
+
+func (l Setter[T]) SetAsValue(ctx context.Context, from types.Set, into *[]T) diag.Diagnostics {
+	if from.IsNull() {
+		return nil
+	}
+
+	return from.ElementsAs(ctx, into, true)
+}
+
+func (l Setter[T]) ValueToSet(ctx context.Context, from []T) (types.Set, diag.Diagnostics) {
+	return types.SetValueFrom(ctx, l.elemType, from)
+}
+
+func (l Setter[T]) UnknownSet() types.Set {
+	return types.SetUnknown(l.elemType)
+}
+
+func (l Setter[T]) NullSet() types.Set {
+	return types.SetNull(l.elemType)
+}
+
+type Refresher[
+	T any,
+	R any,
+	RP interface {
+		Refresh[T]
+		*R
+	},
+] struct {
+	objecter Objecter[R]
+	lister   Lister[R]
+	setter   Setter[R]
+}
+
+func RefresherForSingleNestedAttribute[
+	T any,
+	R any,
+	RP interface {
+		Refresh[T]
+		*R
+	},
+](
+	attribute schema.SingleNestedAttribute,
+) Refresher[T, R, RP] {
+	return Refresher[T, R, RP]{
+		objecter: ObjecterForSingleNestedAttribute[R](attribute),
+	}
+}
+
+func RefresherForListNestedAttribute[
+	T any,
+	R any,
+	RP interface {
+		Refresh[T]
+		*R
+	},
+](
+	attribute schema.ListNestedAttribute,
+) Refresher[T, R, RP] {
+	return Refresher[T, R, RP]{
+		lister: ListerForListNestedAttribute[R](attribute),
+	}
+}
+
+func RefresherForSetAttribute[
+	T any,
+	R any,
+	RP interface {
+		Refresh[T]
+		*R
+	},
+](
+	attribute schema.SetAttribute,
+) Refresher[T, R, RP] {
+	return Refresher[T, R, RP]{
+		setter: SetterForSetAttribute[R](attribute),
+	}
+}
+
+func (r Refresher[T, R, RP]) RefreshToObject(
+	ctx context.Context,
+	source *T,
+	flags RefreshFlags,
+) (
+	object types.Object,
+	value R,
+	diags diag.Diagnostics,
+) {
+	// TODO: Consider making this behavior configurable.
+	if source == nil {
+		object = r.objecter.NullObject()
+		return object, value, diags
+	}
+
+	diags.Append(RP(&value).Refresh(ctx, source, flags)...)
+	if diags.HasError() {
+		return object, value, diags
+	}
+
+	object, diags = r.objecter.ValueToObject(ctx, &value)
+	return object, value, diags
+}
+
+func (r Refresher[T, R, RP]) RefreshToList(
+	ctx context.Context,
+	sources *[]T,
+	flags RefreshFlags,
+) (
+	list types.List,
+	values []R,
+	diags diag.Diagnostics,
+) {
+	// TODO: Consider making this behavior configurable.
+	if sources == nil {
+		list = r.lister.NullList()
+		return list, values, diags
+	}
+
+	values = make([]R, 0, len(*sources))
+
+	for _, source := range *sources {
+		var value R
+
+		diags.Append(RP(&value).Refresh(ctx, &source, flags)...)
+		if diags.HasError() {
+			return list, values, diags
+		}
+
+		values = append(values, value)
+	}
+
+	list, diags = r.lister.ValueToList(ctx, values)
+	return list, values, diags
+}
+
+func (r Refresher[T, R, RP]) RefreshToSet(
+	ctx context.Context,
+	sources *[]T,
+	flags RefreshFlags,
+) (
+	set types.Set,
+	values []R,
+	diags diag.Diagnostics,
+) {
+	// TODO: Consider making this behavior configurable.
+	if sources == nil {
+		set = r.setter.NullSet()
+		return set, values, diags
+	}
+
+	values = make([]R, 0, len(*sources))
+
+	for _, source := range *sources {
+		var value R
+
+		diags.Append(RP(&value).Refresh(ctx, &source, flags)...)
+		if diags.HasError() {
+			return set, values, diags
+		}
+
+		values = append(values, value)
+	}
+
+	set, diags = r.setter.ValueToSet(ctx, values)
+	return set, values, diags
+}
+
+type Renderer[
+	T any,
+	R any,
+	RP interface {
+		Render[T]
+		*R
+	},
+] struct {
+	objecter Objecter[R]
+	lister   Lister[R]
+	setter   Setter[R]
+}
+
+func RendererForSingleNestedAttribute[
+	T any,
+	R any,
+	RP interface {
+		Render[T]
+		*R
+	},
+](
+	attribute schema.SingleNestedAttribute,
+) Renderer[T, R, RP] {
+	return Renderer[T, R, RP]{
+		objecter: ObjecterForSingleNestedAttribute[R](attribute),
+	}
+}
+
+func RendererForListNestedAttribute[
+	T any,
+	R any,
+	RP interface {
+		Render[T]
+		*R
+	},
+](
+	attribute schema.ListNestedAttribute,
+) Renderer[T, R, RP] {
+	return Renderer[T, R, RP]{
+		lister: ListerForListNestedAttribute[R](attribute),
+	}
+}
+
+func RendererForSetAttribute[
+	T any,
+	R any,
+	RP interface {
+		Render[T]
+		*R
+	},
+](
+	attribute schema.SetAttribute,
+) Renderer[T, R, RP] {
+	return Renderer[T, R, RP]{
+		setter: SetterForSetAttribute[R](attribute),
+	}
+}
+
+func (r Renderer[T, R, RP]) RenderFromObject(
+	ctx context.Context,
+	object types.Object,
+) (
+	result T,
+	value R,
+	diags diag.Diagnostics,
+) {
+	diags = r.objecter.ObjectAsValue(ctx, object, &value)
+	if diags.HasError() {
+		return result, value, diags
+	}
+
+	diags.Append(RP(&value).Render(ctx, &result)...)
+	return result, value, diags
+}
+
+func (r Renderer[T, R, RP]) RenderFromList(
+	ctx context.Context,
+	list types.List,
+) (
+	results []T,
+	values []R,
+	diags diag.Diagnostics,
+) {
+	diags = r.lister.ListAsValue(ctx, list, &values)
+	if diags.HasError() {
+		return results, values, diags
+	}
+
+	results = make([]T, 0, len(values))
+
+	for _, value := range values {
+		var result T
+
+		diags.Append(RP(&value).Render(ctx, &result)...)
+		if diags.HasError() {
+			return results, values, diags
+		}
+
+		results = append(results, result)
+	}
+
+	return results, values, diags
+}
+
+func (r Renderer[T, R, RP]) RenderFromSet(
+	ctx context.Context,
+	set types.Set,
+) (
+	results []T,
+	values []R,
+	diags diag.Diagnostics,
+) {
+	diags = r.setter.SetAsValue(ctx, set, &values)
+	if diags.HasError() {
+		return results, values, diags
+	}
+
+	results = make([]T, 0, len(values))
+
+	for _, value := range values {
+		var result T
+
+		diags.Append(RP(&value).Render(ctx, &result)...)
+		if diags.HasError() {
+			return results, values, diags
+		}
+
+		results = append(results, result)
+	}
+
+	return results, values, diags
+}
+
+type Gluer[
+	T any,
+	R any,
+	RP interface {
+		Refresh[T]
+		Render[T]
+		*R
+	},
+] struct {
+	Refresher[T, R, RP]
+	Renderer[T, R, RP]
+}
+
+func GluerForSingleNestedAttribute[
+	T any,
+	R any,
+	RP interface {
+		Refresh[T]
+		Render[T]
+		*R
+	},
+](
+	attribute schema.SingleNestedAttribute,
+) Gluer[T, R, RP] {
+	return Gluer[T, R, RP]{
+		Refresher: RefresherForSingleNestedAttribute[T, R, RP](attribute),
+		Renderer:  RendererForSingleNestedAttribute[T, R, RP](attribute),
+	}
+}
+
+func GluerForListNestedAttribute[
+	T any,
+	R any,
+	RP interface {
+		Refresh[T]
+		Render[T]
+		*R
+	},
+](
+	attribute schema.ListNestedAttribute,
+) Gluer[T, R, RP] {
+	return Gluer[T, R, RP]{
+		Refresher: RefresherForListNestedAttribute[T, R, RP](attribute),
+		Renderer:  RendererForListNestedAttribute[T, R, RP](attribute),
+	}
+}
+
+func GluerForSetAttribute[
+	T any,
+	R any,
+	RP interface {
+		Refresh[T]
+		Render[T]
+		*R
+	},
+](
+	attribute schema.SetAttribute,
+) Gluer[T, R, RP] {
+	return Gluer[T, R, RP]{
+		Refresher: RefresherForSetAttribute[T, R, RP](attribute),
+		Renderer:  RendererForSetAttribute[T, R, RP](attribute),
+	}
+}
diff --git a/internal/provider/interop/data.go b/internal/provider/interop/data.go
new file mode 100644
index 0000000..41aa7ff
--- /dev/null
+++ b/internal/provider/interop/data.go
@@ -0,0 +1,29 @@
+package interop
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+)
+
+func ClientFromProviderData(providerData any) (checkly.Client, diag.Diagnostics) {
+	// Not set when called via ValidateResourceConfig RPC.
+	if providerData == nil {
+		return nil, nil
+	}
+
+	client, ok := providerData.(checkly.Client)
+	if !ok {
+		return nil, diag.Diagnostics{
+			diag.NewErrorDiagnostic(
+				"Unexpected Configure Type",
+				fmt.Sprintf("Expected checkly.Client, got: %T. Please report "+
+					"this issue to the provider developers.", providerData),
+			),
+		}
+	}
+
+	return client, nil
+}
diff --git a/internal/provider/interop/model.go b/internal/provider/interop/model.go
new file mode 100644
index 0000000..40b5b37
--- /dev/null
+++ b/internal/provider/interop/model.go
@@ -0,0 +1,41 @@
+package interop
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+)
+
+type RefreshFlags int
+
+const (
+	Created RefreshFlags = 1 << iota
+	Updated
+
+	Loaded RefreshFlags = 0
+)
+
+func (f RefreshFlags) Contains(other RefreshFlags) bool {
+	return f&other == other
+}
+
+func (f RefreshFlags) Updated() bool {
+	return f.Contains(Updated)
+}
+
+func (f RefreshFlags) Created() bool {
+	return f.Contains(Created)
+}
+
+type Render[T any] interface {
+	Render(ctx context.Context, into *T) diag.Diagnostics
+}
+
+type Refresh[T any] interface {
+	Refresh(ctx context.Context, from *T, flags RefreshFlags) diag.Diagnostics
+}
+
+type Model[T any] interface {
+	Render[T]
+	Refresh[T]
+}
diff --git a/internal/provider/interop/stringset.go b/internal/provider/interop/stringset.go
new file mode 100644
index 0000000..c565817
--- /dev/null
+++ b/internal/provider/interop/stringset.go
@@ -0,0 +1,32 @@
+package interop
+
+import (
+	"github.com/hashicorp/terraform-plugin-framework/attr"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+func IntoUntypedStringSet(slice *[]string) types.Set {
+	if slice == nil {
+		return types.SetNull(types.StringType)
+	}
+
+	var values []attr.Value
+	for _, value := range *slice {
+		values = append(values, types.StringValue(value))
+	}
+
+	return types.SetValueMust(types.StringType, values)
+}
+
+func FromUntypedStringSet(set types.Set) []string {
+	if set.IsNull() {
+		return nil
+	}
+
+	var slice []string
+	for _, el := range set.Elements() {
+		slice = append(slice, el.(types.String).ValueString())
+	}
+
+	return slice
+}
diff --git a/internal/provider/options.go b/internal/provider/options.go
new file mode 100644
index 0000000..b5016b3
--- /dev/null
+++ b/internal/provider/options.go
@@ -0,0 +1,27 @@
+package provider
+
+type Options struct {
+	UseCredentialsFromEnvironment bool
+}
+
+func DefaultOptions() *Options {
+	return &Options{
+		UseCredentialsFromEnvironment: true,
+	}
+}
+
+type Option interface {
+	Apply(opts *Options)
+}
+
+type OptionFunc func(opts *Options)
+
+func (f OptionFunc) Apply(opts *Options) {
+	f(opts)
+}
+
+func WithUseCredentialsFromEnvironment(enabled bool) Option {
+	return OptionFunc(func(opts *Options) {
+		opts.UseCredentialsFromEnvironment = enabled
+	})
+}
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
new file mode 100644
index 0000000..88e805e
--- /dev/null
+++ b/internal/provider/provider.go
@@ -0,0 +1,237 @@
+package provider
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/provider"
+	"github.com/hashicorp/terraform-plugin-framework/provider/schema"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+)
+
+const (
+	defaultAPIURL = "https://api.checklyhq.com"
+)
+
+var (
+	_ provider.Provider              = (*ChecklyProvider)(nil)
+	_ provider.ProviderWithFunctions = (*ChecklyProvider)(nil)
+)
+
+type ChecklyProvider struct {
+	version string
+	options *Options
+	Registry
+}
+
+type ChecklyProviderModel struct {
+	APIKey    types.String `tfsdk:"api_key"`
+	APIURL    types.String `tfsdk:"api_url"`
+	AccountID types.String `tfsdk:"account_id"`
+}
+
+func (p *ChecklyProvider) Metadata(
+	ctx context.Context,
+	req provider.MetadataRequest,
+	resp *provider.MetadataResponse,
+) {
+	resp.TypeName = "checkly"
+	resp.Version = p.version
+}
+
+func (p *ChecklyProvider) Schema(
+	ctx context.Context,
+	req provider.SchemaRequest,
+	resp *provider.SchemaResponse,
+) {
+	resp.Schema = schema.Schema{
+		Attributes: map[string]schema.Attribute{
+			"api_key": schema.StringAttribute{
+				Optional:  true,
+				Sensitive: true, // FIXME: Keep this? Old code did not set it.
+			},
+			"api_url": schema.StringAttribute{
+				Optional: true,
+			},
+			"account_id": schema.StringAttribute{
+				Optional: true,
+			},
+		},
+	}
+}
+
+func (p *ChecklyProvider) Configure(
+	ctx context.Context,
+	req provider.ConfigureRequest,
+	resp *provider.ConfigureResponse,
+) {
+	tflog.Debug(ctx, "Configuring provider")
+
+	var config ChecklyProviderModel
+
+	resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	if config.APIKey.IsUnknown() {
+		resp.Diagnostics.AddAttributeError(
+			path.Root("api_key"),
+			"Unknown Checkly API Key",
+			"The provider cannot create the Checkly API client as there is "+
+				"an unknown configuration value for the Checkly API Key. "+
+				"Either target apply the source of the value first, set the "+
+				"value statically in the configuration, or use the "+
+				"CHECKLY_API_KEY environment variable.",
+		)
+	}
+
+	if config.APIURL.IsUnknown() {
+		resp.Diagnostics.AddAttributeError(
+			path.Root("api_url"),
+			"Unknown Checkly API URL",
+			"The provider cannot create the Checkly API client as there is "+
+				"an unknown configuration value for the Checkly API URL. "+
+				"Either target apply the source of the value first, set the "+
+				"value statically in the configuration, or use the "+
+				"CHECKLY_API_URL environment variable.",
+		)
+	}
+
+	if config.AccountID.IsUnknown() {
+		resp.Diagnostics.AddAttributeError(
+			path.Root("account_id"),
+			"Unknown Checkly Account ID",
+			"The provider cannot create the Checkly API client as there is "+
+				"an unknown configuration value for the Checkly Account ID. "+
+				"Either target apply the source of the value first, set the "+
+				"value statically in the configuration, or use the "+
+				"CHECKLY_API_URL environment variable.",
+		)
+	}
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var apiKey string
+	var apiURL string
+	var accountID string
+
+	if p.options.UseCredentialsFromEnvironment {
+		apiKey = os.Getenv("CHECKLY_API_KEY")
+		apiURL = os.Getenv("CHECKLY_API_URL")
+		accountID = os.Getenv("CHECKLY_ACCOUNT_ID")
+	}
+
+	if !config.APIKey.IsNull() {
+		apiKey = config.APIKey.ValueString()
+	}
+
+	if !config.APIURL.IsNull() {
+		apiURL = config.APIURL.ValueString()
+	}
+
+	if !config.AccountID.IsNull() {
+		accountID = config.AccountID.ValueString()
+	}
+
+	if apiKey == "" {
+		resp.Diagnostics.AddAttributeError(
+			path.Root("api_key"),
+			"Missing Checkly API Key",
+			"The provider cannot create the Checkly API client as there is "+
+				"a missing or empty value for the Checkly API Key. "+
+				"Set the value in the configuration or use the "+
+				"CHECKLY_API_KEY environment variable. If either is already "+
+				"set, ensure the value is not empty.",
+		)
+	}
+
+	if strings.HasPrefix(apiKey, "cu_") && accountID == "" {
+		resp.Diagnostics.AddAttributeError(
+			path.Root("account_id"),
+			"Missing Checkly Account ID",
+			"The provider cannot create the Checkly API client as there is "+
+				"a missing or empty value for the Checkly Account ID, which "+
+				`is required when using User API Keys (keys with "cu_" `+
+				"prefix). Set the value in the configuration or use the "+
+				"CHECKLY_ACCOUNT_ID environment variable. If either is already "+
+				"set, ensure the value is not empty.",
+		)
+	}
+
+	if apiURL == "" {
+		apiURL = defaultAPIURL
+	}
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	ctx = tflog.SetField(ctx, "checkly_api_key", apiKey)
+	ctx = tflog.MaskFieldValuesWithFieldKeys(ctx, "checkly_api_key")
+	ctx = tflog.SetField(ctx, "checkly_api_url", apiURL)
+	ctx = tflog.SetField(ctx, "checkly_account_id", accountID)
+
+	tflog.Debug(ctx, "Creating Checkly client")
+
+	debugLog := os.Getenv("CHECKLY_DEBUG_LOG")
+	var debugOutput io.Writer
+	if debugLog != "" {
+		debugFile, err := os.OpenFile(debugLog, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
+		if err != nil {
+			resp.Diagnostics.AddError(
+				"Error Accessing Checkly Debug Log File",
+				fmt.Sprintf("Could not open debug log file, unexpected error: %s", err),
+			)
+
+			return
+		}
+
+		debugOutput = debugFile
+	}
+
+	client := checkly.NewClient(
+		apiURL,
+		apiKey,
+		nil,
+		debugOutput,
+	)
+
+	if accountID != "" {
+		client.SetAccountId(accountID)
+	}
+
+	apiSource := os.Getenv("CHECKLY_API_SOURCE")
+	if apiSource != "" {
+		client.SetChecklySource(apiSource)
+	} else {
+		client.SetChecklySource("TF")
+	}
+
+	resp.DataSourceData = client
+	resp.ResourceData = client
+}
+
+func New(version string, registry Registry, options ...Option) func() provider.Provider {
+	opts := DefaultOptions()
+	for _, opt := range options {
+		opt.Apply(opts)
+	}
+
+	return func() provider.Provider {
+		return &ChecklyProvider{
+			version:  version,
+			options:  opts,
+			Registry: registry,
+		}
+	}
+}
diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go
new file mode 100644
index 0000000..6084cf1
--- /dev/null
+++ b/internal/provider/provider_test.go
@@ -0,0 +1,62 @@
+package provider_test
+
+import (
+	"regexp"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-framework/providerserver"
+	"github.com/hashicorp/terraform-plugin-go/tfprotov6"
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+
+	"github.com/checkly/terraform-provider-checkly/internal/provider"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/globalregistry"
+)
+
+func protoV6ProviderFactories(options ...provider.Option) map[string]func() (tfprotov6.ProviderServer, error) {
+	return map[string]func() (tfprotov6.ProviderServer, error){
+		"checkly": providerserver.NewProtocol6WithError(provider.New("test", globalregistry.Registry, options...)()),
+	}
+}
+
+func TestProviderConfigMissingAPIKey(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(
+			provider.WithUseCredentialsFromEnvironment(false),
+		),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `
+					provider "checkly" {
+					}
+
+					// Must use the provider or it won't get configured.
+					data "checkly_static_ips" "test" {}
+				`,
+				ExpectError: regexp.MustCompile("Missing Checkly API Key"),
+			},
+		},
+	})
+}
+
+func TestProviderConfigMissingAccountIDWithUserAPIKey(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(
+			provider.WithUseCredentialsFromEnvironment(false),
+		),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `
+					provider "checkly" {
+						api_key = "cu_foo"
+					}
+
+					// Must use the provider or it won't get configured.
+					data "checkly_static_ips" "test" {}
+				`,
+				ExpectError: regexp.MustCompile("Missing Checkly Account ID"),
+			},
+		},
+	})
+}
diff --git a/internal/provider/registry.go b/internal/provider/registry.go
new file mode 100644
index 0000000..a7bd5af
--- /dev/null
+++ b/internal/provider/registry.go
@@ -0,0 +1,15 @@
+package provider
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/datasource"
+	"github.com/hashicorp/terraform-plugin-framework/function"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+)
+
+type Registry interface {
+	Resources(ctx context.Context) []func() resource.Resource
+	DataSources(ctx context.Context) []func() datasource.DataSource
+	Functions(ctx context.Context) []func() function.Function
+}
diff --git a/internal/provider/resources/alert_channel_resource.go b/internal/provider/resources/alert_channel_resource.go
new file mode 100644
index 0000000..fc997eb
--- /dev/null
+++ b/internal/provider/resources/alert_channel_resource.go
@@ -0,0 +1,824 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/int32validator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/resourcevalidator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"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/resource/schema/booldefault"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int32default"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/resources/attributes"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ resource.Resource                     = (*AlertChannelResource)(nil)
+	_ resource.ResourceWithConfigure        = (*AlertChannelResource)(nil)
+	_ resource.ResourceWithImportState      = (*AlertChannelResource)(nil)
+	_ resource.ResourceWithConfigValidators = (*AlertChannelResource)(nil)
+)
+
+type AlertChannelResource struct {
+	client checkly.Client
+}
+
+func NewAlertChannelResource() resource.Resource {
+	return &AlertChannelResource{}
+}
+
+func (r *AlertChannelResource) Metadata(
+	ctx context.Context,
+	req resource.MetadataRequest,
+	resp *resource.MetadataResponse,
+) {
+	resp.TypeName = req.ProviderTypeName + "_alert_channel"
+}
+
+func (r *AlertChannelResource) Schema(
+	ctx context.Context,
+	req resource.SchemaRequest,
+	resp *resource.SchemaResponse,
+) {
+	// TODO: Investigate UpgradeState's potential ability to allow prior
+	// 1-length Sets and Lists to be seamlessly converted to
+	// SingleNestedAttributes.
+	resp.Schema = schema.Schema{
+		Description: "Allows you to define alerting channels for the checks and groups in your account.",
+		Attributes: map[string]schema.Attribute{
+			"id":        attributes.IDAttributeSchema,
+			"email":     EmailAttributeSchema,
+			"slack":     SlackAttributeSchema,
+			"sms":       SMSAttributeSchema,
+			"call":      CallAttributeSchema,
+			"webhook":   WebhookAttributeSchema,
+			"opsgenie":  OpsgenieAttributeSchema,
+			"pagerduty": PagerdutyAttributeSchema,
+			"send_recovery": schema.BoolAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(true),
+				Description: "(Default `true`)",
+			},
+			"send_failure": schema.BoolAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(true),
+				Description: "(Default `true`)",
+			},
+			"send_degraded": schema.BoolAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(false),
+				Description: "(Default `false`)",
+			},
+			"ssl_expiry": schema.BoolAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(false),
+				Description: "(Default `false`)",
+			},
+			"ssl_expiry_threshold": schema.Int32Attribute{
+				Optional: true,
+				Computed: true,
+				Default:  int32default.StaticInt32(30),
+				Validators: []validator.Int32{
+					int32validator.Between(1, 30),
+				},
+				Description: "Value must be between 1 and 30 (Default `30`)",
+			},
+		},
+	}
+}
+
+func (r *AlertChannelResource) ConfigValidators(
+	ctx context.Context,
+) []resource.ConfigValidator {
+	return []resource.ConfigValidator{
+		resourcevalidator.ExactlyOneOf(
+			path.MatchRoot("email"),
+			path.MatchRoot("slack"),
+			path.MatchRoot("sms"),
+			path.MatchRoot("call"),
+			path.MatchRoot("webhook"),
+			path.MatchRoot("opsgenie"),
+			path.MatchRoot("pagerduty"),
+		),
+	}
+}
+
+func (r *AlertChannelResource) Configure(
+	ctx context.Context,
+	req resource.ConfigureRequest,
+	resp *resource.ConfigureResponse,
+) {
+	client, diags := interop.ClientFromProviderData(req.ProviderData)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	r.client = client
+}
+
+func (r *AlertChannelResource) ImportState(
+	ctx context.Context,
+	req resource.ImportStateRequest,
+	resp *resource.ImportStateResponse,
+) {
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *AlertChannelResource) Create(
+	ctx context.Context,
+	req resource.CreateRequest,
+	resp *resource.CreateResponse,
+) {
+	var plan AlertChannelResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.AlertChannel
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.CreateAlertChannel(ctx, desiredModel)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Creating Checkly Alert Channel",
+			fmt.Sprintf("Could not create alert channel, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Created)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *AlertChannelResource) Delete(
+	ctx context.Context,
+	req resource.DeleteRequest,
+	resp *resource.DeleteResponse,
+) {
+	var state AlertChannelResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	id, diags := AlertChannelID.FromString(state.ID)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	err := r.client.DeleteAlertChannel(ctx, id)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Deleting Checkly Alert Channel",
+			fmt.Sprintf("Could not delete alert channel, unexpected error: %s", err),
+		)
+
+		return
+	}
+}
+
+func (r *AlertChannelResource) Read(
+	ctx context.Context,
+	req resource.ReadRequest,
+	resp *resource.ReadResponse,
+) {
+	var state AlertChannelResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	id, diags := AlertChannelID.FromString(state.ID)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	realizedModel, err := r.client.GetAlertChannel(ctx, id)
+	if err != nil {
+		if sdkutil.IsHTTPNotFoundError(err) {
+			resp.State.RemoveResource(ctx)
+			return
+		}
+
+		resp.Diagnostics.AddError(
+			"Error Reading Checkly Alert Channel",
+			fmt.Sprintf("Could not retrieve alert channel, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(state.Refresh(ctx, realizedModel, interop.Loaded)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *AlertChannelResource) Update(
+	ctx context.Context,
+	req resource.UpdateRequest,
+	resp *resource.UpdateResponse,
+) {
+	var plan AlertChannelResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	id, diags := AlertChannelID.FromString(plan.ID)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	var desiredModel checkly.AlertChannel
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.UpdateAlertChannel(
+		ctx,
+		id,
+		desiredModel,
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Updating Checkly Alert Channel",
+			fmt.Sprintf("Could not update alert channel, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Updated)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+var AlertChannelID = sdkutil.Identifier{
+	Path:  path.Root("id"),
+	Title: "Checkly Alert Channel ID",
+}
+
+var (
+	_ interop.Model[checkly.AlertChannel]          = (*AlertChannelResourceModel)(nil)
+	_ interop.Model[checkly.AlertChannelEmail]     = (*EmailAttributeModel)(nil)
+	_ interop.Model[checkly.AlertChannelSlack]     = (*SlackAttributeModel)(nil)
+	_ interop.Model[checkly.AlertChannelSMS]       = (*SMSAttributeModel)(nil)
+	_ interop.Model[checkly.AlertChannelCall]      = (*CallAttributeModel)(nil)
+	_ interop.Model[checkly.AlertChannelWebhook]   = (*WebhookAttributeModel)(nil)
+	_ interop.Model[checkly.AlertChannelOpsgenie]  = (*OpsgenieAttributeModel)(nil)
+	_ interop.Model[checkly.AlertChannelPagerduty] = (*PagerdutyAttributeModel)(nil)
+)
+
+type AlertChannelResourceModel struct {
+	ID                 types.String `tfsdk:"id"`
+	Email              types.Object `tfsdk:"email"`
+	Slack              types.Object `tfsdk:"slack"`
+	SMS                types.Object `tfsdk:"sms"`
+	Call               types.Object `tfsdk:"call"`
+	Webhook            types.Object `tfsdk:"webhook"`
+	Opsgenie           types.Object `tfsdk:"opsgenie"`
+	Pagerduty          types.Object `tfsdk:"pagerduty"`
+	SendRecovery       types.Bool   `tfsdk:"send_recovery"`
+	SendFailure        types.Bool   `tfsdk:"send_failure"`
+	SendDegraded       types.Bool   `tfsdk:"send_degraded"`
+	SSLExpiry          types.Bool   `tfsdk:"ssl_expiry"`
+	SSLExpiryThreshold types.Int32  `tfsdk:"ssl_expiry_threshold"`
+}
+
+func (m *AlertChannelResourceModel) Refresh(ctx context.Context, from *checkly.AlertChannel, flags interop.RefreshFlags) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	if flags.Created() {
+		m.ID = AlertChannelID.IntoString(from.ID)
+	}
+
+	m.Email, _, diags = EmailAttributeGluer.RefreshToObject(ctx, from.Email, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.Slack, _, diags = SlackAttributeGluer.RefreshToObject(ctx, from.Slack, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.SMS, _, diags = SMSAttributeGluer.RefreshToObject(ctx, from.SMS, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.Call, _, diags = CallAttributeGluer.RefreshToObject(ctx, from.CALL, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.Webhook, _, diags = WebhookAttributeGluer.RefreshToObject(ctx, from.Webhook, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.Opsgenie, _, diags = OpsgenieAttributeGluer.RefreshToObject(ctx, from.Opsgenie, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.Pagerduty, _, diags = PagerdutyAttributeGluer.RefreshToObject(ctx, from.Pagerduty, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	if from.SendRecovery != nil {
+		m.SendRecovery = types.BoolValue(*from.SendRecovery)
+	} else {
+		m.SendRecovery = types.BoolNull()
+	}
+
+	if from.SendFailure != nil {
+		m.SendFailure = types.BoolValue(*from.SendFailure)
+	} else {
+		m.SendFailure = types.BoolNull()
+	}
+
+	if from.SendDegraded != nil {
+		m.SendDegraded = types.BoolValue(*from.SendDegraded)
+	} else {
+		m.SendDegraded = types.BoolNull()
+	}
+
+	if from.SSLExpiry != nil {
+		m.SSLExpiry = types.BoolValue(*from.SSLExpiry)
+	} else {
+		m.SSLExpiry = types.BoolNull()
+	}
+
+	if from.SSLExpiryThreshold != nil {
+		m.SSLExpiryThreshold = types.Int32Value(int32(*from.SSLExpiryThreshold))
+	} else {
+		m.SSLExpiryThreshold = types.Int32Null()
+	}
+
+	return nil
+}
+
+func (m *AlertChannelResourceModel) Render(ctx context.Context, into *checkly.AlertChannel) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	into.Email = nil
+	into.Slack = nil
+	into.SMS = nil
+	into.CALL = nil
+	into.Opsgenie = nil
+	into.Webhook = nil
+	into.Pagerduty = nil
+
+	switch {
+	case !m.Email.IsNull():
+		into.Type = checkly.AlertTypeEmail
+		config, _, diags := EmailAttributeGluer.RenderFromObject(ctx, m.Email)
+		if diags.HasError() {
+			return diags
+		}
+		into.Email = &config
+	case !m.Slack.IsNull():
+		into.Type = checkly.AlertTypeSlack
+		config, _, diags := SlackAttributeGluer.RenderFromObject(ctx, m.Slack)
+		if diags.HasError() {
+			return diags
+		}
+		into.Slack = &config
+	case !m.SMS.IsNull():
+		into.Type = checkly.AlertTypeSMS
+		config, _, diags := SMSAttributeGluer.RenderFromObject(ctx, m.SMS)
+		if diags.HasError() {
+			return diags
+		}
+		into.SMS = &config
+	case !m.Call.IsNull():
+		into.Type = checkly.AlertTypeCall
+		config, _, diags := CallAttributeGluer.RenderFromObject(ctx, m.Call)
+		if diags.HasError() {
+			return diags
+		}
+		into.CALL = &config
+	case !m.Webhook.IsNull():
+		into.Type = checkly.AlertTypeWebhook
+		config, _, diags := WebhookAttributeGluer.RenderFromObject(ctx, m.Webhook)
+		if diags.HasError() {
+			return diags
+		}
+		into.Webhook = &config
+	case !m.Opsgenie.IsNull():
+		into.Type = checkly.AlertTypeOpsgenie
+		config, _, diags := OpsgenieAttributeGluer.RenderFromObject(ctx, m.Opsgenie)
+		if diags.HasError() {
+			return diags
+		}
+		into.Opsgenie = &config
+	case !m.Pagerduty.IsNull():
+		into.Type = checkly.AlertTypePagerduty
+		config, _, diags := PagerdutyAttributeGluer.RenderFromObject(ctx, m.Pagerduty)
+		if diags.HasError() {
+			return diags
+		}
+		into.Pagerduty = &config
+	default:
+		// TODO: Use diags instead
+		panic("bug: impossible AlertChannelResourceModel state: no type set")
+	}
+
+	into.SendRecovery = m.SendRecovery.ValueBoolPointer()
+	into.SendFailure = m.SendFailure.ValueBoolPointer()
+	into.SendDegraded = m.SendDegraded.ValueBoolPointer()
+	into.SSLExpiry = m.SSLExpiry.ValueBoolPointer()
+
+	if !m.SSLExpiryThreshold.IsNull() {
+		value := int(m.SSLExpiryThreshold.ValueInt32())
+		into.SSLExpiryThreshold = &value
+	}
+
+	return diags
+}
+
+var EmailAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Attributes: map[string]schema.Attribute{
+		"address": schema.StringAttribute{
+			Required:    true,
+			Description: "The email address of this email alert channel.",
+		},
+	},
+}
+
+type EmailAttributeModel struct {
+	Address types.String `tfsdk:"address"`
+}
+
+var EmailAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.AlertChannelEmail,
+	EmailAttributeModel,
+](EmailAttributeSchema)
+
+func (m *EmailAttributeModel) Refresh(ctx context.Context, from *checkly.AlertChannelEmail, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Address = types.StringValue(from.Address)
+
+	return nil
+}
+
+func (m *EmailAttributeModel) Render(ctx context.Context, into *checkly.AlertChannelEmail) diag.Diagnostics {
+	into.Address = m.Address.ValueString()
+
+	return nil
+}
+
+var SlackAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Attributes: map[string]schema.Attribute{
+		"url": schema.StringAttribute{
+			Required:    true,
+			Description: "The Slack webhook URL",
+		},
+		"channel": schema.StringAttribute{
+			Required:    true,
+			Description: "The name of the alert's Slack channel",
+		},
+	},
+}
+
+type SlackAttributeModel struct {
+	URL     types.String `tfsdk:"url"`
+	Channel types.String `tfsdk:"channel"`
+}
+
+var SlackAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.AlertChannelSlack,
+	SlackAttributeModel,
+](SlackAttributeSchema)
+
+func (m *SlackAttributeModel) Refresh(ctx context.Context, from *checkly.AlertChannelSlack, flags interop.RefreshFlags) diag.Diagnostics {
+	m.URL = types.StringValue(from.WebhookURL)
+	m.Channel = types.StringValue(from.Channel)
+
+	return nil
+}
+
+func (m *SlackAttributeModel) Render(ctx context.Context, into *checkly.AlertChannelSlack) diag.Diagnostics {
+	into.WebhookURL = m.URL.ValueString()
+	into.Channel = m.Channel.ValueString()
+
+	return nil
+}
+
+var SMSAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Attributes: map[string]schema.Attribute{
+		"name": schema.StringAttribute{
+			Required:    true,
+			Description: "The name of this alert channel",
+		},
+		"number": schema.StringAttribute{
+			Required:    true,
+			Description: "The mobile number to receive the alerts",
+		},
+	},
+}
+
+type SMSAttributeModel struct {
+	Name   types.String `tfsdk:"name"`
+	Number types.String `tfsdk:"number"`
+}
+
+var SMSAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.AlertChannelSMS,
+	SMSAttributeModel,
+](SMSAttributeSchema)
+
+func (m *SMSAttributeModel) Refresh(ctx context.Context, from *checkly.AlertChannelSMS, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Name = types.StringValue(from.Name)
+	m.Number = types.StringValue(from.Number)
+
+	return nil
+}
+
+func (m *SMSAttributeModel) Render(ctx context.Context, into *checkly.AlertChannelSMS) diag.Diagnostics {
+	into.Name = m.Name.ValueString()
+	into.Number = m.Number.ValueString()
+
+	return nil
+}
+
+var CallAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Attributes: map[string]schema.Attribute{
+		"name": schema.StringAttribute{
+			Required:    true,
+			Description: "The name of this alert channel",
+		},
+		"number": schema.StringAttribute{
+			Required:    true,
+			Description: "The mobile number to receive the alerts",
+		},
+	},
+}
+
+type CallAttributeModel struct {
+	Name   types.String `tfsdk:"name"`
+	Number types.String `tfsdk:"number"`
+}
+
+var CallAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.AlertChannelCall,
+	CallAttributeModel,
+](CallAttributeSchema)
+
+func (m *CallAttributeModel) Refresh(ctx context.Context, from *checkly.AlertChannelCall, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Name = types.StringValue(from.Name)
+	m.Number = types.StringValue(from.Number)
+
+	return nil
+}
+
+func (m *CallAttributeModel) Render(ctx context.Context, into *checkly.AlertChannelCall) diag.Diagnostics {
+	into.Name = m.Name.ValueString()
+	into.Number = m.Number.ValueString()
+
+	return nil
+}
+
+var WebhookAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Attributes: map[string]schema.Attribute{
+		"name": schema.StringAttribute{
+			Required: true,
+		},
+		"method": schema.StringAttribute{
+			Optional:    true,
+			Computed:    true,
+			Default:     stringdefault.StaticString("POST"),
+			Description: "(Default `POST`)",
+		},
+		"headers": schema.MapAttribute{
+			ElementType: types.StringType,
+			Optional:    true,
+			Computed:    true,
+		},
+		"query_parameters": schema.MapAttribute{
+			ElementType: types.StringType,
+			Optional:    true,
+			Computed:    true,
+		},
+		"template": schema.StringAttribute{
+			Optional: true,
+		},
+		"url": schema.StringAttribute{
+			Required: true,
+		},
+		"webhook_secret": schema.StringAttribute{
+			Optional: true,
+			PlanModifiers: []planmodifier.String{
+				stringplanmodifier.UseStateForUnknown(),
+			},
+		},
+		"webhook_type": schema.StringAttribute{
+			Optional: true,
+			Validators: []validator.String{
+				stringvalidator.OneOf(
+					"WEBHOOK_DISCORD",
+					"WEBHOOK_FIREHYDRANT",
+					"WEBHOOK_GITLAB_ALERT",
+					"WEBHOOK_SPIKESH",
+					"WEBHOOK_SPLUNK",
+					"WEBHOOK_MSTEAMS",
+					"WEBHOOK_TELEGRAM",
+				),
+			},
+			Description: "Type of the webhook. Possible values are 'WEBHOOK_DISCORD', 'WEBHOOK_FIREHYDRANT', 'WEBHOOK_GITLAB_ALERT', 'WEBHOOK_SPIKESH', 'WEBHOOK_SPLUNK', 'WEBHOOK_MSTEAMS' and 'WEBHOOK_TELEGRAM'.",
+		},
+	},
+}
+
+type WebhookAttributeModel struct {
+	Name            types.String `tfsdk:"name"`
+	Method          types.String `tfsdk:"method"`
+	Headers         types.Map    `tfsdk:"headers"`
+	QueryParameters types.Map    `tfsdk:"query_parameters"`
+	Template        types.String `tfsdk:"template"`
+	URL             types.String `tfsdk:"url"`
+	WebhookSecret   types.String `tfsdk:"webhook_secret"`
+	WebhookType     types.String `tfsdk:"webhook_type"`
+}
+
+var WebhookAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.AlertChannelWebhook,
+	WebhookAttributeModel,
+](WebhookAttributeSchema)
+
+func (m *WebhookAttributeModel) Refresh(ctx context.Context, from *checkly.AlertChannelWebhook, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Name = types.StringValue(from.Name)
+	m.Method = types.StringValue(from.Method)
+	m.Headers = sdkutil.KeyValuesIntoMap(&from.Headers)
+	m.QueryParameters = sdkutil.KeyValuesIntoMap(&from.QueryParameters)
+	m.Template = types.StringValue(from.Template)
+	m.URL = types.StringValue(from.URL)
+	// Value is encrypted after creation and cannot be accessed.
+	// m.WebhookSecret = types.StringValue(from.WebhookSecret)
+	m.WebhookType = types.StringValue(from.WebhookType)
+
+	return nil
+}
+
+func (m *WebhookAttributeModel) Render(ctx context.Context, into *checkly.AlertChannelWebhook) diag.Diagnostics {
+	into.Name = m.Name.ValueString()
+	into.Method = m.Method.ValueString()
+	into.Headers = sdkutil.KeyValuesFromMap(m.Headers)
+	into.QueryParameters = sdkutil.KeyValuesFromMap(m.QueryParameters)
+	into.Template = m.Template.ValueString()
+	into.URL = m.URL.ValueString()
+	into.WebhookSecret = m.WebhookSecret.ValueString()
+	into.WebhookType = m.WebhookType.ValueString()
+
+	return nil
+}
+
+var OpsgenieAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Attributes: map[string]schema.Attribute{
+		"name": schema.StringAttribute{
+			Required: true,
+		},
+		"api_key": schema.StringAttribute{
+			Required: true,
+			PlanModifiers: []planmodifier.String{
+				stringplanmodifier.UseStateForUnknown(),
+			},
+		},
+		"region": schema.StringAttribute{
+			Required: true,
+		},
+		"priority": schema.StringAttribute{
+			Required: true,
+		},
+	},
+}
+
+type OpsgenieAttributeModel struct {
+	Name     types.String `tfsdk:"name"`
+	APIKey   types.String `tfsdk:"api_key"`
+	Region   types.String `tfsdk:"region"`
+	Priority types.String `tfsdk:"priority"`
+}
+
+var OpsgenieAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.AlertChannelOpsgenie,
+	OpsgenieAttributeModel,
+](OpsgenieAttributeSchema)
+
+func (m *OpsgenieAttributeModel) Refresh(ctx context.Context, from *checkly.AlertChannelOpsgenie, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Name = types.StringValue(from.Name)
+	// Value is encrypted after creation and cannot be accessed.
+	// m.APIKey = types.StringValue(from.APIKey)
+	m.Region = types.StringValue(from.Region)
+	m.Priority = types.StringValue(from.Priority)
+
+	return nil
+}
+
+func (m *OpsgenieAttributeModel) Render(ctx context.Context, into *checkly.AlertChannelOpsgenie) diag.Diagnostics {
+	into.Name = m.Name.ValueString()
+	into.APIKey = m.APIKey.ValueString()
+	into.Region = m.Region.ValueString()
+	into.Priority = m.Priority.ValueString()
+
+	return nil
+}
+
+var PagerdutyAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Attributes: map[string]schema.Attribute{
+		"service_key": schema.StringAttribute{
+			Required: true,
+		},
+		"service_name": schema.StringAttribute{
+			Optional: true,
+		},
+		"account": schema.StringAttribute{
+			Optional: true,
+		},
+	},
+}
+
+type PagerdutyAttributeModel struct {
+	ServiceKey  types.String `tfsdk:"service_key"`
+	ServiceName types.String `tfsdk:"service_name"`
+	Account     types.String `tfsdk:"account"`
+}
+
+var PagerdutyAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.AlertChannelPagerduty,
+	PagerdutyAttributeModel,
+](PagerdutyAttributeSchema)
+
+func (m *PagerdutyAttributeModel) Refresh(ctx context.Context, from *checkly.AlertChannelPagerduty, flags interop.RefreshFlags) diag.Diagnostics {
+	m.ServiceKey = types.StringValue(from.ServiceKey)
+	m.ServiceName = types.StringValue(from.ServiceName)
+	m.Account = types.StringValue(from.Account)
+
+	return nil
+}
+
+func (m *PagerdutyAttributeModel) Render(ctx context.Context, into *checkly.AlertChannelPagerduty) diag.Diagnostics {
+	into.ServiceKey = m.ServiceKey.ValueString()
+	into.ServiceName = m.ServiceName.ValueString()
+	into.Account = m.Account.ValueString()
+
+	return nil
+}
diff --git a/internal/provider/resources/alert_channel_resource_test.go b/internal/provider/resources/alert_channel_resource_test.go
new file mode 100644
index 0000000..31b6af5
--- /dev/null
+++ b/internal/provider/resources/alert_channel_resource_test.go
@@ -0,0 +1,223 @@
+package resources_test
+
+import (
+	"fmt"
+	"regexp"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccAlertChannelEmail(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "checkly_alert_channel" "t1" {
+				email = {
+					address = "info@example.com"
+				}
+				send_recovery = false
+				send_failure  = false
+				send_degraded = false
+				ssl_expiry    = false
+				ssl_expiry_threshold = 10
+				}`,
+			},
+		},
+	})
+}
+
+func TestAccAlertChannelSlack(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "checkly_alert_channel" "slack_ac" {
+				slack = {
+					channel = "checkly_alerts"
+					url     = "https://hooks.slack.com/services/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"
+				}
+				send_recovery        = true
+				send_failure         = true
+				send_degraded        = false
+				ssl_expiry           = true
+				ssl_expiry_threshold = 11
+			}`,
+			},
+		},
+	})
+}
+
+func TestAccAlertChannelSMS(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "checkly_alert_channel" "sms_ac" {
+				sms = {
+					name   = "smsalerts"
+					number = "4917512345678"
+				}
+			}`,
+			},
+		},
+	})
+}
+
+func TestAccAlertChannelOpsgenie(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "checkly_alert_channel" "opsgenie_ac" {
+				opsgenie = {
+					name     = "opsalert"
+					api_key  = "key1"
+					region   = "EU"
+					priority = "P1"
+				}
+			}`,
+			},
+		},
+	})
+}
+
+func TestAccAlertChannelPagerduty(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "checkly_alert_channel" "pagerduty_ac" {
+				pagerduty = {
+					account      = "checkly"
+					service_key  = "key1"
+					service_name = "pdalert"
+				}
+			}`,
+			},
+		},
+	})
+}
+
+func TestAccAlertChannelWebhook(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "checkly_alert_channel" "webhook_ac" {
+				webhook = {
+				  name   = "webhhookalerts"
+				  method = "get"
+				  headers  = {
+					X-HEADER-1 = "foo"
+				  }
+				  query_parameters = {
+					query1 = "bar"
+				  }
+				  template       = "tmpl"
+				  url            = "https://example.com/webhook"
+				  webhook_secret = "foo-secret"
+				}
+			  }`,
+			},
+		},
+	})
+}
+
+func TestAccAlertChannelFail(t *testing.T) {
+	cases := []struct {
+		Config string
+		Error  string
+	}{
+		{
+			Config: `resource "checkly_alert_channel" "t1" {
+				email = {	}
+			}`,
+			Error: `attribute[\s\S]+"address"[\s\S]+required`,
+		},
+		{
+			Config: `resource "checkly_alert_channel" "t1" {
+				sms = {
+				}
+			}`,
+			Error: `attribute[\s\S]+"number"[\s\S]+required`,
+		},
+		{
+			Config: `resource "checkly_alert_channel" "t1" {
+				slack = {
+				}
+			}`,
+			Error: `attribute[\s\S]+"url"[\s\S]+required`,
+		},
+		{
+			Config: `resource "checkly_alert_channel" "t1" {
+				slack = {
+				}
+			}`,
+			Error: `attribute[\s\S]+"channel"[\s\S]+required`,
+		},
+		{
+			Config: `resource "checkly_alert_channel" "t1" {
+				webhook = {
+				}
+			}`,
+			Error: `attribute[\s\S]+"name"[\s\S]+required`,
+		},
+		{
+			Config: `resource "checkly_alert_channel" "t1" {
+				webhook = {
+				}
+			}`,
+			Error: `attribute[\s\S]+"url"[\s\S]+required`,
+		},
+		{
+			Config: `resource "checkly_alert_channel" "t1" {
+				opsgenie = {
+				}
+			}`,
+			Error: `attribute[\s\S]+"api_key"[\s\S]+required`,
+		},
+		{
+			Config: `resource "checkly_alert_channel" "t1" {
+				opsgenie = {
+				}
+			}`,
+			Error: `attribute[\s\S]+"priority"[\s\S]+required`,
+		},
+		{
+			Config: `resource "checkly_alert_channel" "t1" {
+				opsgenie = {
+				}
+			}`,
+			Error: `attribute[\s\S]+"region"[\s\S]+required`,
+		},
+		{
+			Config: `resource "checkly_alert_channel" "t1" {
+				pagerduty = {
+				}
+			}`,
+			Error: `attribute[\s\S]+"service_key"[\s\S]+required`,
+		},
+	}
+	for key, tc := range cases {
+		t.Run(fmt.Sprintf("%d", key), func(t *testing.T) {
+			resource.UnitTest(t, resource.TestCase{
+				ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+				Steps: []resource.TestStep{
+					{
+						Config:      tc.Config,
+						ExpectError: regexp.MustCompile(tc.Error),
+					},
+				},
+			})
+		})
+	}
+}
diff --git a/internal/provider/resources/attributes/alert_channel_subscription_attribute.go b/internal/provider/resources/attributes/alert_channel_subscription_attribute.go
new file mode 100644
index 0000000..18cc533
--- /dev/null
+++ b/internal/provider/resources/attributes/alert_channel_subscription_attribute.go
@@ -0,0 +1,59 @@
+package attributes
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+)
+
+var (
+	_ interop.Model[checkly.AlertChannelSubscription] = (*AlertChannelSubscriptionAttributeModel)(nil)
+)
+
+var AlertChannelSubscriptionAttributeSchema = schema.ListNestedAttribute{
+	Description: "An array of channel IDs and whether they're activated or " +
+		"not. If you don't set at least one alert subscription for your " +
+		"check, we won't be able to alert you in case something goes wrong " +
+		"with it.",
+	Optional: true,
+	Computed: true,
+	NestedObject: schema.NestedAttributeObject{
+		Attributes: map[string]schema.Attribute{
+			"channel_id": schema.Int64Attribute{
+				Required: true,
+			},
+			"activated": schema.BoolAttribute{
+				Required: true,
+			},
+		},
+	},
+}
+
+type AlertChannelSubscriptionAttributeModel struct {
+	ChannelID types.Int64 `tfsdk:"channel_id"`
+	Activated types.Bool  `tfsdk:"activated"`
+}
+
+var AlertChannelSubscriptionAttributeGluer = interop.GluerForListNestedAttribute[
+	checkly.AlertChannelSubscription,
+	AlertChannelSubscriptionAttributeModel,
+](AlertChannelSubscriptionAttributeSchema)
+
+func (m *AlertChannelSubscriptionAttributeModel) Refresh(ctx context.Context, from *checkly.AlertChannelSubscription, flags interop.RefreshFlags) diag.Diagnostics {
+	m.ChannelID = types.Int64Value(from.ChannelID)
+	m.Activated = types.BoolValue(from.Activated)
+
+	return nil
+}
+
+func (m *AlertChannelSubscriptionAttributeModel) Render(ctx context.Context, into *checkly.AlertChannelSubscription) diag.Diagnostics {
+	into.ChannelID = m.ChannelID.ValueInt64()
+	into.Activated = m.Activated.ValueBool()
+
+	return nil
+}
diff --git a/internal/provider/resources/attributes/alert_settings_attribute.go b/internal/provider/resources/attributes/alert_settings_attribute.go
new file mode 100644
index 0000000..eaf25d3
--- /dev/null
+++ b/internal/provider/resources/attributes/alert_settings_attribute.go
@@ -0,0 +1,396 @@
+package attributes
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/int32validator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/attr"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int32default"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/objectdefault"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+)
+
+func init() {
+	defaultAlertSettings := checkly.AlertSettings{
+		EscalationType: "RUN_BASED",
+		RunBasedEscalation: checkly.RunBasedEscalation{
+			FailedRunThreshold: 5,
+		},
+	}
+
+	defaultAlertSettingsObject, _, diags := AlertSettingsAttributeGluer.RefreshToObject(
+		context.Background(),
+		&defaultAlertSettings,
+		interop.Loaded,
+	)
+	if diags.HasError() {
+		panic(diags)
+	}
+
+	// defaultRunBasedEscalationObject, _, diags := RunBasedEscalationAttributeGluer.RefreshToObject(
+	// 	context.Background(),
+	// 	&defaultAlertSettings.RunBasedEscalation,
+	// 	interop.Loaded,
+	// )
+	// if diags.HasError() {
+	// 	panic(diags)
+	// }
+
+	AlertSettingsAttributeSchema.Default = objectdefault.StaticValue(defaultAlertSettingsObject)
+	// RunBasedEscalationAttributeSchema.Default = objectdefault.StaticValue(defaultRunBasedEscalationObject)
+}
+
+var RunBasedEscalationAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Computed: true,
+	Attributes: map[string]schema.Attribute{
+		"failed_run_threshold": schema.Int32Attribute{
+			Description: "After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`).",
+			Optional:    true,
+			Computed:    true,
+			Default:     int32default.StaticInt32(1),
+			Validators: []validator.Int32{
+				int32validator.Between(1, 5),
+			},
+		},
+	},
+	Default: objectdefault.StaticValue(
+		types.ObjectValueMust(
+			map[string]attr.Type{
+				"failed_run_threshold": types.Int32Type,
+			},
+			map[string]attr.Value{
+				"failed_run_threshold": types.Int32Value(3),
+			},
+		),
+	),
+}
+
+var TimeBasedEscalationAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Computed: true,
+	Attributes: map[string]schema.Attribute{
+		"minutes_failing_threshold": schema.Int32Attribute{
+			Description: "After how many minutes after a check starts failing an alert should be sent. Possible values are `5`, `10`, `15`, and `30`. (Default `5`).",
+			Optional:    true,
+			Computed:    true,
+			Default:     int32default.StaticInt32(5),
+			Validators: []validator.Int32{
+				int32validator.OneOf(5, 10, 15, 30),
+			},
+		},
+	},
+}
+
+var RemindersAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Computed: true,
+	Attributes: map[string]schema.Attribute{
+		"amount": schema.Int32Attribute{
+			Description: "How many reminders to send out after the initial alert notification. Possible values are `0`, `1`, `2`, `3`, `4`, `5`, and `100000`",
+			Optional:    true,
+			Validators: []validator.Int32{
+				int32validator.OneOf(0, 1, 2, 3, 4, 5, 100000),
+			},
+		},
+		"interval": schema.Int32Attribute{
+			Description: "Possible values are `5`, `10`, `15`, and `30`. (Default `5`).",
+			Optional:    true,
+			Computed:    true,
+			Default:     int32default.StaticInt32(5),
+			Validators: []validator.Int32{
+				int32validator.OneOf(5, 10, 15, 30),
+			},
+		},
+	},
+}
+
+var ParallelRunFailureThresholdAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Computed: true,
+	Attributes: map[string]schema.Attribute{
+		"enabled": schema.BoolAttribute{
+			Description: "Applicable only for checks scheduled in parallel in multiple locations.",
+			Optional:    true,
+			Computed:    true,
+			Default:     booldefault.StaticBool(false),
+		},
+		"percentage": schema.Int32Attribute{
+			Description: "Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `90`, and `100`. (Default `10`).",
+			Optional:    true,
+			Computed:    true,
+			Default:     int32default.StaticInt32(10),
+			Validators: []validator.Int32{
+				int32validator.OneOf(10, 20, 30, 40, 50, 60, 70, 80, 90, 100),
+			},
+		},
+	},
+}
+
+var SSLCertificatesAttributeSchema = schema.SingleNestedAttribute{
+	Description:        "At what interval the reminders should be sent.",
+	Optional:           true,
+	DeprecationMessage: "This property is deprecated and it's ignored by the Checkly Public API. It will be removed in a future version.",
+	Attributes: map[string]schema.Attribute{
+		"enabled": schema.BoolAttribute{
+			Description: "Determines if alert notifications should be sent for expiring SSL certificates. Possible values `true`, and `false`. (Default `false`).",
+			Optional:    true,
+			Computed:    true,
+			Default:     booldefault.StaticBool(false),
+		},
+		"alert_threshold": schema.Int32Attribute{
+			Description: "How long before SSL certificate expiry to send alerts. Possible values `3`, `7`, `14`, `30`. (Default `3`).",
+			Optional:    true,
+			Computed:    true,
+			Default:     int32default.StaticInt32(3),
+			Validators: []validator.Int32{
+				int32validator.OneOf(3, 7, 14, 30),
+			},
+		},
+	},
+}
+
+var AlertSettingsAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Computed: true,
+	Attributes: map[string]schema.Attribute{
+		"escalation_type": schema.StringAttribute{
+			Optional: true,
+			Computed: true,
+			Default:  stringdefault.StaticString("RUN_BASED"),
+			Validators: []validator.String{
+				stringvalidator.OneOf("RUN_BASED", "TIME_BASED"),
+			},
+			Description: "Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`.",
+		},
+		"run_based_escalation":           RunBasedEscalationAttributeSchema,
+		"time_based_escalation":          TimeBasedEscalationAttributeSchema,
+		"reminders":                      RemindersAttributeSchema,
+		"parallel_run_failure_threshold": ParallelRunFailureThresholdAttributeSchema,
+		"ssl_certificates":               SSLCertificatesAttributeSchema,
+	},
+}
+
+type AlertSettingsAttributeModel struct {
+	EscalationType              types.String `tfsdk:"escalation_type"`
+	RunBasedEscalation          types.Object `tfsdk:"run_based_escalation"`
+	TimeBasedEscalation         types.Object `tfsdk:"time_based_escalation"`
+	Reminders                   types.Object `tfsdk:"reminders"`
+	ParallelRunFailureThreshold types.Object `tfsdk:"parallel_run_failure_threshold"`
+	SSLCertificates             types.Object `tfsdk:"ssl_certificates"`
+}
+
+var AlertSettingsAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.AlertSettings,
+	AlertSettingsAttributeModel,
+](AlertSettingsAttributeSchema)
+
+func (m *AlertSettingsAttributeModel) Refresh(ctx context.Context, from *checkly.AlertSettings, flags interop.RefreshFlags) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	m.EscalationType = types.StringValue(from.EscalationType)
+
+	runBasedEscalation := &from.RunBasedEscalation
+	timeBasedEscalation := &from.TimeBasedEscalation
+
+	// switch from.EscalationType {
+	// case checkly.RunBased:
+	// 	timeBasedEscalation = nil
+	// case checkly.TimeBased:
+	// 	runBasedEscalation = nil
+	// }
+
+	m.RunBasedEscalation, _, diags = RunBasedEscalationAttributeGluer.RefreshToObject(ctx, runBasedEscalation, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.TimeBasedEscalation, _, diags = TimeBasedEscalationAttributeGluer.RefreshToObject(ctx, timeBasedEscalation, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.Reminders, _, diags = RemindersAttributeGluer.RefreshToObject(ctx, &from.Reminders, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.ParallelRunFailureThreshold, _, diags = ParallelRunFailureThresholdAttributeGluer.RefreshToObject(ctx, &from.ParallelRunFailureThreshold, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	sslCertificates := &from.SSLCertificates
+	if !sslCertificates.Enabled && sslCertificates.AlertThreshold == 0 {
+		sslCertificates = nil
+	}
+
+	m.SSLCertificates, _, diags = SSLCertificatesAttributeGluer.RefreshToObject(ctx, sslCertificates, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	return diags
+}
+
+func (m *AlertSettingsAttributeModel) Render(ctx context.Context, into *checkly.AlertSettings) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	switch m.EscalationType.ValueString() {
+	case checkly.RunBased:
+		into.EscalationType = checkly.RunBased
+		into.RunBasedEscalation, _, diags = RunBasedEscalationAttributeGluer.RenderFromObject(ctx, m.RunBasedEscalation)
+		if diags.HasError() {
+			return diags
+		}
+	case checkly.TimeBased:
+		into.EscalationType = checkly.TimeBased
+		into.TimeBasedEscalation, _, diags = TimeBasedEscalationAttributeGluer.RenderFromObject(ctx, m.TimeBasedEscalation)
+		if diags.HasError() {
+			return diags
+		}
+	default:
+		panic("OTHER")
+		// TODO diags
+	}
+
+	into.Reminders, _, diags = RemindersAttributeGluer.RenderFromObject(ctx, m.Reminders)
+	if diags.HasError() {
+		return diags
+	}
+
+	into.ParallelRunFailureThreshold, _, diags = ParallelRunFailureThresholdAttributeGluer.RenderFromObject(ctx, m.ParallelRunFailureThreshold)
+	if diags.HasError() {
+		return diags
+	}
+
+	into.SSLCertificates, _, diags = SSLCertificatesAttributeGluer.RenderFromObject(ctx, m.SSLCertificates)
+	if diags.HasError() {
+		return diags
+	}
+
+	return diags
+}
+
+type RunBasedEscalationAttributeModel struct {
+	FailedRunThreshold types.Int32 `tfsdk:"failed_run_threshold"`
+}
+
+var RunBasedEscalationAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.RunBasedEscalation,
+	RunBasedEscalationAttributeModel,
+](RunBasedEscalationAttributeSchema)
+
+func (m *RunBasedEscalationAttributeModel) Refresh(ctx context.Context, from *checkly.RunBasedEscalation, flags interop.RefreshFlags) diag.Diagnostics {
+	m.FailedRunThreshold = types.Int32Value(int32(from.FailedRunThreshold))
+
+	return nil
+}
+
+func (m *RunBasedEscalationAttributeModel) Render(ctx context.Context, into *checkly.RunBasedEscalation) diag.Diagnostics {
+	into.FailedRunThreshold = int(m.FailedRunThreshold.ValueInt32())
+
+	return nil
+}
+
+type TimeBasedEscalationAttributeModel struct {
+	MinutesFailingThreshold types.Int32 `tfsdk:"minutes_failing_threshold"`
+}
+
+var TimeBasedEscalationAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.TimeBasedEscalation,
+	TimeBasedEscalationAttributeModel,
+](TimeBasedEscalationAttributeSchema)
+
+func (m *TimeBasedEscalationAttributeModel) Refresh(ctx context.Context, from *checkly.TimeBasedEscalation, flags interop.RefreshFlags) diag.Diagnostics {
+	m.MinutesFailingThreshold = types.Int32Value(int32(from.MinutesFailingThreshold))
+
+	return nil
+}
+
+func (m *TimeBasedEscalationAttributeModel) Render(ctx context.Context, into *checkly.TimeBasedEscalation) diag.Diagnostics {
+	into.MinutesFailingThreshold = int(m.MinutesFailingThreshold.ValueInt32())
+
+	return nil
+}
+
+type RemindersAttributeModel struct {
+	Amount   types.Int32 `tfsdk:"amount"`
+	Interval types.Int32 `tfsdk:"interval"`
+}
+
+var RemindersAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.Reminders,
+	RemindersAttributeModel,
+](RemindersAttributeSchema)
+
+func (m *RemindersAttributeModel) Refresh(ctx context.Context, from *checkly.Reminders, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Amount = types.Int32Value(int32(from.Amount))
+	m.Interval = types.Int32Value(int32(from.Interval))
+
+	return nil
+}
+
+func (m *RemindersAttributeModel) Render(ctx context.Context, into *checkly.Reminders) diag.Diagnostics {
+	into.Amount = int(m.Amount.ValueInt32())
+	into.Interval = int(m.Interval.ValueInt32())
+
+	return nil
+}
+
+type ParallelRunFailureThresholdAttributeModel struct {
+	Enabled    types.Bool  `tfsdk:"enabled"`
+	Percentage types.Int32 `tfsdk:"percentage"`
+}
+
+var ParallelRunFailureThresholdAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.ParallelRunFailureThreshold,
+	ParallelRunFailureThresholdAttributeModel,
+](ParallelRunFailureThresholdAttributeSchema)
+
+func (m *ParallelRunFailureThresholdAttributeModel) Refresh(ctx context.Context, from *checkly.ParallelRunFailureThreshold, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Enabled = types.BoolValue(from.Enabled)
+	m.Percentage = types.Int32Value(int32(from.Percentage))
+
+	return nil
+}
+
+func (m *ParallelRunFailureThresholdAttributeModel) Render(ctx context.Context, into *checkly.ParallelRunFailureThreshold) diag.Diagnostics {
+	into.Enabled = m.Enabled.ValueBool()
+	into.Percentage = int(m.Percentage.ValueInt32())
+
+	return nil
+}
+
+type SSLCertificatesAttributeModel struct {
+	Enabled        types.Bool  `tfsdk:"enabled"`
+	AlertThreshold types.Int32 `tfsdk:"alert_threshold"`
+}
+
+var SSLCertificatesAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.SSLCertificates,
+	SSLCertificatesAttributeModel,
+](SSLCertificatesAttributeSchema)
+
+func (m *SSLCertificatesAttributeModel) Refresh(ctx context.Context, from *checkly.SSLCertificates, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Enabled = types.BoolValue(from.Enabled)
+	m.AlertThreshold = types.Int32Value(int32(from.AlertThreshold))
+
+	return nil
+}
+
+func (m *SSLCertificatesAttributeModel) Render(ctx context.Context, into *checkly.SSLCertificates) diag.Diagnostics {
+	into.Enabled = m.Enabled.ValueBool()
+	into.AlertThreshold = int(m.AlertThreshold.ValueInt32())
+
+	return nil
+}
diff --git a/internal/provider/resources/attributes/api_check_defaults_attribute.go b/internal/provider/resources/attributes/api_check_defaults_attribute.go
new file mode 100644
index 0000000..5b5419c
--- /dev/null
+++ b/internal/provider/resources/attributes/api_check_defaults_attribute.go
@@ -0,0 +1,85 @@
+package attributes
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ interop.Model[checkly.APICheckDefaults] = (*APICheckDefaultsAttributeModel)(nil)
+)
+
+var APICheckDefaultsAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Computed: true,
+	Attributes: map[string]schema.Attribute{
+		"url": schema.StringAttribute{
+			Description: "The base url for this group which you can reference with the `GROUP_BASE_URL` variable in all group checks.",
+			Required:    true,
+		},
+		"headers":          HeadersAttributeSchema,
+		"query_parameters": QueryParametersAttributeSchema,
+		"assertion":        AssertionAttributeSchema,
+		"basic_auth":       BasicAuthAttributeSchema,
+	},
+}
+
+type APICheckDefaultsAttributeModel struct {
+	URL             types.String `tfsdk:"url"`
+	Headers         types.Map    `tfsdk:"headers"`
+	QueryParameters types.Map    `tfsdk:"query_parameters"`
+	Assertions      types.List   `tfsdk:"assertions"`
+	BasicAuth       types.Object `tfsdk:"basic_auth"`
+}
+
+var APICheckDefaultsAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.APICheckDefaults,
+	APICheckDefaultsAttributeModel,
+](APICheckDefaultsAttributeSchema)
+
+func (m *APICheckDefaultsAttributeModel) Refresh(ctx context.Context, from *checkly.APICheckDefaults, flags interop.RefreshFlags) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	m.URL = types.StringValue(from.BaseURL)
+	m.Headers = sdkutil.KeyValuesIntoMap(&from.Headers)
+	m.QueryParameters = sdkutil.KeyValuesIntoMap(&from.QueryParameters)
+
+	m.Assertions, _, diags = AssertionAttributeGluer.RefreshToList(ctx, &from.Assertions, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.BasicAuth, _, diags = BasicAuthAttributeGluer.RefreshToObject(ctx, &from.BasicAuth, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	return diags
+}
+
+func (m *APICheckDefaultsAttributeModel) Render(ctx context.Context, into *checkly.APICheckDefaults) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	into.BaseURL = m.URL.ValueString()
+	into.Headers = sdkutil.KeyValuesFromMap(m.Headers)
+	into.QueryParameters = sdkutil.KeyValuesFromMap(m.QueryParameters)
+
+	into.Assertions, _, diags = AssertionAttributeGluer.RenderFromList(ctx, m.Assertions)
+	if diags.HasError() {
+		return diags
+	}
+
+	into.BasicAuth, _, diags = BasicAuthAttributeGluer.RenderFromObject(ctx, m.BasicAuth)
+	if diags.HasError() {
+		return diags
+	}
+
+	return diags
+}
diff --git a/internal/provider/resources/attributes/assertion_attribute.go b/internal/provider/resources/attributes/assertion_attribute.go
new file mode 100644
index 0000000..975fd20
--- /dev/null
+++ b/internal/provider/resources/attributes/assertion_attribute.go
@@ -0,0 +1,97 @@
+package attributes
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+)
+
+var (
+	_ interop.Model[checkly.Assertion] = (*AssertionAttributeModel)(nil)
+)
+
+var AssertionAttributeSchema = schema.ListNestedAttribute{
+	Optional: true,
+	NestedObject: schema.NestedAttributeObject{
+		Attributes: map[string]schema.Attribute{
+			"source": schema.StringAttribute{
+				Required: true,
+				Validators: []validator.String{
+					stringvalidator.OneOf(
+						"STATUS_CODE",
+						"JSON_BODY",
+						"HEADERS",
+						"TEXT_BODY",
+						"RESPONSE_TIME",
+					),
+				},
+				Description: "The source of the asserted value. Possible values `STATUS_CODE`, `JSON_BODY`, `HEADERS`, `TEXT_BODY`, and `RESPONSE_TIME`.",
+			},
+			"property": schema.StringAttribute{
+				Optional: true,
+			},
+			"comparison": schema.StringAttribute{
+				Required: true,
+				Validators: []validator.String{
+					stringvalidator.OneOf(
+						"CONTAINS",
+						"EQUALS",
+						"GREATER_THAN",
+						"HAS_KEY",
+						"HAS_VALUE",
+						"IS_EMPTY",
+						"IS_NULL",
+						"LESS_THAN",
+						"NOT_CONTAINS",
+						"NOT_EMPTY",
+						"NOT_EQUALS",
+						"NOT_HAS_KEY",
+						"NOT_HAS_VALUE",
+						"NOT_NULL",
+					),
+				},
+				Description: "The type of comparison to be executed between expected and actual value of the assertion. Possible values `EQUALS`, `NOT_EQUALS`, `HAS_KEY`, `NOT_HAS_KEY`, `HAS_VALUE`, `NOT_HAS_VALUE`, `IS_EMPTY`, `NOT_EMPTY`, `GREATER_THAN`, `LESS_THAN`, `CONTAINS`, `NOT_CONTAINS`, `IS_NULL`, and `NOT_NULL`.",
+			},
+			"target": schema.StringAttribute{
+				Required: true,
+			},
+		},
+	},
+}
+
+type AssertionAttributeModel struct {
+	Source     types.String `tfsdk:"source"`
+	Property   types.String `tfsdk:"property"`
+	Comparison types.String `tfsdk:"comparison"`
+	Target     types.String `tfsdk:"target"`
+}
+
+var AssertionAttributeGluer = interop.GluerForListNestedAttribute[
+	checkly.Assertion,
+	AssertionAttributeModel,
+](AssertionAttributeSchema)
+
+func (m *AssertionAttributeModel) Refresh(ctx context.Context, from *checkly.Assertion, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Source = types.StringValue(from.Source)
+	m.Property = types.StringValue(from.Property)
+	m.Comparison = types.StringValue(from.Comparison)
+	m.Target = types.StringValue(from.Target)
+
+	return nil
+}
+
+func (m *AssertionAttributeModel) Render(ctx context.Context, into *checkly.Assertion) diag.Diagnostics {
+	into.Source = m.Source.ValueString()
+	into.Property = m.Property.ValueString()
+	into.Comparison = m.Comparison.ValueString()
+	into.Target = m.Target.ValueString()
+
+	return nil
+}
diff --git a/internal/provider/resources/attributes/basic_auth_attribute.go b/internal/provider/resources/attributes/basic_auth_attribute.go
new file mode 100644
index 0000000..8604e94
--- /dev/null
+++ b/internal/provider/resources/attributes/basic_auth_attribute.go
@@ -0,0 +1,54 @@
+package attributes
+
+import (
+	"context"
+
+	"github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+var (
+	_ interop.Model[checkly.BasicAuth] = (*BasicAuthAttributeModel)(nil)
+)
+
+var BasicAuthAttributeSchema = schema.SingleNestedAttribute{
+	Description: "Credentials for Basic HTTP authentication.",
+	Optional:    true,
+	Computed:    true,
+	Attributes: map[string]schema.Attribute{
+		"username": schema.StringAttribute{
+			Required: true,
+		},
+		"password": schema.StringAttribute{
+			Required:  true,
+			Sensitive: true,
+		},
+	},
+}
+
+type BasicAuthAttributeModel struct {
+	Username types.String `tfsdk:"username"`
+	Password types.String `tfsdk:"password"`
+}
+
+var BasicAuthAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.BasicAuth,
+	BasicAuthAttributeModel,
+](BasicAuthAttributeSchema)
+
+func (m *BasicAuthAttributeModel) Refresh(ctx context.Context, from *checkly.BasicAuth, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Username = types.StringValue(from.Username)
+	m.Password = types.StringValue(from.Password)
+
+	return nil
+}
+
+func (m *BasicAuthAttributeModel) Render(ctx context.Context, into *checkly.BasicAuth) diag.Diagnostics {
+	into.Username = m.Username.ValueString()
+	into.Password = m.Password.ValueString()
+
+	return nil
+}
diff --git a/internal/provider/resources/attributes/environment_variable_attribute.go b/internal/provider/resources/attributes/environment_variable_attribute.go
new file mode 100644
index 0000000..2ab0625
--- /dev/null
+++ b/internal/provider/resources/attributes/environment_variable_attribute.go
@@ -0,0 +1,104 @@
+package attributes
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+)
+
+var (
+	_ interop.Model[checkly.EnvironmentVariable] = (*EnvironmentVariableAttributeModel)(nil)
+)
+
+var EnvironmentVariableAttributeSchema = schema.ListNestedAttribute{
+	Optional: true,
+	Description: "Introduce additional environment variables to the check " +
+		"execution environment. Only relevant for browser checks. Prefer " +
+		"global environment variables when possible.",
+	NestedObject: schema.NestedAttributeObject{
+		Attributes: map[string]schema.Attribute{
+			"key": schema.StringAttribute{
+				Description: "The name of the environment variable.",
+				Required:    true,
+			},
+			"value": schema.StringAttribute{
+				Description: "The value of the environment variable. By " +
+					"default the value is plain text and can be seen by any " +
+					"team member. It will also be present in check results " +
+					"and logs.",
+				Required: true,
+				// We cannot make the value conditionally sensitive, so it's
+				// better to assume everything's sensitive.
+				Sensitive: true,
+			},
+			"locked": schema.BoolAttribute{
+				Description: "Locked environment variables are encrypted at " +
+					"rest and in flight on the Checkly backend and are only " +
+					"decrypted when needed. Their value is hidden by " +
+					"default, but can be accessed by team members with the " +
+					"appropriate permissions.",
+				Optional: true,
+				Computed: true,
+				Default:  booldefault.StaticBool(false),
+				Validators: []validator.Bool{
+					boolvalidator.ConflictsWith(
+						path.MatchRelative().AtParent().AtName("secret"),
+					),
+				},
+			},
+			"secret": schema.BoolAttribute{
+				Description: "Secret environment variables are always " +
+					"encrypted and their value is never shown to any user. " +
+					"However, keep in mind that your Terraform state will " +
+					"still contain the value.",
+				Optional: true,
+				Computed: true,
+				Default:  booldefault.StaticBool(false),
+				Validators: []validator.Bool{
+					boolvalidator.ConflictsWith(
+						path.MatchRelative().AtParent().AtName("locked"),
+					),
+				},
+			},
+		},
+	},
+}
+
+type EnvironmentVariableAttributeModel struct {
+	Key    types.String `tfsdk:"key"`
+	Value  types.String `tfsdk:"value"`
+	Locked types.Bool   `tfsdk:"locked"`
+	Secret types.Bool   `tfsdk:"secret"`
+}
+
+var EnvironmentVariableAttributeGluer = interop.GluerForListNestedAttribute[
+	checkly.EnvironmentVariable,
+	EnvironmentVariableAttributeModel,
+](EnvironmentVariableAttributeSchema)
+
+func (m *EnvironmentVariableAttributeModel) Refresh(ctx context.Context, from *checkly.EnvironmentVariable, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Key = types.StringValue(from.Key)
+	m.Value = types.StringValue(from.Value)
+	m.Locked = types.BoolValue(from.Locked)
+	m.Secret = types.BoolValue(from.Secret)
+
+	return nil
+}
+
+func (m *EnvironmentVariableAttributeModel) Render(ctx context.Context, into *checkly.EnvironmentVariable) diag.Diagnostics {
+	into.Key = m.Key.ValueString()
+	into.Value = m.Value.ValueString()
+	into.Locked = m.Locked.ValueBool()
+	into.Secret = m.Secret.ValueBool()
+
+	return nil
+}
diff --git a/internal/provider/resources/attributes/headers_attribute.go b/internal/provider/resources/attributes/headers_attribute.go
new file mode 100644
index 0000000..cc4feec
--- /dev/null
+++ b/internal/provider/resources/attributes/headers_attribute.go
@@ -0,0 +1,37 @@
+package attributes
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ interop.Model[[]checkly.KeyValue] = (*HeadersAttributeModel)(nil)
+)
+
+var HeadersAttributeSchema = schema.MapAttribute{
+	ElementType: types.StringType,
+	Optional:    true,
+	Computed:    true, // TODO: Really?
+}
+
+type HeadersAttributeModel types.Map
+
+func (m *HeadersAttributeModel) Refresh(ctx context.Context, from *[]checkly.KeyValue, flags interop.RefreshFlags) diag.Diagnostics {
+	*m = HeadersAttributeModel(sdkutil.KeyValuesIntoMap(from))
+
+	return nil
+}
+
+func (m *HeadersAttributeModel) Render(ctx context.Context, into *[]checkly.KeyValue) diag.Diagnostics {
+	*into = sdkutil.KeyValuesFromMap(types.Map(*m))
+
+	return nil
+}
diff --git a/internal/provider/resources/attributes/id_attribute.go b/internal/provider/resources/attributes/id_attribute.go
new file mode 100644
index 0000000..40ce184
--- /dev/null
+++ b/internal/provider/resources/attributes/id_attribute.go
@@ -0,0 +1,15 @@
+package attributes
+
+import (
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+)
+
+var IDAttributeSchema = schema.StringAttribute{
+	Computed:    true,
+	Description: "The ID of this resource.",
+	PlanModifiers: []planmodifier.String{
+		stringplanmodifier.UseStateForUnknown(),
+	},
+}
diff --git a/internal/provider/resources/attributes/locations_attribute.go b/internal/provider/resources/attributes/locations_attribute.go
new file mode 100644
index 0000000..274a65e
--- /dev/null
+++ b/internal/provider/resources/attributes/locations_attribute.go
@@ -0,0 +1,39 @@
+package attributes
+
+import (
+	"context"
+
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+var (
+	_ interop.Model[string] = (*LocationsAttributeModel)(nil)
+)
+
+var LocationsAttributeSchema = schema.SetAttribute{
+	Description: "An array of one or more data center locations where to run the checks.",
+	ElementType: types.StringType,
+	Optional:    true,
+}
+
+type LocationsAttributeModel string
+
+var LocationsAttributeGluer = interop.GluerForSetAttribute[
+	string,
+	LocationsAttributeModel,
+](LocationsAttributeSchema)
+
+func (m *LocationsAttributeModel) Refresh(ctx context.Context, from *string, flags interop.RefreshFlags) diag.Diagnostics {
+	*m = LocationsAttributeModel(*from)
+
+	return nil
+}
+
+func (m *LocationsAttributeModel) Render(ctx context.Context, into *string) diag.Diagnostics {
+	*into = string(*m)
+
+	return nil
+}
diff --git a/internal/provider/resources/attributes/private_locations_attribute.go b/internal/provider/resources/attributes/private_locations_attribute.go
new file mode 100644
index 0000000..a39fd17
--- /dev/null
+++ b/internal/provider/resources/attributes/private_locations_attribute.go
@@ -0,0 +1,39 @@
+package attributes
+
+import (
+	"context"
+
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+var (
+	_ interop.Model[string] = (*PrivateLocationsAttributeModel)(nil)
+)
+
+var PrivateLocationsAttributeSchema = schema.SetAttribute{
+	Description: "An array of one or more private locations slugs.",
+	ElementType: types.StringType,
+	Optional:    true,
+}
+
+type PrivateLocationsAttributeModel string
+
+var PrivateLocationsAttributeGluer = interop.GluerForSetAttribute[
+	string,
+	PrivateLocationsAttributeModel,
+](PrivateLocationsAttributeSchema)
+
+func (m *PrivateLocationsAttributeModel) Refresh(ctx context.Context, from *string, flags interop.RefreshFlags) diag.Diagnostics {
+	*m = PrivateLocationsAttributeModel(*from)
+
+	return nil
+}
+
+func (m *PrivateLocationsAttributeModel) Render(ctx context.Context, into *string) diag.Diagnostics {
+	*into = string(*m)
+
+	return nil
+}
diff --git a/internal/provider/resources/attributes/query_parameters_attribute.go b/internal/provider/resources/attributes/query_parameters_attribute.go
new file mode 100644
index 0000000..a8812e2
--- /dev/null
+++ b/internal/provider/resources/attributes/query_parameters_attribute.go
@@ -0,0 +1,37 @@
+package attributes
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ interop.Model[[]checkly.KeyValue] = (*QueryParametersAttributeModel)(nil)
+)
+
+var QueryParametersAttributeSchema = schema.MapAttribute{
+	ElementType: types.StringType,
+	Optional:    true,
+	Computed:    true, // TODO: Really?
+}
+
+type QueryParametersAttributeModel types.Map
+
+func (m *QueryParametersAttributeModel) Refresh(ctx context.Context, from *[]checkly.KeyValue, flags interop.RefreshFlags) diag.Diagnostics {
+	*m = QueryParametersAttributeModel(sdkutil.KeyValuesIntoMap(from))
+
+	return nil
+}
+
+func (m *QueryParametersAttributeModel) Render(ctx context.Context, into *[]checkly.KeyValue) diag.Diagnostics {
+	*into = sdkutil.KeyValuesFromMap(types.Map(*m))
+
+	return nil
+}
diff --git a/internal/provider/resources/attributes/request_attribute.go b/internal/provider/resources/attributes/request_attribute.go
new file mode 100644
index 0000000..3187ea2
--- /dev/null
+++ b/internal/provider/resources/attributes/request_attribute.go
@@ -0,0 +1,165 @@
+package attributes
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ interop.Model[checkly.Request] = (*RequestAttributeModel)(nil)
+)
+
+var RequestAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Attributes: map[string]schema.Attribute{
+		"method": schema.StringAttribute{
+			Optional: true,
+			Computed: true,
+			Default:  stringdefault.StaticString("GET"),
+			Validators: []validator.String{
+				stringvalidator.OneOf(
+					"GET",
+					"POST",
+					"PUT",
+					"HEAD",
+					"DELETE",
+					"PATCH",
+				),
+			},
+			Description: "The HTTP method to use for this API check. Possible values are `GET`, `POST`, `PUT`, `HEAD`, `DELETE`, `PATCH`. (Default `GET`).",
+		},
+		"url": schema.StringAttribute{
+			Required: true,
+		},
+		"follow_redirects": schema.BoolAttribute{
+			Optional: true,
+		},
+		"skip_ssl": schema.BoolAttribute{
+			Optional: true,
+		},
+		"headers":          HeadersAttributeSchema,
+		"query_parameters": QueryParametersAttributeSchema,
+		"body": schema.StringAttribute{
+			Optional:    true,
+			Description: "The body of the request.",
+		},
+		"body_type": schema.StringAttribute{
+			Optional: true,
+			Computed: true,
+			Default:  stringdefault.StaticString("NONE"),
+			Validators: []validator.String{
+				stringvalidator.OneOf(
+					"NONE",
+					"JSON",
+					"FORM",
+					"RAW",
+					"GRAPHQL",
+				),
+			},
+			Description: "The `Content-Type` header of the request. Possible values `NONE`, `JSON`, `FORM`, `RAW`, and `GRAPHQL`.",
+		},
+		"assertion":  AssertionAttributeSchema,
+		"basic_auth": BasicAuthAttributeSchema,
+		"ip_family": schema.StringAttribute{
+			Optional: true,
+			Computed: true,
+			Default:  stringdefault.StaticString("IPv4"),
+			Validators: []validator.String{
+				stringvalidator.OneOf(
+					"IPv4",
+					"IPv6",
+				),
+			},
+			Description: "IP Family to be used when executing the api check. The value can be either IPv4 or IPv6.",
+		},
+	},
+}
+
+type RequestAttributeModel struct {
+	Method          types.String `tfsdk:"method"`
+	URL             types.String `tfsdk:"url"`
+	FollowRedirects types.Bool   `tfsdk:"follow_redirects"`
+	SkipSSL         types.Bool   `tfsdk:"skip_ssl"`
+	Headers         types.Map    `tfsdk:"headers"`
+	QueryParameters types.Map    `tfsdk:"query_parameters"`
+	Body            types.String `tfsdk:"body"`
+	BodyType        types.String `tfsdk:"body_type"`
+	Assertions      types.List   `tfsdk:"assertions"`
+	BasicAuth       types.Object `tfsdk:"basic_auth"`
+	IPFamily        types.String `tfsdk:"ip_family"`
+}
+
+var RequestAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.Request,
+	RequestAttributeModel,
+](RequestAttributeSchema)
+
+func (m *RequestAttributeModel) Refresh(ctx context.Context, from *checkly.Request, flags interop.RefreshFlags) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	m.Method = types.StringValue(from.Method)
+	m.URL = types.StringValue(from.URL)
+	m.FollowRedirects = types.BoolValue(from.FollowRedirects)
+	m.SkipSSL = types.BoolValue(from.SkipSSL)
+	m.Headers = sdkutil.KeyValuesIntoMap(&from.Headers)
+	m.QueryParameters = sdkutil.KeyValuesIntoMap(&from.QueryParameters)
+	m.Body = types.StringValue(from.Body)
+	m.BodyType = types.StringValue(from.BodyType)
+
+	m.Assertions, _, diags = AssertionAttributeGluer.RefreshToList(ctx, &from.Assertions, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.BasicAuth, _, diags = BasicAuthAttributeGluer.RefreshToObject(ctx, from.BasicAuth, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.IPFamily = types.StringValue(from.IPFamily)
+
+	return nil
+}
+
+func (m *RequestAttributeModel) Render(ctx context.Context, into *checkly.Request) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	into.Method = m.Method.ValueString()
+	into.URL = m.URL.ValueString()
+	into.FollowRedirects = m.FollowRedirects.ValueBool()
+	into.SkipSSL = m.SkipSSL.ValueBool()
+	into.Headers = sdkutil.KeyValuesFromMap(m.Headers)
+	into.QueryParameters = sdkutil.KeyValuesFromMap(m.QueryParameters)
+	into.Body = m.Body.ValueString()
+	into.BodyType = m.Body.ValueString()
+
+	into.Assertions, _, diags = AssertionAttributeGluer.RenderFromList(ctx, m.Assertions)
+	if diags.HasError() {
+		return diags
+	}
+
+	if m.BasicAuth.IsNull() || m.BasicAuth.IsUnknown() {
+		into.BasicAuth = nil
+	} else {
+		basicAuth, _, diags := BasicAuthAttributeGluer.RenderFromObject(ctx, m.BasicAuth)
+		if diags.HasError() {
+			return diags
+		}
+
+		into.BasicAuth = &basicAuth
+	}
+
+	into.IPFamily = m.IPFamily.ValueString()
+
+	return nil
+}
diff --git a/internal/provider/resources/attributes/retry_strategy_attribute.go b/internal/provider/resources/attributes/retry_strategy_attribute.go
new file mode 100644
index 0000000..1b06c7a
--- /dev/null
+++ b/internal/provider/resources/attributes/retry_strategy_attribute.go
@@ -0,0 +1,103 @@
+package attributes
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/int32validator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int32default"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+)
+
+var (
+	_ interop.Model[checkly.RetryStrategy] = (*RetryStrategyAttributeModel)(nil)
+)
+
+var RetryStrategyAttributeSchema = schema.SingleNestedAttribute{
+	Optional: true,
+	Computed: true,
+	Attributes: map[string]schema.Attribute{
+		"type": schema.StringAttribute{
+			Required: true,
+			Validators: []validator.String{
+				stringvalidator.OneOf(
+					"FIXED",
+					"LINEAR",
+					"EXPONENTIAL",
+				),
+			},
+			Description: "Determines which type of retry strategy to use. Possible values are `FIXED`, `LINEAR`, or `EXPONENTIAL`.",
+		},
+		"base_backoff_seconds": schema.Int32Attribute{
+			Optional:    true,
+			Computed:    true,
+			Default:     int32default.StaticInt32(60),
+			Description: "The number of seconds to wait before the first retry attempt.",
+		},
+		"max_retries": schema.Int32Attribute{
+			Optional: true,
+			Computed: true,
+			Default:  int32default.StaticInt32(2),
+			Validators: []validator.Int32{
+				int32validator.Between(1, 10),
+			},
+			Description: "The maximum number of times to retry the check. Value must be between 1 and 10.",
+		},
+		"max_duration_seconds": schema.Int32Attribute{
+			Optional: true,
+			Computed: true,
+			Default:  int32default.StaticInt32(600),
+			Validators: []validator.Int32{
+				int32validator.AtMost(600),
+			},
+			Description: "The total amount of time to continue retrying the check (maximum 600 seconds).",
+		},
+		"same_region": schema.BoolAttribute{
+			Optional:    true,
+			Computed:    true,
+			Default:     booldefault.StaticBool(true),
+			Description: "Whether retries should be run in the same region as the initial check run.",
+		},
+	},
+	Description: "A strategy for retrying failed check runs.",
+}
+
+type RetryStrategyAttributeModel struct {
+	Type               types.String `tfsdk:"type"`
+	BaseBackoffSeconds types.Int32  `tfsdk:"base_backoff_seconds"`
+	MaxRetries         types.Int32  `tfsdk:"max_retries"`
+	MaxDurationSeconds types.Int32  `tfsdk:"max_duration_seconds"`
+	SameRegion         types.Bool   `tfsdk:"same_region"`
+}
+
+var RetryStrategyAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.RetryStrategy,
+	RetryStrategyAttributeModel,
+](RetryStrategyAttributeSchema)
+
+func (m *RetryStrategyAttributeModel) Refresh(ctx context.Context, from *checkly.RetryStrategy, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Type = types.StringValue(from.Type)
+	m.BaseBackoffSeconds = types.Int32Value(int32(from.BaseBackoffSeconds))
+	m.MaxRetries = types.Int32Value(int32(from.MaxRetries))
+	m.MaxDurationSeconds = types.Int32Value(int32(from.MaxDurationSeconds))
+	m.SameRegion = types.BoolValue(from.SameRegion)
+
+	return nil
+}
+
+func (m *RetryStrategyAttributeModel) Render(ctx context.Context, into *checkly.RetryStrategy) diag.Diagnostics {
+	into.Type = m.Type.ValueString()
+	into.BaseBackoffSeconds = int(m.BaseBackoffSeconds.ValueInt32())
+	into.MaxRetries = int(m.MaxRetries.ValueInt32())
+	into.MaxDurationSeconds = int(m.MaxDurationSeconds.ValueInt32())
+	into.SameRegion = m.SameRegion.ValueBool()
+
+	return nil
+}
diff --git a/internal/provider/resources/check_group_resource.go b/internal/provider/resources/check_group_resource.go
new file mode 100644
index 0000000..ac5521b
--- /dev/null
+++ b/internal/provider/resources/check_group_resource.go
@@ -0,0 +1,500 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/mapvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"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"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/resources/attributes"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ resource.Resource                = (*CheckGroupResource)(nil)
+	_ resource.ResourceWithConfigure   = (*CheckGroupResource)(nil)
+	_ resource.ResourceWithImportState = (*CheckGroupResource)(nil)
+)
+
+type CheckGroupResource struct {
+	client checkly.Client
+}
+
+func NewCheckGroupResource() resource.Resource {
+	return &CheckGroupResource{}
+}
+
+func (r *CheckGroupResource) Metadata(
+	ctx context.Context,
+	req resource.MetadataRequest,
+	resp *resource.MetadataResponse,
+) {
+	resp.TypeName = req.ProviderTypeName + "_check_group"
+}
+
+func (r *CheckGroupResource) Schema(
+	ctx context.Context,
+	req resource.SchemaRequest,
+	resp *resource.SchemaResponse,
+) {
+	resp.Schema = schema.Schema{
+		Description: "Check groups allow you to group together a set of related checks, which can also share default settings for various attributes.",
+		Attributes: map[string]schema.Attribute{
+			"id": attributes.IDAttributeSchema,
+			"name": schema.StringAttribute{
+				Required:    true,
+				Description: "The name of the check group.",
+			},
+			"concurrency": schema.Int32Attribute{
+				Required:    true,
+				Description: "Determines how many checks are run concurrently when triggering a check group from CI/CD or through the API.",
+			},
+			"activated": schema.BoolAttribute{
+				Required:    true,
+				Description: "Determines if the checks in the group are running or not.",
+			},
+			"muted": schema.BoolAttribute{
+				Optional:    true,
+				Description: "Determines if any notifications will be sent out when a check in this group fails and/or recovers.",
+			},
+			"run_parallel": schema.BoolAttribute{
+				Optional:    true,
+				Description: "Determines if the checks in the group should run in all selected locations in parallel or round-robin.",
+			},
+			"locations":         attributes.LocationsAttributeSchema,
+			"private_locations": attributes.PrivateLocationsAttributeSchema,
+			"environment_variables": schema.MapAttribute{
+				ElementType: types.StringType,
+				Validators: []validator.Map{
+					mapvalidator.ConflictsWith(
+						path.MatchRelative().AtParent().AtName("environment_variable"),
+					),
+				},
+				Optional:           true,
+				Description:        "Key/value pairs for setting environment variables during check execution. These are only relevant for browser checks. Use global environment variables whenever possible.",
+				DeprecationMessage: "The property `environment_variables` is deprecated and will be removed in a future version. Consider using the new `environment_variable` list.",
+			},
+			"environment_variable": attributes.EnvironmentVariableAttributeSchema,
+			"double_check": schema.BoolAttribute{
+				Optional:           true,
+				Description:        "Setting this to `true` will trigger a retry when a check fails from the failing region and another, randomly selected region before marking the check as failed.",
+				DeprecationMessage: "The property `double_check` is deprecated and will be removed in a future version. To enable retries for failed check runs, use the `retry_strategy` property instead.",
+			},
+			"tags": schema.SetAttribute{
+				ElementType: types.StringType,
+				Optional:    true,
+				Description: "Tags for organizing and filtering checks.",
+			},
+			"setup_snippet_id": schema.Int64Attribute{
+				Optional:    true,
+				Description: "An ID reference to a snippet to use in the setup phase of an API check.",
+			},
+			"teardown_snippet_id": schema.Int64Attribute{
+				Optional:    true,
+				Description: "An ID reference to a snippet to use in the teardown phase of an API check.",
+			},
+			"local_setup_script": schema.StringAttribute{
+				Optional:    true,
+				Description: "A valid piece of Node.js code to run in the setup phase of an API check in this group.",
+			},
+			"local_teardown_script": schema.StringAttribute{
+				Optional:    true,
+				Description: "A valid piece of Node.js code to run in the teardown phase of an API check in this group.",
+			},
+			"runtime_id": schema.StringAttribute{
+				Optional:    true,
+				Description: "The id of the runtime to use for this group.",
+			},
+			"alert_channel_subscription": attributes.AlertChannelSubscriptionAttributeSchema,
+			"alert_settings":             attributes.AlertSettingsAttributeSchema,
+			"use_global_alert_settings": schema.BoolAttribute{
+				Optional:    true,
+				Description: "When true, the account level alert settings will be used, not the alert setting defined on this check group.",
+			},
+			"api_check_defaults": attributes.APICheckDefaultsAttributeSchema,
+			"retry_strategy":     attributes.RetryStrategyAttributeSchema,
+		},
+	}
+}
+
+func (r *CheckGroupResource) Configure(
+	ctx context.Context,
+	req resource.ConfigureRequest,
+	resp *resource.ConfigureResponse,
+) {
+	client, diags := interop.ClientFromProviderData(req.ProviderData)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	r.client = client
+}
+
+func (r *CheckGroupResource) ImportState(
+	ctx context.Context,
+	req resource.ImportStateRequest,
+	resp *resource.ImportStateResponse,
+) {
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *CheckGroupResource) Create(
+	ctx context.Context,
+	req resource.CreateRequest,
+	resp *resource.CreateResponse,
+) {
+	var plan CheckGroupResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.Group
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.CreateGroup(ctx, desiredModel)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Creating Checkly Check Group",
+			fmt.Sprintf("Could not create check group, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Created)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *CheckGroupResource) Delete(
+	ctx context.Context,
+	req resource.DeleteRequest,
+	resp *resource.DeleteResponse,
+) {
+	var state CheckGroupResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	id, diags := CheckGroupID.FromString(state.ID)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	err := r.client.DeleteGroup(ctx, id)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Deleting Checkly Check Group",
+			fmt.Sprintf("Could not delete check group, unexpected error: %s", err),
+		)
+
+		return
+	}
+}
+
+func (r *CheckGroupResource) Read(
+	ctx context.Context,
+	req resource.ReadRequest,
+	resp *resource.ReadResponse,
+) {
+	var state CheckGroupResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	id, diags := CheckGroupID.FromString(state.ID)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	realizedModel, err := r.client.GetGroup(ctx, id)
+	if err != nil {
+		if sdkutil.IsHTTPNotFoundError(err) {
+			resp.State.RemoveResource(ctx)
+			return
+		}
+
+		resp.Diagnostics.AddError(
+			"Error Reading Checkly Check Group",
+			fmt.Sprintf("Could not retrieve check group, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(state.Refresh(ctx, realizedModel, interop.Loaded)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *CheckGroupResource) Update(
+	ctx context.Context,
+	req resource.UpdateRequest,
+	resp *resource.UpdateResponse,
+) {
+	var plan CheckGroupResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	id, diags := CheckGroupID.FromString(plan.ID)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	var desiredModel checkly.Group
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.UpdateGroup(
+		ctx,
+		id,
+		desiredModel,
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Updating Checkly Check Group",
+			fmt.Sprintf("Could not update check group, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Updated)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+var CheckGroupID = sdkutil.Identifier{
+	Path:  path.Root("id"),
+	Title: "Checkly Check Group ID",
+}
+
+var (
+	_ interop.Model[checkly.Group] = (*CheckGroupResourceModel)(nil)
+)
+
+type CheckGroupResourceModel struct {
+	ID                        types.String `tfsdk:"id"`
+	Name                      types.String `tfsdk:"name"`
+	Concurrency               types.Int32  `tfsdk:"concurrency"`
+	Activated                 types.Bool   `tfsdk:"activated"`
+	Muted                     types.Bool   `tfsdk:"muted"`
+	RunParallel               types.Bool   `tfsdk:"run_parallel"`
+	Locations                 types.Set    `tfsdk:"locations"`
+	PrivateLocations          types.Set    `tfsdk:"private_locations"`
+	EnvironmentVariables      types.Map    `tfsdk:"environment_variables"`
+	EnvironmentVariable       types.List   `tfsdk:"environment_variable"`
+	DoubleCheck               types.Bool   `tfsdk:"double_check"`
+	Tags                      types.Set    `tfsdk:"tags"`
+	SetupSnippetID            types.Int64  `tfsdk:"setup_snippet_id"`
+	TearDownSnippetID         types.Int64  `tfsdk:"teardown_snippet_id"`
+	LocalSetupScript          types.String `tfsdk:"local_setup_script"`
+	LocalTearDownScript       types.String `tfsdk:"local_teardown_script"`
+	RuntimeID                 types.String `tfsdk:"runtime_id"`
+	AlertChannelSubscriptions types.List   `tfsdk:"alert_channel_subscription"`
+	AlertSettings             types.Object `tfsdk:"alert_settings"`
+	UseGlobalAlertSettings    types.Bool   `tfsdk:"use_global_alert_settings"`
+	APICheckDefaults          types.Object `tfsdk:"api_check_defaults"`
+	RetryStrategy             types.Object `tfsdk:"retry_strategy"`
+}
+
+func (m *CheckGroupResourceModel) Refresh(ctx context.Context, from *checkly.Group, flags interop.RefreshFlags) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	if flags.Created() {
+		m.ID = CheckGroupID.IntoString(from.ID)
+	}
+
+	m.Name = types.StringValue(from.Name)
+	m.Concurrency = types.Int32Value(int32(from.Concurrency))
+	m.Activated = types.BoolValue(from.Activated)
+	m.Muted = types.BoolValue(from.Muted)
+	m.RunParallel = types.BoolValue(from.RunParallel)
+
+	m.Locations, _, diags = attributes.LocationsAttributeGluer.RefreshToSet(ctx, &from.Locations, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.PrivateLocations, _, diags = attributes.PrivateLocationsAttributeGluer.RefreshToSet(ctx, from.PrivateLocations, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	if !m.EnvironmentVariables.IsNull() {
+		// Deprecated mode.
+		m.EnvironmentVariables = types.MapNull(types.StringType)
+
+		// TODO either implement backwards compat or remove.
+	} else {
+		m.EnvironmentVariable, _, diags = attributes.EnvironmentVariableAttributeGluer.RefreshToList(ctx, &from.EnvironmentVariables, flags)
+		if diags.HasError() {
+			return diags
+		}
+	}
+
+	m.DoubleCheck = types.BoolValue(from.DoubleCheck)
+
+	m.Tags = interop.IntoUntypedStringSet(&from.Tags)
+
+	m.SetupSnippetID = types.Int64Value(from.SetupSnippetID)
+	m.TearDownSnippetID = types.Int64Value(from.TearDownSnippetID)
+	m.LocalSetupScript = types.StringValue(from.LocalSetupScript)
+	m.LocalTearDownScript = types.StringValue(from.LocalTearDownScript)
+
+	if from.RuntimeID != nil {
+		m.RuntimeID = types.StringValue(*from.RuntimeID)
+	} else {
+		m.RuntimeID = types.StringNull()
+	}
+
+	m.AlertChannelSubscriptions, _, diags = attributes.AlertChannelSubscriptionAttributeGluer.RefreshToList(ctx, &from.AlertChannelSubscriptions, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.AlertSettings, _, diags = attributes.AlertSettingsAttributeGluer.RefreshToObject(ctx, &from.AlertSettings, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.UseGlobalAlertSettings = types.BoolValue(from.UseGlobalAlertSettings)
+
+	m.APICheckDefaults, _, diags = attributes.APICheckDefaultsAttributeGluer.RefreshToObject(ctx, &from.APICheckDefaults, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.RetryStrategy, _, diags = attributes.RetryStrategyAttributeGluer.RefreshToObject(ctx, from.RetryStrategy, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	return nil
+}
+
+func (m *CheckGroupResourceModel) Render(ctx context.Context, into *checkly.Group) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	into.Name = m.Name.ValueString()
+	into.Concurrency = int(m.Concurrency.ValueInt32())
+	into.Activated = m.Activated.ValueBool()
+	into.Muted = m.Muted.ValueBool()
+	into.RunParallel = m.RunParallel.ValueBool()
+
+	into.Locations, _, diags = attributes.LocationsAttributeGluer.RenderFromSet(ctx, m.Locations)
+	if diags.HasError() {
+		return diags
+	}
+
+	privateLocations, _, diags := attributes.PrivateLocationsAttributeGluer.RenderFromSet(ctx, m.PrivateLocations)
+	if diags.HasError() {
+		return diags
+	}
+
+	into.PrivateLocations = &privateLocations
+
+	if !m.EnvironmentVariables.IsNull() {
+		// Deprecated mode.
+		into.EnvironmentVariables = nil
+
+		// TODO either implement backwards compat or remove.
+	} else {
+		into.EnvironmentVariables = nil
+
+		into.EnvironmentVariables, _, diags = attributes.EnvironmentVariableAttributeGluer.RenderFromList(ctx, m.EnvironmentVariable)
+		if diags.HasError() {
+			return diags
+		}
+	}
+
+	into.DoubleCheck = m.DoubleCheck.ValueBool()
+
+	into.Tags = interop.FromUntypedStringSet(m.Tags)
+
+	into.SetupSnippetID = m.SetupSnippetID.ValueInt64()
+	into.TearDownSnippetID = m.TearDownSnippetID.ValueInt64()
+	into.LocalSetupScript = m.LocalSetupScript.ValueString()
+	into.LocalTearDownScript = m.LocalTearDownScript.ValueString()
+
+	if !m.RuntimeID.IsNull() {
+		value := m.RuntimeID.ValueString()
+		into.RuntimeID = &value
+	} else {
+		into.RuntimeID = nil
+	}
+
+	into.AlertChannelSubscriptions, _, diags = attributes.AlertChannelSubscriptionAttributeGluer.RenderFromList(ctx, m.AlertChannelSubscriptions)
+	if diags.HasError() {
+		return diags
+	}
+
+	into.AlertSettings, _, diags = attributes.AlertSettingsAttributeGluer.RenderFromObject(ctx, m.AlertSettings)
+	if diags.HasError() {
+		return diags
+	}
+
+	into.UseGlobalAlertSettings = m.UseGlobalAlertSettings.ValueBool()
+
+	into.APICheckDefaults, _, diags = attributes.APICheckDefaultsAttributeGluer.RenderFromObject(ctx, m.APICheckDefaults)
+	if diags.HasError() {
+		return diags
+	}
+
+	if m.RetryStrategy.IsNull() || m.RetryStrategy.IsUnknown() {
+		into.RetryStrategy = nil
+	} else {
+		retryStrategy, _, diags := attributes.RetryStrategyAttributeGluer.RenderFromObject(ctx, m.RetryStrategy)
+		if diags.HasError() {
+			return diags
+		}
+
+		into.RetryStrategy = &retryStrategy
+	}
+
+	return nil
+}
diff --git a/internal/provider/resources/check_group_resource_test.go b/internal/provider/resources/check_group_resource_test.go
new file mode 100644
index 0000000..a16a448
--- /dev/null
+++ b/internal/provider/resources/check_group_resource_test.go
@@ -0,0 +1,433 @@
+package resources_test
+
+import (
+	"regexp"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+
+	"github.com/checkly/checkly-go-sdk"
+)
+
+var wantGroup = checkly.Group{
+	Name:             "test",
+	Activated:        true,
+	Muted:            false,
+	Tags:             []string{"auto"},
+	Locations:        []string{"eu-west-1"},
+	PrivateLocations: &[]string{},
+	Concurrency:      3,
+	APICheckDefaults: checkly.APICheckDefaults{
+		BaseURL: "example.com/api/test",
+		Headers: []checkly.KeyValue{
+			{
+				Key:   "X-Test",
+				Value: "foo",
+			},
+		},
+		QueryParameters: []checkly.KeyValue{
+			{
+				Key:   "query",
+				Value: "foo",
+			},
+		},
+		Assertions: []checkly.Assertion{
+			{
+				Source:     checkly.StatusCode,
+				Comparison: checkly.Equals,
+				Target:     "200",
+			},
+		},
+		BasicAuth: checkly.BasicAuth{
+			Username: "user",
+			Password: "pass",
+		},
+	},
+	EnvironmentVariables: []checkly.EnvironmentVariable{
+		{
+			Key:   "ENVTEST",
+			Value: "Hello world",
+		},
+	},
+	DoubleCheck:            true,
+	UseGlobalAlertSettings: false,
+	AlertSettings: checkly.AlertSettings{
+		EscalationType: checkly.RunBased,
+		RunBasedEscalation: checkly.RunBasedEscalation{
+			FailedRunThreshold: 1,
+		},
+		Reminders: checkly.Reminders{
+			Amount:   0,
+			Interval: 5,
+		},
+	},
+	LocalSetupScript:          "setup-test",
+	LocalTearDownScript:       "teardown-test",
+	AlertChannelSubscriptions: []checkly.AlertChannelSubscription{},
+}
+
+func TestAccCheckGroupEmptyConfig(t *testing.T) {
+	config := `resource "checkly_check_group" "test" {}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "name" is required`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "concurrency" is required`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "activated" is required`),
+			},
+		},
+	})
+}
+
+func TestAccCheckGroupInvalid(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      testCheckGroup_invalid,
+				ExpectError: regexp.MustCompile(`Inappropriate value for attribute "locations"`),
+			},
+			{
+				Config:      testCheckGroup_invalid,
+				ExpectError: regexp.MustCompile(`Inappropriate value for attribute "muted"`),
+			},
+			{
+				Config:      testCheckGroup_invalid,
+				ExpectError: regexp.MustCompile(`Inappropriate value for attribute "activated"`),
+			},
+			{
+				Config:      testCheckGroup_invalid,
+				ExpectError: regexp.MustCompile(`The argument "concurrency" is required`),
+			},
+			{
+				Config:      testCheckGroup_invalid,
+				ExpectError: regexp.MustCompile(`Missing required argument`),
+			},
+		},
+	})
+}
+
+func TestAccCheckGroupBasic(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: testCheckGroup_basic,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"name",
+						"test",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"activated",
+						"true",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"muted",
+						"false",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"concurrency",
+						"3",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"locations.#",
+						"2",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"locations.*",
+						"us-east-1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"locations.*",
+						"eu-central-1",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccCheckGroupWithApiDefaults(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: testCheckGroup_withApiDefaults,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"name",
+						"test",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.*.url",
+						"http://api.example.com/",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccCheckGroupFull(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: testCheckGroup_full,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"name",
+						"test",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"activated",
+						"true",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"muted",
+						"false",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"concurrency",
+						"3",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"double_check",
+						"true",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"use_global_alert_settings",
+						"false",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"locations.#",
+						"2",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"locations.*",
+						"us-east-1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"locations.*",
+						"eu-central-1",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check_group.test",
+						"environment_variables.FOO",
+						"BAR",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"alert_settings.*.escalation_type",
+						"RUN_BASED",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"alert_settings.*.reminders.#",
+						"1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"alert_settings.*.reminders.*.amount",
+						"2",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"alert_settings.*.reminders.*.interval",
+						"5",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"alert_settings.*.run_based_escalation.#",
+						"1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"alert_settings.*.run_based_escalation.*.failed_run_threshold",
+						"1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.#",
+						"1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.*.assertion.#",
+						"1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.*.assertion.*.comparison",
+						"EQUALS",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.*.assertion.*.property",
+						"",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.*.assertion.*.source",
+						"STATUS_CODE",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.*.assertion.*.target",
+						"200",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.*.basic_auth.#",
+						"1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.*.basic_auth.*.password",
+						"pass",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.*.basic_auth.*.username",
+						"user",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.*.headers.X-Test",
+						"foo",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.*.query_parameters.query",
+						"foo",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check_group.test",
+						"api_check_defaults.*.url",
+						"http://example.com/",
+					),
+				),
+			},
+		},
+	})
+}
+
+const testCheckGroup_invalid = `
+	resource "checkly_check_group" "test" {
+		name = "test"
+		activated = "invalid"
+		muted = "invalid"
+		locations = "invalid"
+	}
+`
+
+const testCheckGroup_basic = `
+	resource "checkly_check_group" "test" {
+		name        = "test"
+		activated   = true
+		muted       = false
+		concurrency = 3
+		locations   = [
+			"us-east-1",
+			"eu-central-1",
+		]
+	}
+`
+
+const testCheckGroup_withApiDefaults = `
+	resource "checkly_check_group" "test" {
+		name        = "test"
+		activated   = true
+		muted       = false
+		concurrency = 3
+		locations   = [
+			"eu-west-1",
+			"eu-west-2"
+		]
+		api_check_defaults = {
+			url = "http://api.example.com/"
+		}
+	}
+`
+
+const testCheckGroup_full = `
+  resource "checkly_check_group" "test" {
+	name                      = "test"
+	activated                 = true
+	muted                     = false
+	concurrency               = 3
+	double_check              = true
+	use_global_alert_settings = false
+	locations = [ "us-east-1", "eu-central-1" ]
+	api_check_defaults = {
+	  url = "http://example.com/"
+	  headers = {
+		X-Test = "foo"
+	  }
+	  query_parameters = {
+		query = "foo"
+	  }
+	  assertion = {
+		source     = "STATUS_CODE"
+		property   = ""
+		comparison = "EQUALS"
+		target     = "200"
+	  }
+	  basic_auth = {
+		username = "user"
+		password = "pass"
+	  }
+	}
+	environment_variables = {
+	  FOO = "BAR"
+	}
+	alert_settings = {
+	  escalation_type = "RUN_BASED"
+	  run_based_escalation = {
+		failed_run_threshold = 1
+	  }
+	  reminders = {
+		amount   = 2
+		interval = 5
+	  }
+		parallel_run_failure_threshold = {
+		enabled = false
+		percentage = 10
+		}
+	}
+	local_setup_script    = "setup-test"
+	local_teardown_script = "teardown-test"
+  }
+`
diff --git a/internal/provider/resources/check_resource.go b/internal/provider/resources/check_resource.go
new file mode 100644
index 0000000..69e406b
--- /dev/null
+++ b/internal/provider/resources/check_resource.go
@@ -0,0 +1,594 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/int32validator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/mapvalidator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"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/resource/schema/int32default"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/resources/attributes"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ resource.Resource                = (*CheckResource)(nil)
+	_ resource.ResourceWithConfigure   = (*CheckResource)(nil)
+	_ resource.ResourceWithImportState = (*CheckResource)(nil)
+)
+
+type CheckResource struct {
+	client checkly.Client
+}
+
+func NewCheckResource() resource.Resource {
+	return &CheckResource{}
+}
+
+func (r *CheckResource) Metadata(
+	ctx context.Context,
+	req resource.MetadataRequest,
+	resp *resource.MetadataResponse,
+) {
+	resp.TypeName = req.ProviderTypeName + "_check"
+}
+
+func (r *CheckResource) Schema(
+	ctx context.Context,
+	req resource.SchemaRequest,
+	resp *resource.SchemaResponse,
+) {
+	resp.Schema = schema.Schema{
+		Description: "Check groups allow you to group together a set of related checks, which can also share default settings for various attributes.",
+		Attributes: map[string]schema.Attribute{
+			"id": attributes.IDAttributeSchema,
+			"name": schema.StringAttribute{
+				Required:    true,
+				Description: "The name of the check.",
+			},
+			"type": schema.StringAttribute{
+				Required: true,
+				Validators: []validator.String{
+					stringvalidator.OneOf(
+						"API",
+						"BROWSER",
+						"MULTI_STEP",
+					),
+				},
+				Description: "The type of the check. Possible values are `API`, `BROWSER`, and `MULTI_STEP`.",
+			},
+			"frequency": schema.Int32Attribute{
+				Required: true,
+				Validators: []validator.Int32{
+					int32validator.OneOf(0, 1, 2, 5, 10, 15, 30, 60, 120, 180, 360, 720, 1440),
+					// TODO: can only be 0 if type == API
+				},
+				Description: "The frequency in minutes to run the check. Possible values are `0`, `1`, `2`, `5`, `10`, `15`, `30`, `60`, `120`, `180`, `360`, `720`, and `1440`.",
+			},
+			"frequency_offset": schema.Int32Attribute{
+				Optional: true,
+				Validators: []validator.Int32{
+					int32validator.OneOf(10, 20, 30), // TODO: Are these the only values?
+					// TODO: can only be set if frequency == 0
+				},
+				Description: "This property is only valid for high frequency API checks. To create a high frequency check, the property `frequency` must be `0` and `frequency_offset` could be `10`, `20` or `30`.",
+			},
+			"activated": schema.BoolAttribute{
+				Required:    true,
+				Description: "Determines if the check is running or not. Possible values `true`, and `false`.",
+			},
+			"muted": schema.BoolAttribute{
+				Optional:    true,
+				Description: "Determines if any notifications will be sent out when a check fails/degrades/recovers.",
+			},
+			"should_fail": schema.BoolAttribute{
+				Optional:    true,
+				Description: "Allows to invert the behaviour of when a check is considered to fail. Allows for validating error status like 404.",
+			},
+			"run_parallel": schema.BoolAttribute{
+				Optional:    true,
+				Description: "Determines if the check should run in all selected locations in parallel or round-robin.",
+			},
+			"locations": schema.SetAttribute{
+				ElementType: types.StringType,
+				Optional:    true,
+				Description: "An array of one or more data center locations where to run the checks.",
+			},
+			"private_locations": attributes.PrivateLocationsAttributeSchema,
+			"script": schema.StringAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     stringdefault.StaticString(""),
+				Description: "A valid piece of Node.js JavaScript code describing a browser interaction with the Puppeteer/Playwright framework or a reference to an external JavaScript file.",
+			},
+			"degraded_response_time": schema.Int32Attribute{
+				Optional: true,
+				Computed: true,
+				Default:  int32default.StaticInt32(15000),
+				Validators: []validator.Int32{
+					int32validator.Between(0, 30000),
+				},
+				Description: "The response time in milliseconds starting from which a check should be considered degraded. Possible values are between 0 and 30000. (Default `15000`).",
+			},
+			"max_response_time": schema.Int32Attribute{
+				Optional: true,
+				Computed: true,
+				Default:  int32default.StaticInt32(30000),
+				Validators: []validator.Int32{
+					int32validator.Between(0, 30000),
+				},
+				Description: "The response time in milliseconds starting from which a check should be considered failing. Possible values are between 0 and 30000. (Default `30000`).",
+			},
+			"environment_variables": schema.MapAttribute{
+				ElementType: types.StringType,
+				Validators: []validator.Map{
+					mapvalidator.ConflictsWith(
+						path.MatchRelative().AtParent().AtName("environment_variable"),
+					),
+				},
+				Optional:           true,
+				Description:        "Key/value pairs for setting environment variables during check execution. These are only relevant for browser checks. Use global environment variables whenever possible.",
+				DeprecationMessage: "The property `environment_variables` is deprecated and will be removed in a future version. Consider using the new `environment_variable` list.",
+			},
+			"environment_variable": attributes.EnvironmentVariableAttributeSchema,
+			"double_check": schema.BoolAttribute{
+				Optional:           true,
+				Description:        "Setting this to `true` will trigger a retry when a check fails from the failing region and another, randomly selected region before marking the check as failed.",
+				DeprecationMessage: "The property `double_check` is deprecated and will be removed in a future version. To enable retries for failed check runs, use the `retry_strategy` property instead.",
+			},
+			"tags": schema.SetAttribute{
+				ElementType: types.StringType,
+				Optional:    true,
+				Description: "Tags for organizing and filtering checks.",
+			},
+			"ssl_check": schema.BoolAttribute{
+				Optional:           true,
+				Description:        "Determines if the SSL certificate should be validated for expiry.",
+				DeprecationMessage: "The property `ssl_check` is deprecated and it's ignored by the Checkly Public API. It will be removed in a future version.",
+			},
+			"ssl_check_domain": schema.StringAttribute{
+				Optional:   true,
+				Validators: []validator.String{
+					// TODO: can only be set if type == BROWSER
+				},
+				Description: "A valid fully qualified domain name (FQDN) to check its SSL certificate.",
+			},
+			"setup_snippet_id": schema.Int64Attribute{
+				Optional:    true,
+				Description: "An ID reference to a snippet to use in the setup phase of an API check.",
+			},
+			"teardown_snippet_id": schema.Int64Attribute{
+				Optional:    true,
+				Description: "An ID reference to a snippet to use in the teardown phase of an API check.",
+			},
+			"local_setup_script": schema.StringAttribute{
+				Optional:    true,
+				Description: "A valid piece of Node.js code to run in the setup phase.",
+			},
+			"local_teardown_script": schema.StringAttribute{
+				Optional:    true,
+				Description: "A valid piece of Node.js code to run in the teardown phase.",
+			},
+			"runtime_id": schema.StringAttribute{
+				Optional:    true,
+				Description: "The id of the runtime to use for this check.",
+				// TODO: If type == MULTI_STEP, use GetRuntime to check whether
+				// the runtime supports MULTI_STEP
+			},
+			"alert_channel_subscription": attributes.AlertChannelSubscriptionAttributeSchema,
+			"alert_settings":             attributes.AlertSettingsAttributeSchema,
+			"use_global_alert_settings": schema.BoolAttribute{
+				Optional:    true,
+				Description: "When true, the account level alert settings will be used, not the alert setting defined on this check.",
+			},
+			"request": attributes.RequestAttributeSchema, // TODO: can only be set if type == API
+			"group_id": schema.Int64Attribute{
+				Optional:    true,
+				Description: "The id of the check group this check is part of.",
+			},
+			"group_order": schema.Int32Attribute{
+				Optional:    true,
+				Description: "The position of this check in a check group. It determines in what order checks are run when a group is triggered from the API or from CI/CD.",
+			},
+			"retry_strategy": attributes.RetryStrategyAttributeSchema,
+		},
+	}
+}
+
+func (r *CheckResource) Configure(
+	ctx context.Context,
+	req resource.ConfigureRequest,
+	resp *resource.ConfigureResponse,
+) {
+	client, diags := interop.ClientFromProviderData(req.ProviderData)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	r.client = client
+}
+
+func (r *CheckResource) ImportState(
+	ctx context.Context,
+	req resource.ImportStateRequest,
+	resp *resource.ImportStateResponse,
+) {
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *CheckResource) Create(
+	ctx context.Context,
+	req resource.CreateRequest,
+	resp *resource.CreateResponse,
+) {
+	var plan CheckResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.Check
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.CreateCheck(ctx, desiredModel)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Creating Checkly Check",
+			fmt.Sprintf("Could not create check, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Created)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *CheckResource) Delete(
+	ctx context.Context,
+	req resource.DeleteRequest,
+	resp *resource.DeleteResponse,
+) {
+	var state CheckResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	err := r.client.DeleteCheck(ctx, state.ID.ValueString())
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Deleting Checkly Check",
+			fmt.Sprintf("Could not delete check, unexpected error: %s", err),
+		)
+
+		return
+	}
+}
+
+func (r *CheckResource) Read(
+	ctx context.Context,
+	req resource.ReadRequest,
+	resp *resource.ReadResponse,
+) {
+	var state CheckResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.GetCheck(ctx, state.ID.ValueString())
+	if err != nil {
+		if sdkutil.IsHTTPNotFoundError(err) {
+			resp.State.RemoveResource(ctx)
+			return
+		}
+
+		resp.Diagnostics.AddError(
+			"Error Reading Checkly Check",
+			fmt.Sprintf("Could not retrieve check, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(state.Refresh(ctx, realizedModel, interop.Loaded)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *CheckResource) Update(
+	ctx context.Context,
+	req resource.UpdateRequest,
+	resp *resource.UpdateResponse,
+) {
+	var plan CheckResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.Check
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.UpdateCheck(
+		ctx,
+		plan.ID.ValueString(),
+		desiredModel,
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Updating Checkly Check",
+			fmt.Sprintf("Could not update check, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Updated)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+var (
+	_ interop.Model[checkly.Check] = (*CheckResourceModel)(nil)
+)
+
+type CheckResourceModel struct {
+	ID                        types.String `tfsdk:"id"`
+	Name                      types.String `tfsdk:"name"`
+	Type                      types.String `tfsdk:"type"`
+	Frequency                 types.Int32  `tfsdk:"frequency"`
+	FrequencyOffset           types.Int32  `tfsdk:"frequency_offset"`
+	Activated                 types.Bool   `tfsdk:"activated"`
+	Muted                     types.Bool   `tfsdk:"muted"`
+	ShouldFail                types.Bool   `tfsdk:"should_fail"`
+	RunParallel               types.Bool   `tfsdk:"run_parallel"`
+	Locations                 types.Set    `tfsdk:"locations"`
+	PrivateLocations          types.Set    `tfsdk:"private_locations"`
+	Script                    types.String `tfsdk:"script"`
+	DegradedResponseTime      types.Int32  `tfsdk:"degraded_response_time"`
+	MaxResponseTime           types.Int32  `tfsdk:"max_response_time"`
+	EnvironmentVariables      types.Map    `tfsdk:"environment_variables"`
+	EnvironmentVariable       types.List   `tfsdk:"environment_variable"`
+	DoubleCheck               types.Bool   `tfsdk:"double_check"`
+	Tags                      types.Set    `tfsdk:"tags"`
+	SSLCheck                  types.Bool   `tfsdk:"ssl_check"`
+	SSLCheckDomain            types.String `tfsdk:"ssl_check_domain"`
+	SetupSnippetID            types.Int64  `tfsdk:"setup_snippet_id"`
+	TearDownSnippetID         types.Int64  `tfsdk:"teardown_snippet_id"`
+	LocalSetupScript          types.String `tfsdk:"local_setup_script"`
+	LocalTearDownScript       types.String `tfsdk:"local_teardown_script"`
+	RuntimeID                 types.String `tfsdk:"runtime_id"`
+	AlertChannelSubscriptions types.List   `tfsdk:"alert_channel_subscription"`
+	AlertSettings             types.Object `tfsdk:"alert_settings"`
+	UseGlobalAlertSettings    types.Bool   `tfsdk:"use_global_alert_settings"`
+	Request                   types.Object `tfsdk:"request"`
+	GroupID                   types.Int64  `tfsdk:"group_id"`
+	GroupOrder                types.Int32  `tfsdk:"group_order"`
+	RetryStrategy             types.Object `tfsdk:"retry_strategy"`
+}
+
+func (m *CheckResourceModel) Refresh(ctx context.Context, from *checkly.Check, flags interop.RefreshFlags) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	if flags.Created() {
+		m.ID = types.StringValue(from.ID)
+	}
+
+	m.Name = types.StringValue(from.Name)
+	m.Type = types.StringValue(from.Type)
+	m.Frequency = types.Int32Value(int32(from.Frequency))
+	m.FrequencyOffset = types.Int32Value(int32(from.FrequencyOffset))
+	m.Activated = types.BoolValue(from.Activated)
+	m.Muted = types.BoolValue(from.Muted)
+	m.ShouldFail = types.BoolValue(from.ShouldFail)
+	m.RunParallel = types.BoolValue(from.RunParallel)
+
+	m.Locations, _, diags = attributes.LocationsAttributeGluer.RefreshToSet(ctx, &from.Locations, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.PrivateLocations, _, diags = attributes.PrivateLocationsAttributeGluer.RefreshToSet(ctx, from.PrivateLocations, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.Script = types.StringValue(from.Script)
+	m.DegradedResponseTime = types.Int32Value(int32(from.DegradedResponseTime))
+	m.MaxResponseTime = types.Int32Value(int32(from.MaxResponseTime))
+
+	if !m.EnvironmentVariables.IsNull() {
+		// Deprecated mode.
+		m.EnvironmentVariables = types.MapNull(types.StringType)
+
+		// TODO either implement backwards compat or remove.
+	} else {
+		m.EnvironmentVariable, _, diags = attributes.EnvironmentVariableAttributeGluer.RefreshToList(ctx, &from.EnvironmentVariables, flags)
+		if diags.HasError() {
+			return diags
+		}
+	}
+
+	m.DoubleCheck = types.BoolValue(from.DoubleCheck)
+
+	m.Tags = interop.IntoUntypedStringSet(&from.Tags)
+
+	m.SSLCheck = types.BoolValue(from.SSLCheck)
+	m.SSLCheckDomain = types.StringValue(from.SSLCheckDomain)
+
+	m.SetupSnippetID = types.Int64Value(from.SetupSnippetID)
+	m.TearDownSnippetID = types.Int64Value(from.TearDownSnippetID)
+	m.LocalSetupScript = types.StringValue(from.LocalSetupScript)
+	m.LocalTearDownScript = types.StringValue(from.LocalTearDownScript)
+
+	if from.RuntimeID != nil {
+		m.RuntimeID = types.StringValue(*from.RuntimeID)
+	} else {
+		m.RuntimeID = types.StringNull()
+	}
+
+	m.AlertChannelSubscriptions, _, diags = attributes.AlertChannelSubscriptionAttributeGluer.RefreshToList(ctx, &from.AlertChannelSubscriptions, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.AlertSettings, _, diags = attributes.AlertSettingsAttributeGluer.RefreshToObject(ctx, &from.AlertSettings, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.UseGlobalAlertSettings = types.BoolValue(from.UseGlobalAlertSettings)
+
+	m.Request, _, diags = attributes.RequestAttributeGluer.RefreshToObject(ctx, &from.Request, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.GroupID = types.Int64Value(from.GroupID)
+	m.GroupOrder = types.Int32Value(int32(from.GroupOrder))
+
+	m.RetryStrategy, _, diags = attributes.RetryStrategyAttributeGluer.RefreshToObject(ctx, from.RetryStrategy, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	return nil
+}
+
+func (m *CheckResourceModel) Render(ctx context.Context, into *checkly.Check) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	into.Name = m.Name.ValueString()
+	into.Type = m.Type.ValueString()
+	into.Frequency = int(m.Frequency.ValueInt32())
+	into.FrequencyOffset = int(m.FrequencyOffset.ValueInt32())
+	into.Activated = m.Activated.ValueBool()
+	into.Muted = m.Muted.ValueBool()
+	into.ShouldFail = m.ShouldFail.ValueBool()
+	into.RunParallel = m.RunParallel.ValueBool()
+
+	into.Locations, _, diags = attributes.LocationsAttributeGluer.RenderFromSet(ctx, m.Locations)
+	if diags.HasError() {
+		return diags
+	}
+
+	privateLocations, _, diags := attributes.PrivateLocationsAttributeGluer.RenderFromSet(ctx, m.PrivateLocations)
+	if diags.HasError() {
+		return diags
+	}
+
+	into.PrivateLocations = &privateLocations
+
+	into.Script = m.Script.ValueString()
+	into.DegradedResponseTime = int(m.DegradedResponseTime.ValueInt32())
+	into.MaxResponseTime = int(m.MaxResponseTime.ValueInt32())
+
+	if !m.EnvironmentVariables.IsNull() {
+		// Deprecated mode.
+		into.EnvironmentVariables = nil
+
+		// TODO either implement backwards compat or remove.
+	} else {
+		into.EnvironmentVariables = nil
+
+		into.EnvironmentVariables, _, diags = attributes.EnvironmentVariableAttributeGluer.RenderFromList(ctx, m.EnvironmentVariable)
+		if diags.HasError() {
+			return diags
+		}
+	}
+
+	into.DoubleCheck = m.DoubleCheck.ValueBool()
+
+	into.Tags = interop.FromUntypedStringSet(m.Tags)
+
+	into.SSLCheck = m.SSLCheck.ValueBool()
+	into.SSLCheckDomain = m.SSLCheckDomain.ValueString()
+
+	into.SetupSnippetID = m.SetupSnippetID.ValueInt64()
+	into.TearDownSnippetID = m.TearDownSnippetID.ValueInt64()
+	into.LocalSetupScript = m.LocalSetupScript.ValueString()
+	into.LocalTearDownScript = m.LocalTearDownScript.ValueString()
+
+	if !m.RuntimeID.IsNull() {
+		value := m.RuntimeID.ValueString()
+		into.RuntimeID = &value
+	} else {
+		into.RuntimeID = nil
+	}
+
+	into.AlertChannelSubscriptions, _, diags = attributes.AlertChannelSubscriptionAttributeGluer.RenderFromList(ctx, m.AlertChannelSubscriptions)
+	if diags.HasError() {
+		return diags
+	}
+
+	into.AlertSettings, _, diags = attributes.AlertSettingsAttributeGluer.RenderFromObject(ctx, m.AlertSettings)
+	if diags.HasError() {
+		return diags
+	}
+
+	into.UseGlobalAlertSettings = m.UseGlobalAlertSettings.ValueBool()
+
+	into.Request, _, diags = attributes.RequestAttributeGluer.RenderFromObject(ctx, m.Request)
+	if diags.HasError() {
+		return diags
+	}
+
+	into.GroupID = m.GroupID.ValueInt64()
+	into.GroupOrder = int(m.GroupOrder.ValueInt32())
+
+	if m.RetryStrategy.IsNull() || m.RetryStrategy.IsUnknown() {
+		into.RetryStrategy = nil
+	} else {
+		retryStrategy, _, diags := attributes.RetryStrategyAttributeGluer.RenderFromObject(ctx, m.RetryStrategy)
+		if diags.HasError() {
+			return diags
+		}
+
+		into.RetryStrategy = &retryStrategy
+	}
+
+	return nil
+}
diff --git a/internal/provider/resources/check_resource_test.go b/internal/provider/resources/check_resource_test.go
new file mode 100644
index 0000000..211deef
--- /dev/null
+++ b/internal/provider/resources/check_resource_test.go
@@ -0,0 +1,717 @@
+package resources_test
+
+import (
+	"net/http"
+	"regexp"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+
+	"github.com/checkly/checkly-go-sdk"
+)
+
+func TestAccCheckRequiredFields(t *testing.T) {
+	config := `resource "checkly_check" "test" {}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "type" is required, but no definition was found.`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "name" is required, but no definition was found.`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "activated" is required, but no definition was found.`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "frequency" is required, but no definition was found.`),
+			},
+		},
+	})
+}
+
+func TestAccBrowserCheckInvalidInputs(t *testing.T) {
+	config := `resource "checkly_check" "test" {
+		name                      = 1
+		type                      = "BROWSER"
+		activated                 = "invalid"
+		should_fail               = "invalid"
+		double_check              = "invalid"
+		use_global_alert_settings = "invalid"
+		locations = "invalid"
+		script = 4
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`Inappropriate value for attribute "activated"`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "frequency" is required`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`Inappropriate value for attribute "should_fail"`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`Inappropriate value for attribute "use_global_alert_settings"`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`Inappropriate value for attribute "double_check"`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`Inappropriate value for attribute "locations"`),
+			},
+		},
+	})
+}
+
+func TestAccBrowserCheckMissingScript(t *testing.T) {
+	config := `resource "checkly_check" "test" {
+		type = "BROWSER"
+		activated = true
+		frequency = 10
+		name = "browser check"
+		locations = [ "us-west-1" ]
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`API error 1: unexpected response status 400`),
+			},
+		},
+	})
+}
+
+func TestAccBrowserCheckBasic(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: browserCheck_basic,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"name",
+						"Browser Check",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"type",
+						"BROWSER",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"activated",
+						"true",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"script",
+						"console.log('test')",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"locations.#",
+						"2",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"locations.*",
+						"us-east-1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"locations.*",
+						"eu-central-1",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"tags.#",
+						"2",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"tags.*",
+						"browser",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"tags.*",
+						"e2e",
+					),
+					resource.TestCheckNoResourceAttr(
+						"checkly_check.test",
+						"request",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccApiCheckBasic(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: apiCheck_basic,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"name",
+						"API Check 1",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"activated",
+						"true",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"locations.*",
+						"eu-central-1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"locations.*",
+						"us-east-1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.method",
+						"GET",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.url",
+						"https://api.checklyhq.com/public-stats",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.assertion.*.comparison",
+						"EQUALS",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.assertion.*.property",
+						"",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.assertion.*.source",
+						"STATUS_CODE",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.assertion.*.target",
+						"200",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccMultiStepCheckRuntimeValidation(t *testing.T) {
+	unsupportedRuntime := `resource "checkly_check" "test" {
+		name = "test"
+		type = "MULTI_STEP"
+		activated = true
+		frequency = 5
+		locations = ["eu-central-1"]
+		script = "console.log('test')"
+		runtime_id = "2023.02"
+	}`
+	noSpecifiedRuntime := `resource "checkly_check" "test" {
+		name = "test"
+		type = "MULTI_STEP"
+		activated = true
+		frequency = 5
+		locations = ["eu-central-1"]
+		script = "console.log('test')"
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      unsupportedRuntime,
+				ExpectError: regexp.MustCompile("Error: runtime 2023.02 does not support MULTI_STEP checks"),
+			},
+			{
+				Config: noSpecifiedRuntime,
+				Check: resource.TestCheckNoResourceAttr(
+					"checkly_check.test",
+					"runtime_id",
+				),
+			},
+		},
+	})
+}
+
+func TestAccMultiStepCheckBasic(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: multiStepCheck_basic,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"name",
+						"MultiStep Check",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"type",
+						"MULTI_STEP",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"runtime_id",
+						"2023.09",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"activated",
+						"true",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"script",
+						"console.log('test')",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"locations.#",
+						"2",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"locations.*",
+						"us-east-1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"locations.*",
+						"eu-central-1",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"tags.#",
+						"2",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"tags.*",
+						"browser",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"tags.*",
+						"e2e",
+					),
+					resource.TestCheckNoResourceAttr(
+						"checkly_check.test",
+						"request",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccApiCheckFull(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: apiCheck_full,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"degraded_response_time",
+						"15000",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"max_response_time",
+						"30000",
+					),
+					resource.TestCheckNoResourceAttr(
+						"checkly_check.test",
+						"environment_variables",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						`"locations.#"`,
+						"3",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						`"request.*.headers.X-CUSTOM-1"`,
+						"1",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.headers.X-CUSTOM-2",
+						"FOO",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.query_parameters.param1",
+						"123",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.query_parameters.param2",
+						"bar",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.basic_auth.*.username",
+						"user",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.basic_auth.*.password",
+						"pass",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.assertion.#",
+						"3",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.assertion.*.comparison",
+						"EQUALS",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.assertion.*.comparison",
+						"GREATER_THAN",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.assertion.*.target",
+						"200",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.assertion.*.target",
+						"no-cache",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.assertion.*.target",
+						"100",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccApiCheckMore(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: apiCheck_post,
+				Check: resource.ComposeTestCheckFunc(
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.method",
+						"POST",
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.body",
+						`{\"message\":\"hello checkly\",\"messageId\":1}`,
+					),
+					testCheckResourceAttrExpr(
+						"checkly_check.test",
+						"request.*.body_type",
+						"JSON",
+					),
+				),
+			},
+			{
+				Config: apiCheck_withEmptyBasicAuth,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_check.test",
+						"name",
+						"api check with empty basic_auth",
+					),
+				),
+			},
+		},
+	})
+}
+
+var wantCheck = checkly.Check{
+	Name:                 "My test check",
+	Type:                 checkly.TypeAPI,
+	Frequency:            1,
+	Activated:            true,
+	Muted:                false,
+	ShouldFail:           false,
+	Locations:            []string{"eu-west-1"},
+	PrivateLocations:     &[]string{},
+	Script:               "foo",
+	DegradedResponseTime: 15000,
+	MaxResponseTime:      30000,
+	EnvironmentVariables: []checkly.EnvironmentVariable{
+		{
+			Key:   "ENVTEST",
+			Value: "Hello world",
+		},
+	},
+	DoubleCheck: false,
+	Tags: []string{
+		"foo",
+		"bar",
+	},
+	SSLCheck:            false,
+	LocalSetupScript:    "bogus",
+	LocalTearDownScript: "bogus",
+	AlertSettings: checkly.AlertSettings{
+		EscalationType: checkly.RunBased,
+		RunBasedEscalation: checkly.RunBasedEscalation{
+			FailedRunThreshold: 1,
+		},
+		Reminders: checkly.Reminders{
+			Interval: 5,
+		},
+	},
+	UseGlobalAlertSettings: false,
+	Request: checkly.Request{
+		Method: http.MethodGet,
+		URL:    "http://example.com",
+		Headers: []checkly.KeyValue{
+			{
+				Key:   "X-Test",
+				Value: "foo",
+			},
+		},
+		QueryParameters: []checkly.KeyValue{
+			{
+				Key:   "query",
+				Value: "foo",
+			},
+		},
+		Assertions: []checkly.Assertion{
+			{
+				Source:     checkly.StatusCode,
+				Comparison: checkly.Equals,
+				Target:     "200",
+			},
+		},
+		Body:     "",
+		BodyType: "NONE",
+		BasicAuth: &checkly.BasicAuth{
+			Username: "example",
+			Password: "pass",
+		},
+	},
+}
+
+const browserCheck_basic = `
+	resource "checkly_check" "test" {
+		name                      = "Browser Check"
+		type                      = "BROWSER"
+		activated                 = true
+		should_fail               = false
+		frequency                 = 720
+		double_check              = true
+		use_global_alert_settings = true
+		locations                 = [ "us-east-1", "eu-central-1" ]
+		tags                      = [ "browser", "e2e" ]
+		script                    = "console.log('test')"
+	}
+`
+const multiStepCheck_basic = `
+	resource "checkly_check" "test" {
+		name                      = "MultiStep Check"
+		type                      = "MULTI_STEP"
+		activated                 = true
+		should_fail               = false
+		frequency                 = 720
+		double_check              = true
+		use_global_alert_settings = true
+		locations                 = [ "us-east-1", "eu-central-1" ]
+		tags                      = [ "api", "multi-step" ]
+		runtime_id				  = "2023.09"
+		script                    = "console.log('test')"
+	}
+`
+
+const apiCheck_basic = `
+	resource "checkly_check" "test" {
+	  name                      = "API Check 1"
+	  type                      = "API"
+	  frequency                 = 60
+	  activated                 = true
+	  muted                     = true
+	  double_check              = true
+	  max_response_time         = 18000
+	  locations                 = [ "us-east-1", "eu-central-1" ]
+	  use_global_alert_settings = true
+	  request = {
+		method     = "GET"
+		url        = "https://api.checklyhq.com/public-stats"
+		assertions = [{
+		  comparison = "EQUALS"
+		  property   = ""
+		  source     = "STATUS_CODE"
+		  target     = "200"
+		}]
+	  }
+	}
+`
+
+const apiCheck_full = `
+  resource "checkly_check" "test" {
+	name                   = "apiCheck_full"
+	type                   = "API"
+	frequency              = 120
+	activated              = true
+	muted                  = true
+	double_check           = true
+	degraded_response_time = 15000
+	max_response_time      = 30000
+	environment_variables  = null
+	locations = [
+	  "eu-central-1",
+	  "us-east-1",
+	  "ap-northeast-1"
+	]
+	request = {
+	  method           = "GET"
+	  url              = "https://api.checklyhq.com/public-stats"
+	  follow_redirects = true
+	  headers = {
+		X-CUSTOM-1 = 1
+		X-CUSTOM-2 = "foo"
+	  }
+	  query_parameters = {
+		param1 = 123
+		param2 = "bar"
+	  }
+	  basic_auth = {
+		username = "user"
+		password = "pass"
+	  }
+	  assertions = [{
+		comparison = "EQUALS"
+		property   = ""
+		source     = "STATUS_CODE"
+		target     = "200"
+	  }, {
+		comparison = "EQUALS"
+		property   = "cache-control"
+		source     = "HEADERS"
+		target     = "no-cache"
+	  }, {
+		comparison = "GREATER_THAN"
+		property   = "$.apiCheckResults"
+		source     = "JSON_BODY"
+		target     = "100"
+	  }]
+	}
+
+	alert_settings {
+	  escalation_type = "RUN_BASED"
+	  reminders = {
+		amount   = 0
+		interval = 5
+	  }
+	  run_based_escalation = {
+		failed_run_threshold = 1
+	  }
+		parallel_run_failure_threshold = {
+		enabled = false
+		percentage = 10
+		}
+	}
+  }
+`
+
+const apiCheck_post = `
+  resource "checkly_check" "test" {
+	name         = "apiCheck_post"
+	type         = "API"
+	activated    = true
+	double_check = true
+	frequency    = 720
+	locations = [ "eu-central-1", "us-east-2" ]
+	max_response_time     = 18000
+	muted                 = true
+	environment_variables = null
+	request = {
+	  method           = "POST"
+	  url              = "https://jsonplaceholder.typicode.com/posts"
+	  headers = {
+		Content-type = "application/json; charset=UTF-8"
+	  }
+	  body      = "{\"message\":\"hello checkly\",\"messageId\":1}"
+	  body_type = "JSON"
+	}
+	use_global_alert_settings = true
+  }
+`
+
+const apiCheck_withEmptyBasicAuth = `
+  resource "checkly_check" "test" {
+	name                   = "api check with empty basic_auth"
+	type                   = "API"
+	activated              = true
+	should_fail            = false
+	frequency              = 1
+	degraded_response_time = 3000
+	max_response_time      = 6000
+	tags = [
+	  "testing",
+	  "bug"
+	]
+	locations = [ "eu-central-1" ]
+	request {
+	  follow_redirects = false
+	  url              = "https://api.checklyhq.com/public-stats"
+	  basic_auth = {
+		username = ""
+		password = ""
+	  }
+	  assertions = [{
+		source     = "STATUS_CODE"
+		property   = ""
+		comparison = "EQUALS"
+		target     = "200"
+	  }]
+	}
+  }
+`
diff --git a/internal/provider/resources/dashboard_resource.go b/internal/provider/resources/dashboard_resource.go
new file mode 100644
index 0000000..969820f
--- /dev/null
+++ b/internal/provider/resources/dashboard_resource.go
@@ -0,0 +1,398 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/int32validator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"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/resource/schema/booldefault"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int32default"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/resources/attributes"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ resource.Resource                = (*DashboardResource)(nil)
+	_ resource.ResourceWithConfigure   = (*DashboardResource)(nil)
+	_ resource.ResourceWithImportState = (*DashboardResource)(nil)
+)
+
+type DashboardResource struct {
+	client checkly.Client
+}
+
+func NewDashboardResource() resource.Resource {
+	return &DashboardResource{}
+}
+
+func (r *DashboardResource) Metadata(
+	ctx context.Context,
+	req resource.MetadataRequest,
+	resp *resource.MetadataResponse,
+) {
+	resp.TypeName = req.ProviderTypeName + "_dashboard"
+}
+
+func (r *DashboardResource) Schema(
+	ctx context.Context,
+	req resource.SchemaRequest,
+	resp *resource.SchemaResponse,
+) {
+	resp.Schema = schema.Schema{
+		Attributes: map[string]schema.Attribute{
+			"id": attributes.IDAttributeSchema,
+			"custom_url": schema.StringAttribute{
+				Required:    true,
+				Description: "A subdomain name under 'checklyhq.com'. Needs to be unique across all users.",
+			},
+			"custom_domain": schema.StringAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     nil, // TODO
+				Description: "A custom user domain, e.g. 'status.example.com'. See the docs on updating your DNS and SSL usage.",
+			},
+			"logo": schema.StringAttribute{
+				Optional:    true,
+				Description: "A URL pointing to an image file to use for the dashboard logo.",
+			},
+			"favicon": schema.StringAttribute{
+				Optional:    true,
+				Description: "A URL pointing to an image file to use as browser favicon.",
+			},
+			"link": schema.StringAttribute{
+				Optional:    true,
+				Description: "A link to for the dashboard logo.",
+			},
+			"description": schema.StringAttribute{
+				Optional:    true,
+				Description: "HTML <meta> description for the dashboard.",
+			},
+			"header": schema.StringAttribute{
+				Optional:    true,
+				Description: "A piece of text displayed at the top of your dashboard.",
+			},
+			"width": schema.StringAttribute{
+				Optional: true,
+				Computed: true,
+				Default:  stringdefault.StaticString("FULL"),
+				Validators: []validator.String{
+					stringvalidator.OneOf("FULL", "960PX"),
+				},
+				Description: "Determines whether to use the full screen or focus in the center. Possible values `FULL` and `960PX`.",
+			},
+			"refresh_rate": schema.Int32Attribute{
+				Optional: true,
+				Computed: true,
+				Default:  int32default.StaticInt32(60),
+				Validators: []validator.Int32{
+					int32validator.OneOf(60, 300, 600),
+				},
+				Description: "How often to refresh the dashboard in seconds. Possible values `60`, '300' and `600`.",
+			},
+			"paginate": schema.BoolAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(true),
+				Description: "Determines if pagination is on or off.",
+			},
+			"checks_per_page": schema.Int32Attribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     int32default.StaticInt32(15),
+				Description: "Determines how many checks to show per page.",
+			},
+			"pagination_rate": schema.Int32Attribute{
+				Optional: true,
+				Computed: true,
+				Default:  int32default.StaticInt32(60),
+				Validators: []validator.Int32{
+					int32validator.OneOf(30, 60, 300),
+				},
+				Description: "How often to trigger pagination in seconds. Possible values `30`, `60` and `300`.",
+			},
+			"tags": schema.SetAttribute{
+				ElementType: types.StringType,
+				Optional:    true,
+				Description: "A list of one or more tags that filter which checks to display on the dashboard.",
+			},
+			"hide_tags": schema.BoolAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(false),
+				Description: "Show or hide the tags on the dashboard.",
+			},
+			"use_tags_and_operator": schema.BoolAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(false),
+				Description: "Set when to use AND operator for fetching dashboard tags.",
+			},
+			"is_private": schema.BoolAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(false),
+				Description: "Set your dashboard as private and generate key.",
+			},
+			"key": schema.StringAttribute{
+				Computed:    true,
+				Sensitive:   true,
+				Description: "The access key when the dashboard is private.",
+			},
+		},
+	}
+}
+
+func (r *DashboardResource) Configure(
+	ctx context.Context,
+	req resource.ConfigureRequest,
+	resp *resource.ConfigureResponse,
+) {
+	client, diags := interop.ClientFromProviderData(req.ProviderData)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	r.client = client
+}
+
+func (r *DashboardResource) ImportState(
+	ctx context.Context,
+	req resource.ImportStateRequest,
+	resp *resource.ImportStateResponse,
+) {
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *DashboardResource) Create(
+	ctx context.Context,
+	req resource.CreateRequest,
+	resp *resource.CreateResponse,
+) {
+	var plan DashboardResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.Dashboard
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.CreateDashboard(ctx, desiredModel)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Creating Checkly Dashboard",
+			fmt.Sprintf("Could not create dashboard, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Created)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *DashboardResource) Delete(
+	ctx context.Context,
+	req resource.DeleteRequest,
+	resp *resource.DeleteResponse,
+) {
+	var state DashboardResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	err := r.client.DeleteDashboard(ctx, state.ID.ValueString())
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Deleting Checkly Dashboard",
+			fmt.Sprintf("Could not delete dashboard, unexpected error: %s", err),
+		)
+
+		return
+	}
+}
+
+func (r *DashboardResource) Read(
+	ctx context.Context,
+	req resource.ReadRequest,
+	resp *resource.ReadResponse,
+) {
+	var state DashboardResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.GetDashboard(ctx, state.ID.ValueString())
+	if err != nil {
+		if sdkutil.IsHTTPNotFoundError(err) {
+			resp.State.RemoveResource(ctx)
+			return
+		}
+
+		resp.Diagnostics.AddError(
+			"Error Reading Checkly Dashboard",
+			fmt.Sprintf("Could not retrieve dashboard, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(state.Refresh(ctx, realizedModel, interop.Loaded)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *DashboardResource) Update(
+	ctx context.Context,
+	req resource.UpdateRequest,
+	resp *resource.UpdateResponse,
+) {
+	var plan DashboardResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.Dashboard
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.UpdateDashboard(
+		ctx,
+		plan.ID.ValueString(),
+		desiredModel,
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Updating Checkly Dashboard",
+			fmt.Sprintf("Could not update dashboard, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Updated)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+var (
+	_ interop.Model[checkly.Dashboard] = (*DashboardResourceModel)(nil)
+)
+
+type DashboardResourceModel struct {
+	ID                 types.String `tfsdk:"id"`
+	CustomURL          types.String `tfsdk:"custom_url"`
+	CustomDomain       types.String `tfsdk:"custom_domain"`
+	Logo               types.String `tfsdk:"logo"`
+	Favicon            types.String `tfsdk:"favicon"`
+	Link               types.String `tfsdk:"link"`
+	Description        types.String `tfsdk:"description"`
+	Header             types.String `tfsdk:"header"`
+	Width              types.String `tfsdk:"width"`
+	RefreshRate        types.Int32  `tfsdk:"refresh_rate"`
+	Paginate           types.Bool   `tfsdk:"paginate"`
+	ChecksPerPage      types.Int32  `tfsdk:"checks_per_page"`
+	PaginationRate     types.Int32  `tfsdk:"pagination_rate"`
+	Tags               types.Set    `tfsdk:"tags"`
+	HideTags           types.Bool   `tfsdk:"hide_tags"`
+	UseTagsAndOperator types.Bool   `tfsdk:"use_tags_and_operator"`
+	IsPrivate          types.Bool   `tfsdk:"is_private"`
+	Key                types.String `tfsdk:"key"`
+}
+
+func (m *DashboardResourceModel) Refresh(ctx context.Context, from *checkly.Dashboard, flags interop.RefreshFlags) diag.Diagnostics {
+	if flags.Created() {
+		m.ID = types.StringValue(from.DashboardID)
+	}
+
+	m.CustomURL = types.StringValue(from.CustomUrl)
+	m.CustomDomain = types.StringValue(from.CustomDomain)
+	m.Logo = types.StringValue(from.Logo)
+	m.Favicon = types.StringValue(from.Favicon)
+	m.Link = types.StringValue(from.Link)
+	m.Description = types.StringValue(from.Description)
+	m.Header = types.StringValue(from.Header)
+	m.Width = types.StringValue(from.Width)
+	m.RefreshRate = types.Int32Value(int32(from.RefreshRate))
+	m.Paginate = types.BoolValue(from.Paginate)
+	m.ChecksPerPage = types.Int32Value(int32(from.ChecksPerPage))
+	m.PaginationRate = types.Int32Value(int32(from.PaginationRate))
+	m.HideTags = types.BoolValue(from.HideTags)
+	m.UseTagsAndOperator = types.BoolValue(from.UseTagsAndOperator)
+	m.IsPrivate = types.BoolValue(from.IsPrivate)
+	m.Tags = interop.IntoUntypedStringSet(&from.Tags)
+
+	if from.IsPrivate {
+		if len(from.Keys) > 0 {
+			m.Key = types.StringValue(from.Keys[0].RawKey)
+		}
+	} else {
+		m.Key = types.StringNull()
+	}
+
+	return nil
+}
+
+func (m *DashboardResourceModel) Render(ctx context.Context, into *checkly.Dashboard) diag.Diagnostics {
+	into.CustomUrl = m.CustomURL.ValueString()
+	into.CustomDomain = m.CustomDomain.ValueString()
+	into.IsPrivate = m.IsPrivate.ValueBool()
+	into.Logo = m.Logo.ValueString()
+	into.Link = m.Link.ValueString()
+	into.Description = m.Description.ValueString()
+	into.Favicon = m.Favicon.ValueString()
+	into.Header = m.Header.ValueString()
+	into.Width = m.Width.ValueString()
+	into.RefreshRate = int(m.RefreshRate.ValueInt32())
+	into.ChecksPerPage = int(m.ChecksPerPage.ValueInt32())
+	into.PaginationRate = int(m.PaginationRate.ValueInt32())
+	into.Paginate = m.Paginate.ValueBool()
+	into.Tags = interop.FromUntypedStringSet(m.Tags)
+	into.HideTags = m.HideTags.ValueBool()
+	into.UseTagsAndOperator = m.UseTagsAndOperator.ValueBool()
+
+	return nil
+}
diff --git a/internal/provider/resources/environment_variable_resource.go b/internal/provider/resources/environment_variable_resource.go
new file mode 100644
index 0000000..54a149b
--- /dev/null
+++ b/internal/provider/resources/environment_variable_resource.go
@@ -0,0 +1,284 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"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/resource/schema/booldefault"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/resources/attributes"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ resource.Resource                = (*EnvironmentVariableResource)(nil)
+	_ resource.ResourceWithConfigure   = (*EnvironmentVariableResource)(nil)
+	_ resource.ResourceWithImportState = (*EnvironmentVariableResource)(nil)
+)
+
+type EnvironmentVariableResource struct {
+	client checkly.Client
+}
+
+func NewEnvironmentVariableResource() resource.Resource {
+	return &EnvironmentVariableResource{}
+}
+
+func (r *EnvironmentVariableResource) Metadata(
+	ctx context.Context,
+	req resource.MetadataRequest,
+	resp *resource.MetadataResponse,
+) {
+	resp.TypeName = req.ProviderTypeName + "_environment_variable"
+}
+
+func (r *EnvironmentVariableResource) Schema(
+	ctx context.Context,
+	req resource.SchemaRequest,
+	resp *resource.SchemaResponse,
+) {
+	resp.Schema = schema.Schema{
+		Attributes: map[string]schema.Attribute{
+			"id": attributes.IDAttributeSchema,
+			"key": schema.StringAttribute{
+				Required:    true,
+				Description: "", // TODO
+			},
+			"value": schema.StringAttribute{
+				Required:    true,
+				Sensitive:   true, // FIXME: Keep sensitive? Old code did not set it.
+				Description: "",   // TODO
+			},
+			"locked": schema.BoolAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(false),
+				Description: "", // TODO
+			},
+			"secret": schema.BoolAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(false),
+				Description: "", // TODO
+			},
+		},
+	}
+}
+
+func (r *EnvironmentVariableResource) Configure(
+	ctx context.Context,
+	req resource.ConfigureRequest,
+	resp *resource.ConfigureResponse,
+) {
+	client, diags := interop.ClientFromProviderData(req.ProviderData)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	r.client = client
+}
+
+func (r *EnvironmentVariableResource) ImportState(
+	ctx context.Context,
+	req resource.ImportStateRequest,
+	resp *resource.ImportStateResponse,
+) {
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *EnvironmentVariableResource) Create(
+	ctx context.Context,
+	req resource.CreateRequest,
+	resp *resource.CreateResponse,
+) {
+	var plan EnvironmentVariableResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.EnvironmentVariable
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.CreateEnvironmentVariable(
+		ctx,
+		desiredModel,
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Creating Checkly Environment Variable",
+			fmt.Sprintf("Could not create environment variable, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Created)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *EnvironmentVariableResource) Delete(
+	ctx context.Context,
+	req resource.DeleteRequest,
+	resp *resource.DeleteResponse,
+) {
+	var state EnvironmentVariableResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	err := r.client.DeleteEnvironmentVariable(ctx, state.ID.ValueString())
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Deleting Checkly Environment Variable",
+			fmt.Sprintf("Could not delete environment variable, unexpected error: %s", err),
+		)
+
+		return
+	}
+}
+
+func (r *EnvironmentVariableResource) Read(
+	ctx context.Context,
+	req resource.ReadRequest,
+	resp *resource.ReadResponse,
+) {
+	var state EnvironmentVariableResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.GetEnvironmentVariable(
+		ctx,
+		state.ID.ValueString(),
+	)
+	if err != nil {
+		if sdkutil.IsHTTPNotFoundError(err) {
+			resp.State.RemoveResource(ctx)
+			return
+		}
+
+		resp.Diagnostics.AddError(
+			"Error Reading Checkly Environment Variable",
+			fmt.Sprintf("Could not retrieve environment variable, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(state.Refresh(ctx, realizedModel, interop.Loaded)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *EnvironmentVariableResource) Update(
+	ctx context.Context,
+	req resource.UpdateRequest,
+	resp *resource.UpdateResponse,
+) {
+	var plan EnvironmentVariableResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.EnvironmentVariable
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.UpdateEnvironmentVariable(
+		ctx,
+		plan.ID.ValueString(),
+		desiredModel,
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Updating Checkly Environment Variable",
+			fmt.Sprintf("Could not update environment variable, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Updated)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+var (
+	_ interop.Model[checkly.EnvironmentVariable] = (*EnvironmentVariableResourceModel)(nil)
+)
+
+type EnvironmentVariableResourceModel struct {
+	ID     types.String `tfsdk:"id"`
+	Key    types.String `tfsdk:"key"`
+	Value  types.String `tfsdk:"value"`
+	Locked types.Bool   `tfsdk:"locked"`
+	Secret types.Bool   `tfsdk:"secret"`
+}
+
+func (m *EnvironmentVariableResourceModel) Refresh(ctx context.Context, from *checkly.EnvironmentVariable, flags interop.RefreshFlags) diag.Diagnostics {
+	if flags.Created() {
+		m.ID = types.StringValue(from.Key)
+	}
+
+	m.Key = types.StringValue(from.Key)
+	m.Locked = types.BoolValue(from.Locked)
+	m.Secret = types.BoolValue(from.Secret)
+
+	// We can never receive a secret value back from the server. Just assume
+	// the value is still unchanged and only update state if we're not dealing
+	// with a secret.
+	if !from.Secret {
+		m.Value = types.StringValue(from.Value)
+	}
+
+	return nil
+}
+
+func (m *EnvironmentVariableResourceModel) Render(ctx context.Context, into *checkly.EnvironmentVariable) diag.Diagnostics {
+	into.Key = m.Key.ValueString()
+	into.Value = m.Value.ValueString()
+	into.Locked = m.Locked.ValueBool()
+	into.Secret = m.Secret.ValueBool()
+
+	return nil
+}
diff --git a/internal/provider/resources/environment_variable_resource_test.go b/internal/provider/resources/environment_variable_resource_test.go
new file mode 100644
index 0000000..99bd50a
--- /dev/null
+++ b/internal/provider/resources/environment_variable_resource_test.go
@@ -0,0 +1,70 @@
+package resources_test
+
+import (
+	"regexp"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccEnvVarCheckRequiredFields(t *testing.T) {
+	config := `resource "checkly_environment_variable" "test" {}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "key" is required`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "value" is required`),
+			},
+		},
+	})
+}
+
+func TestAccEnvVarSuccess(t *testing.T) {
+	config := `resource "checkly_environment_variable" "test" {
+		key     = "API_URL"
+		value   = "https://api.checklyhq.com"
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: config,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_environment_variable.test",
+						"key",
+						"API_URL",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_environment_variable.test",
+						"value",
+						"https://api.checklyhq.com",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccSecretEnvVarSuccess(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "checkly_environment_variable" "test" {
+				key     = "SECRET"
+				value   = "https://api.checklyhq.com"
+				secret  = true
+			}`,
+			},
+		},
+	})
+}
diff --git a/internal/provider/resources/heartbeat_resource.go b/internal/provider/resources/heartbeat_resource.go
new file mode 100644
index 0000000..d9ec591
--- /dev/null
+++ b/internal/provider/resources/heartbeat_resource.go
@@ -0,0 +1,489 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+	"slices"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag"
+	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"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/resource/schema/booldefault"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/resources/attributes"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ resource.Resource                   = (*HeartbeatResource)(nil)
+	_ resource.ResourceWithConfigure      = (*HeartbeatResource)(nil)
+	_ resource.ResourceWithImportState    = (*HeartbeatResource)(nil)
+	_ resource.ResourceWithValidateConfig = (*HeartbeatResource)(nil)
+)
+
+type HeartbeatResource struct {
+	client checkly.Client
+}
+
+func NewHeartbeatResource() resource.Resource {
+	return &HeartbeatResource{}
+}
+
+func (r *HeartbeatResource) Metadata(
+	ctx context.Context,
+	req resource.MetadataRequest,
+	resp *resource.MetadataResponse,
+) {
+	resp.TypeName = req.ProviderTypeName + "_heartbeat"
+}
+
+func (r *HeartbeatResource) Schema(
+	ctx context.Context,
+	req resource.SchemaRequest,
+	resp *resource.SchemaResponse,
+) {
+	resp.Schema = schema.Schema{
+		Description: "Heartbeats allows you to monitor your cron jobs and set up alerting, so you get a notification when things break or slow down.",
+		Attributes: map[string]schema.Attribute{
+			"id": attributes.IDAttributeSchema,
+			"name": schema.StringAttribute{
+				Description: "The name of the check.",
+				Required:    true,
+			},
+			"activated": schema.BoolAttribute{
+				Description: "Determines if the check is running or not. Possible values `true`, and `false`.",
+				Required:    true,
+			},
+			"muted": schema.BoolAttribute{
+				Description: "Determines if any notifications will be sent out when a check fails/degrades/recovers.",
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(false),
+			},
+			"tags": schema.SetAttribute{
+				Description: "A list of tags for organizing and filtering checks.",
+				ElementType: types.StringType,
+				Optional:    true,
+				Computed:    true,
+			},
+			"alert_settings": attributes.AlertSettingsAttributeSchema,
+			"use_global_alert_settings": schema.BoolAttribute{
+				Description: "When true, the account level alert settings will be used, not the alert setting defined on this check.",
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(false),
+			},
+			"heartbeat":                  HeartbeatAttributeSchema,
+			"alert_channel_subscription": attributes.AlertChannelSubscriptionAttributeSchema,
+		},
+	}
+}
+
+func valueWithUnitToSeconds(value int32, unit string) int32 {
+	switch unit {
+	case "seconds":
+		return value * 1
+	case "minutes":
+		return value * 60
+	case "hours":
+		return value * 3600
+	case "days":
+		return value * 3600 * 24
+	default:
+		return 0
+	}
+}
+
+func (r *HeartbeatResource) ValidateConfig(
+	ctx context.Context,
+	req resource.ValidateConfigRequest,
+	resp *resource.ValidateConfigResponse,
+) {
+	var config HeartbeatResourceModel
+
+	resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	_, heartbeatAttributeModel, diags := HeartbeatAttributeGluer.RenderFromObject(ctx, config.Heartbeat)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	if !heartbeatAttributeModel.Period.IsUnknown() && !heartbeatAttributeModel.PeriodUnit.IsUnknown() {
+		value := heartbeatAttributeModel.Period.ValueInt32()
+		valuePath := path.Root("heartbeat").AtName("period")
+
+		unit := heartbeatAttributeModel.PeriodUnit.ValueString()
+		unitPath := path.Root("heartbeat").AtName("period_unit")
+
+		seconds := valueWithUnitToSeconds(value, unit)
+
+		if seconds < 30 {
+			resp.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic(
+				valuePath,
+				fmt.Sprintf(`value in combination with %s must be greater than or equal to 30s`, unitPath.String()),
+				fmt.Sprintf("%d %s", value, unit),
+			))
+		}
+
+		if seconds > 3600*24*365 {
+			resp.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic(
+				valuePath,
+				fmt.Sprintf(`value in combination with %s must be less than or equal to 365 days`, unitPath.String()),
+				fmt.Sprintf("%d %s", value, unit),
+			))
+		}
+	}
+
+	if !heartbeatAttributeModel.Grace.IsUnknown() && !heartbeatAttributeModel.GraceUnit.IsUnknown() {
+		value := heartbeatAttributeModel.Grace.ValueInt32()
+		valuePath := path.Root("heartbeat").AtName("grace")
+
+		unit := heartbeatAttributeModel.GraceUnit.ValueString()
+		unitPath := path.Root("heartbeat").AtName("grace_unit")
+
+		seconds := valueWithUnitToSeconds(value, unit)
+
+		if seconds > 3600*24*365 {
+			resp.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic(
+				valuePath,
+				fmt.Sprintf(`value in combination with %s must be less than or equal to 365 days`, unitPath.String()),
+				fmt.Sprintf("%d %s", value, unit),
+			))
+		}
+	}
+}
+
+func (r *HeartbeatResource) Configure(
+	ctx context.Context,
+	req resource.ConfigureRequest,
+	resp *resource.ConfigureResponse,
+) {
+	client, diags := interop.ClientFromProviderData(req.ProviderData)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	r.client = client
+}
+
+func (r *HeartbeatResource) ImportState(
+	ctx context.Context,
+	req resource.ImportStateRequest,
+	resp *resource.ImportStateResponse,
+) {
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *HeartbeatResource) Create(
+	ctx context.Context,
+	req resource.CreateRequest,
+	resp *resource.CreateResponse,
+) {
+	var plan HeartbeatResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.HeartbeatCheck
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.CreateHeartbeat(ctx, desiredModel)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Creating Checkly Heartbeat",
+			fmt.Sprintf("Could not create heartbeat, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Created)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *HeartbeatResource) Delete(
+	ctx context.Context,
+	req resource.DeleteRequest,
+	resp *resource.DeleteResponse,
+) {
+	var state HeartbeatResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	err := r.client.DeleteCheck(ctx, state.ID.ValueString())
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Deleting Checkly Heartbeat",
+			fmt.Sprintf("Could not delete heartbeat, unexpected error: %s", err),
+		)
+
+		return
+	}
+}
+
+func (r *HeartbeatResource) Read(
+	ctx context.Context,
+	req resource.ReadRequest,
+	resp *resource.ReadResponse,
+) {
+	var state HeartbeatResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.GetHeartbeatCheck(ctx, state.ID.ValueString())
+	if err != nil {
+		if sdkutil.IsHTTPNotFoundError(err) {
+			resp.State.RemoveResource(ctx)
+			return
+		}
+
+		resp.Diagnostics.AddError(
+			"Error Reading Checkly Heartbeat",
+			fmt.Sprintf("Could not retrieve heartbeat, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(state.Refresh(ctx, realizedModel, interop.Loaded)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *HeartbeatResource) Update(
+	ctx context.Context,
+	req resource.UpdateRequest,
+	resp *resource.UpdateResponse,
+) {
+	var plan HeartbeatResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.HeartbeatCheck
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.UpdateHeartbeat(
+		ctx,
+		plan.ID.ValueString(),
+		desiredModel,
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Updating Checkly Heartbeat",
+			fmt.Sprintf("Could not update heartbeat, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Updated)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+var (
+	_ interop.Model[checkly.HeartbeatCheck] = (*HeartbeatResourceModel)(nil)
+	_ interop.Model[checkly.Heartbeat]      = (*HeartbeatAttributeModel)(nil)
+)
+
+type HeartbeatResourceModel struct {
+	ID                        types.String `tfsdk:"id"`
+	Name                      types.String `tfsdk:"name"`
+	Activated                 types.Bool   `tfsdk:"activated"`
+	Muted                     types.Bool   `tfsdk:"muted"`
+	Tags                      types.Set    `tfsdk:"tags"`
+	AlertSettings             types.Object `tfsdk:"alert_settings"`
+	UseGlobalAlertSettings    types.Bool   `tfsdk:"use_global_alert_settings"`
+	Heartbeat                 types.Object `tfsdk:"heartbeat"`
+	AlertChannelSubscriptions types.List   `tfsdk:"alert_channel_subscription"`
+}
+
+func (m *HeartbeatResourceModel) Refresh(ctx context.Context, from *checkly.HeartbeatCheck, flags interop.RefreshFlags) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	if flags.Created() {
+		m.ID = types.StringValue(from.ID)
+	}
+
+	m.Name = types.StringValue(from.Name)
+	m.Activated = types.BoolValue(from.Activated)
+	m.Muted = types.BoolValue(from.Muted)
+
+	slices.Sort(from.Tags)
+	m.Tags = interop.IntoUntypedStringSet(&from.Tags)
+
+	m.AlertSettings, _, diags = attributes.AlertSettingsAttributeGluer.RefreshToObject(ctx, &from.AlertSettings, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.UseGlobalAlertSettings = types.BoolValue(from.UseGlobalAlertSettings)
+
+	m.Heartbeat, _, diags = HeartbeatAttributeGluer.RefreshToObject(ctx, &from.Heartbeat, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.AlertChannelSubscriptions, _, diags = attributes.AlertChannelSubscriptionAttributeGluer.RefreshToList(ctx, &from.AlertChannelSubscriptions, flags)
+	if diags.HasError() {
+		return diags
+	}
+
+	return diags
+}
+
+func (m *HeartbeatResourceModel) Render(ctx context.Context, into *checkly.HeartbeatCheck) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	into.Name = m.Name.ValueString()
+	into.Activated = m.Activated.ValueBool()
+	into.Muted = m.Muted.ValueBool()
+	into.Tags = interop.FromUntypedStringSet(m.Tags)
+
+	into.AlertSettings, _, diags = attributes.AlertSettingsAttributeGluer.RenderFromObject(ctx, m.AlertSettings)
+	if diags.HasError() {
+		return diags
+	}
+
+	into.UseGlobalAlertSettings = m.UseGlobalAlertSettings.ValueBool()
+
+	into.Heartbeat, _, diags = HeartbeatAttributeGluer.RenderFromObject(ctx, m.Heartbeat)
+	if diags.HasError() {
+		return diags
+	}
+
+	into.AlertChannelSubscriptions, _, diags = attributes.AlertChannelSubscriptionAttributeGluer.RenderFromList(ctx, m.AlertChannelSubscriptions)
+	if diags.HasError() {
+		return diags
+	}
+
+	return diags
+}
+
+var HeartbeatAttributeSchema = schema.SingleNestedAttribute{
+	Required: true,
+	Attributes: map[string]schema.Attribute{
+		"period": schema.Int32Attribute{
+			Description: "How often you expect a ping to the ping URL.",
+			Required:    true,
+		},
+		"period_unit": schema.StringAttribute{
+			Description: "Possible values `seconds`, `minutes`, `hours` and `days`.",
+			Required:    true,
+			Validators: []validator.String{
+				stringvalidator.OneOf(
+					"seconds",
+					"minutes",
+					"hours",
+					"days",
+				),
+			},
+		},
+		"grace": schema.Int32Attribute{
+			Description: "How long Checkly should wait before triggering any alerts when a ping does not arrive within the set period.",
+			Required:    true,
+		},
+		"grace_unit": schema.StringAttribute{
+			Description: "Possible values `seconds`, `minutes`, `hours` and `days`.",
+			Required:    true,
+			Validators: []validator.String{
+				stringvalidator.OneOf(
+					"seconds",
+					"minutes",
+					"hours",
+					"days",
+				),
+			},
+		},
+		"ping_token": schema.StringAttribute{
+			Description: "Custom token to generate your ping URL. Checkly will expect a ping to `https://ping.checklyhq.com/[PING_TOKEN]`.",
+			Computed:    true,
+			PlanModifiers: []planmodifier.String{
+				stringplanmodifier.UseStateForUnknown(),
+			},
+		},
+	},
+}
+
+type HeartbeatAttributeModel struct {
+	Period     types.Int32  `tfsdk:"period"`
+	PeriodUnit types.String `tfsdk:"period_unit"`
+	Grace      types.Int32  `tfsdk:"grace"`
+	GraceUnit  types.String `tfsdk:"grace_unit"`
+	PingToken  types.String `tfsdk:"ping_token"`
+}
+
+var HeartbeatAttributeGluer = interop.GluerForSingleNestedAttribute[
+	checkly.Heartbeat,
+	HeartbeatAttributeModel,
+](HeartbeatAttributeSchema)
+
+func (m *HeartbeatAttributeModel) Refresh(ctx context.Context, from *checkly.Heartbeat, flags interop.RefreshFlags) diag.Diagnostics {
+	m.Period = types.Int32Value(int32(from.Period))
+	m.PeriodUnit = types.StringValue(from.PeriodUnit)
+	m.Grace = types.Int32Value(int32(from.Grace))
+	m.GraceUnit = types.StringValue(from.GraceUnit)
+	m.PingToken = types.StringValue(from.PingToken)
+
+	return nil
+}
+
+func (m *HeartbeatAttributeModel) Render(ctx context.Context, into *checkly.Heartbeat) diag.Diagnostics {
+	into.Period = int(m.Period.ValueInt32())
+	into.PeriodUnit = m.PeriodUnit.ValueString()
+	into.Grace = int(m.Grace.ValueInt32())
+	into.GraceUnit = m.GraceUnit.ValueString()
+	into.PingToken = m.PingToken.ValueString()
+
+	return nil
+}
diff --git a/internal/provider/resources/heartbeat_resource_test.go b/internal/provider/resources/heartbeat_resource_test.go
new file mode 100644
index 0000000..6496ce0
--- /dev/null
+++ b/internal/provider/resources/heartbeat_resource_test.go
@@ -0,0 +1,215 @@
+package resources_test
+
+import (
+	"regexp"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccHeartbeatRequiredFields(t *testing.T) {
+	config := `resource "checkly_heartbeat" "test" {}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "name" is required, but no definition was found.`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "activated" is required, but no definition was found.`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "heartbeat" is required, but no definition was found.`),
+			},
+		},
+	})
+}
+
+func TestAccHeartbeatCheckInvalidInputs(t *testing.T) {
+	config := `resource "checkly_check" "test" {
+		name                      = 1
+		activated                 = "invalid"
+		use_global_alert_settings = "invalid"
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`Inappropriate value for attribute "activated"`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`Inappropriate value for attribute "use_global_alert_settings"`),
+			},
+		},
+	})
+}
+
+func TestAccHeartbeatCheckMissingHeartbeatFields(t *testing.T) {
+	config := `resource "checkly_heartbeat" "test" {
+		activated = true
+		name = "heartbeat check"
+		heartbeat = {
+
+		}
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "grace" is required, but no definition was found.`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "grace_unit" is required, but no definition was found.`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "period" is required, but no definition was found.`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "period_unit" is required, but no definition was found.`),
+			},
+		},
+	})
+}
+
+func TestAccHeartbeatCheckPeriodTooBig(t *testing.T) {
+	config := `resource "checkly_heartbeat" "test" {
+		activated = true
+		name = "heartbeat check"
+		heartbeat = {
+			period = 366
+			period_unit = "days"
+			grace = 0
+			grace_unit = "seconds"
+		}
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`Attribute heartbeat\.period value [\s\S]*?must be less than or equal to 365 days`),
+			},
+		},
+	})
+}
+
+func TestAccHeartbeatCheckPeriodTooSmall(t *testing.T) {
+	config := `resource "checkly_heartbeat" "test" {
+		activated = true
+		name = "heartbeat check"
+		heartbeat = {
+			period = 5
+			period_unit = "seconds"
+			grace = 0
+			grace_unit = "seconds"
+		}
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`Attribute heartbeat.period value[\s\S]*?must be greater than or equal to 30s`),
+			},
+		},
+	})
+}
+
+func TestAccHeartbeatCheckInvalidPeriodUnit(t *testing.T) {
+	config := `resource "checkly_heartbeat" "test" {
+		activated = true
+		name = "heartbeat check"
+		heartbeat = {
+			period = 5
+			period_unit = "lightyear"
+			grace = 0
+			grace_unit = "seconds"
+		}
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`Attribute heartbeat\.period_unit value must be one of`),
+			},
+		},
+	})
+}
+
+func TestAccHeartbeatCheckInvalidGraceUnit(t *testing.T) {
+	config := `resource "checkly_heartbeat" "test" {
+		activated = true
+		name = "heartbeat check"
+		heartbeat = {
+			period = 5
+			period_unit = "days"
+			grace = 0
+			grace_unit = "lightyear"
+		}
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`Attribute heartbeat\.grace_unit value must be one of`),
+			},
+		},
+	})
+}
+
+func TestAccHeartbeatCheckCreate(t *testing.T) {
+	config := `resource "checkly_heartbeat" "test" {
+		activated = true
+		name = "heartbeat check"
+		heartbeat = {
+			period = 5
+			period_unit = "days"
+			grace = 0
+			grace_unit = "seconds"
+		}
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: config,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_heartbeat.test",
+						"name",
+						"heartbeat check",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_heartbeat.test",
+						"heartbeat.period",
+						"5",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_heartbeat.test",
+						"heartbeat.period_unit",
+						"days",
+					),
+				),
+			},
+		},
+	})
+}
diff --git a/internal/provider/resources/maintenance_windows_resource.go b/internal/provider/resources/maintenance_windows_resource.go
new file mode 100644
index 0000000..c43cb4d
--- /dev/null
+++ b/internal/provider/resources/maintenance_windows_resource.go
@@ -0,0 +1,316 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"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"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/resources/attributes"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ resource.Resource                = (*MaintenanceWindowsResource)(nil)
+	_ resource.ResourceWithConfigure   = (*MaintenanceWindowsResource)(nil)
+	_ resource.ResourceWithImportState = (*MaintenanceWindowsResource)(nil)
+)
+
+type MaintenanceWindowsResource struct {
+	client checkly.Client
+}
+
+func NewMaintenanceWindowsResource() resource.Resource {
+	return &MaintenanceWindowsResource{}
+}
+
+func (r *MaintenanceWindowsResource) Metadata(
+	ctx context.Context,
+	req resource.MetadataRequest,
+	resp *resource.MetadataResponse,
+) {
+	resp.TypeName = req.ProviderTypeName + "_maintenance_windows"
+}
+
+func (r *MaintenanceWindowsResource) Schema(
+	ctx context.Context,
+	req resource.SchemaRequest,
+	resp *resource.SchemaResponse,
+) {
+	resp.Schema = schema.Schema{
+		Attributes: map[string]schema.Attribute{
+			"id": attributes.IDAttributeSchema,
+			"name": schema.StringAttribute{
+				Required:    true,
+				Description: "The maintenance window name.",
+			},
+			"starts_at": schema.StringAttribute{
+				Required:    true,
+				Description: "The start date of the maintenance window.",
+			},
+			"ends_at": schema.StringAttribute{
+				Required:    true,
+				Description: "The end date of the maintenance window.",
+			},
+			"repeat_unit": schema.StringAttribute{
+				Optional: true,
+				Validators: []validator.String{
+					stringvalidator.OneOf("DAY", "WEEK", "MONTH"),
+				},
+				Description: "The repeat cadence for the maintenance window. Possible values `DAY`, `WEEK` and `MONTH`.",
+			},
+			"repeat_interval": schema.Int32Attribute{
+				Optional:    true,
+				Description: "The repeat interval of the maintenance window from the first occurrence.",
+			},
+			"repeat_ends_at": schema.StringAttribute{
+				Optional:    true,
+				Description: "The date on which the maintenance window should stop repeating.",
+			},
+			"tags": schema.SetAttribute{
+				ElementType: types.StringType,
+				Optional:    true,
+				Description: "The names of the checks and groups maintenance window should apply to.",
+			},
+		},
+	}
+}
+
+func (r *MaintenanceWindowsResource) Configure(
+	ctx context.Context,
+	req resource.ConfigureRequest,
+	resp *resource.ConfigureResponse,
+) {
+	client, diags := interop.ClientFromProviderData(req.ProviderData)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	r.client = client
+}
+
+func (r *MaintenanceWindowsResource) ImportState(
+	ctx context.Context,
+	req resource.ImportStateRequest,
+	resp *resource.ImportStateResponse,
+) {
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *MaintenanceWindowsResource) Create(
+	ctx context.Context,
+	req resource.CreateRequest,
+	resp *resource.CreateResponse,
+) {
+	var plan MaintenanceWindowsResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.MaintenanceWindow
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.CreateMaintenanceWindow(ctx, desiredModel)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Creating Checkly Maintenance Window",
+			fmt.Sprintf("Could not create maintenance window, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Created)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *MaintenanceWindowsResource) Delete(
+	ctx context.Context,
+	req resource.DeleteRequest,
+	resp *resource.DeleteResponse,
+) {
+	var state MaintenanceWindowsResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	id, diags := MaintenanceWindowID.FromString(state.ID)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	err := r.client.DeleteMaintenanceWindow(ctx, id)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Deleting Checkly Maintenance Window",
+			fmt.Sprintf("Could not delete maintenance window, unexpected error: %s", err),
+		)
+
+		return
+	}
+}
+
+func (r *MaintenanceWindowsResource) Read(
+	ctx context.Context,
+	req resource.ReadRequest,
+	resp *resource.ReadResponse,
+) {
+	var state MaintenanceWindowsResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	id, diags := MaintenanceWindowID.FromString(state.ID)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	realizedModel, err := r.client.GetMaintenanceWindow(ctx, id)
+	if err != nil {
+		if sdkutil.IsHTTPNotFoundError(err) {
+			resp.State.RemoveResource(ctx)
+			return
+		}
+
+		resp.Diagnostics.AddError(
+			"Error Reading Checkly Maintenance Window",
+			fmt.Sprintf("Could not retrieve maintenance window, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(state.Refresh(ctx, realizedModel, interop.Loaded)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *MaintenanceWindowsResource) Update(
+	ctx context.Context,
+	req resource.UpdateRequest,
+	resp *resource.UpdateResponse,
+) {
+	var plan MaintenanceWindowsResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	id, diags := MaintenanceWindowID.FromString(plan.ID)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	var desiredModel checkly.MaintenanceWindow
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.UpdateMaintenanceWindow(
+		ctx,
+		id,
+		desiredModel,
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Updating Checkly Maintenance Window",
+			fmt.Sprintf("Could not update maintenance window, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Updated)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+var MaintenanceWindowID = sdkutil.Identifier{
+	Path:  path.Root("id"),
+	Title: "Checkly Maintenance Window ID",
+}
+
+var (
+	_ interop.Model[checkly.MaintenanceWindow] = (*MaintenanceWindowsResourceModel)(nil)
+)
+
+type MaintenanceWindowsResourceModel struct {
+	ID             types.String `tfsdk:"id"`
+	Name           types.String `tfsdk:"name"`
+	StartsAt       types.String `tfsdk:"starts_at"`
+	EndsAt         types.String `tfsdk:"ends_at"`
+	RepeatUnit     types.String `tfsdk:"repeat_unit"`
+	RepeatInterval types.Int32  `tfsdk:"repeat_interval"`
+	RepeatEndsAt   types.String `tfsdk:"repeat_ends_at"`
+	Tags           types.Set    `tfsdk:"tags"`
+}
+
+func (m *MaintenanceWindowsResourceModel) Refresh(ctx context.Context, from *checkly.MaintenanceWindow, flags interop.RefreshFlags) diag.Diagnostics {
+	if flags.Created() {
+		m.ID = MaintenanceWindowID.IntoString(from.ID)
+	}
+
+	m.Name = types.StringValue(from.Name)
+	m.StartsAt = types.StringValue(from.StartsAt)
+	m.EndsAt = types.StringValue(from.EndsAt)
+	m.RepeatUnit = types.StringValue(from.RepeatUnit)
+	m.RepeatEndsAt = types.StringValue(from.RepeatEndsAt)
+	m.RepeatInterval = types.Int32Value(int32(from.RepeatInterval))
+	m.Tags = interop.IntoUntypedStringSet(&from.Tags)
+
+	return nil
+}
+
+func (m *MaintenanceWindowsResourceModel) Render(ctx context.Context, into *checkly.MaintenanceWindow) diag.Diagnostics {
+	into.Name = m.Name.ValueString()
+	into.StartsAt = m.StartsAt.ValueString()
+	into.EndsAt = m.EndsAt.ValueString()
+	into.RepeatUnit = m.RepeatUnit.ValueString()
+	into.RepeatEndsAt = m.RepeatEndsAt.ValueString()
+	into.RepeatInterval = int(m.RepeatInterval.ValueInt32())
+	into.Tags = interop.FromUntypedStringSet(m.Tags)
+
+	return nil
+}
diff --git a/internal/provider/resources/private_location_resource.go b/internal/provider/resources/private_location_resource.go
new file mode 100644
index 0000000..951c026
--- /dev/null
+++ b/internal/provider/resources/private_location_resource.go
@@ -0,0 +1,284 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework/attr"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"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/resource/schema/stringdefault"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/resources/attributes"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ resource.Resource                = (*PrivateLocationResource)(nil)
+	_ resource.ResourceWithConfigure   = (*PrivateLocationResource)(nil)
+	_ resource.ResourceWithImportState = (*PrivateLocationResource)(nil)
+)
+
+type PrivateLocationResource struct {
+	client checkly.Client
+}
+
+func NewPrivateLocationResource() resource.Resource {
+	return &PrivateLocationResource{}
+}
+
+func (r *PrivateLocationResource) Metadata(
+	ctx context.Context,
+	req resource.MetadataRequest,
+	resp *resource.MetadataResponse,
+) {
+	resp.TypeName = req.ProviderTypeName + "_private_location"
+}
+
+func (r *PrivateLocationResource) Schema(
+	ctx context.Context,
+	req resource.SchemaRequest,
+	resp *resource.SchemaResponse,
+) {
+	resp.Schema = schema.Schema{
+		Attributes: map[string]schema.Attribute{
+			"id": attributes.IDAttributeSchema,
+			"name": schema.StringAttribute{
+				Required:    true,
+				Description: "The private location name.",
+			},
+			"slug_name": schema.StringAttribute{
+				Required:    true,
+				Description: "Valid slug name.",
+			},
+			"icon": schema.StringAttribute{
+				Optional:    true,
+				Computed:    true,
+				Default:     stringdefault.StaticString("location"),
+				Description: "Icon assigned to the private location.",
+			},
+			"keys": schema.SetAttribute{
+				ElementType: types.StringType,
+				Computed:    true,
+				Sensitive:   true,
+				Description: "Private location API keys.",
+			},
+		},
+	}
+}
+
+func (r *PrivateLocationResource) Configure(
+	ctx context.Context,
+	req resource.ConfigureRequest,
+	resp *resource.ConfigureResponse,
+) {
+	client, diags := interop.ClientFromProviderData(req.ProviderData)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	r.client = client
+}
+
+func (r *PrivateLocationResource) ImportState(
+	ctx context.Context,
+	req resource.ImportStateRequest,
+	resp *resource.ImportStateResponse,
+) {
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *PrivateLocationResource) Create(
+	ctx context.Context,
+	req resource.CreateRequest,
+	resp *resource.CreateResponse,
+) {
+	var plan PrivateLocationResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.PrivateLocation
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.CreatePrivateLocation(ctx, desiredModel)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Creating Checkly Private Location",
+			fmt.Sprintf("Could not create private location, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Created)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *PrivateLocationResource) Delete(
+	ctx context.Context,
+	req resource.DeleteRequest,
+	resp *resource.DeleteResponse,
+) {
+	var state PrivateLocationResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	err := r.client.DeletePrivateLocation(ctx, state.ID.ValueString())
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Deleting Checkly Private Location",
+			fmt.Sprintf("Could not delete private location, unexpected error: %s", err),
+		)
+
+		return
+	}
+}
+
+func (r *PrivateLocationResource) Read(
+	ctx context.Context,
+	req resource.ReadRequest,
+	resp *resource.ReadResponse,
+) {
+	var state PrivateLocationResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.GetPrivateLocation(ctx, state.ID.ValueString())
+	if err != nil {
+		if sdkutil.IsHTTPNotFoundError(err) {
+			resp.State.RemoveResource(ctx)
+			return
+		}
+
+		resp.Diagnostics.AddError(
+			"Error Reading Checkly Private Location",
+			fmt.Sprintf("Could not retrieve private location, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(state.Refresh(ctx, realizedModel, interop.Loaded)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *PrivateLocationResource) Update(
+	ctx context.Context,
+	req resource.UpdateRequest,
+	resp *resource.UpdateResponse,
+) {
+	var plan PrivateLocationResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.PrivateLocation
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.UpdatePrivateLocation(
+		ctx,
+		plan.ID.ValueString(),
+		desiredModel,
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Updating Checkly Private Location",
+			fmt.Sprintf("Could not update private location, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Updated)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+var (
+	_ interop.Model[checkly.PrivateLocation] = (*PrivateLocationResourceModel)(nil)
+)
+
+type PrivateLocationResourceModel struct {
+	ID       types.String `tfsdk:"id"`
+	Name     types.String `tfsdk:"name"`
+	SlugName types.String `tfsdk:"slug_name"`
+	Icon     types.String `tfsdk:"icon"`
+	Keys     types.Set    `tfsdk:"keys"`
+}
+
+func (m *PrivateLocationResourceModel) Refresh(ctx context.Context, from *checkly.PrivateLocation, flags interop.RefreshFlags) diag.Diagnostics {
+	if flags.Created() {
+		m.ID = types.StringValue(from.ID)
+	}
+
+	m.Name = types.StringValue(from.Name)
+	m.SlugName = types.StringValue(from.SlugName)
+	m.Icon = types.StringValue(from.Icon)
+
+	var keyValues []attr.Value
+	for _, key := range from.Keys {
+		keyValues = append(keyValues, types.StringValue(key.RawKey))
+	}
+
+	keys, diags := types.SetValue(types.StringType, keyValues)
+	if diags.HasError() {
+		return diags
+	}
+
+	m.Keys = keys
+
+	return nil
+}
+
+func (m *PrivateLocationResourceModel) Render(ctx context.Context, into *checkly.PrivateLocation) diag.Diagnostics {
+	into.Name = m.Name.ValueString()
+	into.SlugName = m.SlugName.ValueString()
+	into.Icon = m.Icon.ValueString()
+
+	// Keys are intentionally not included.
+
+	return nil
+}
diff --git a/internal/provider/resources/private_location_resource_test.go b/internal/provider/resources/private_location_resource_test.go
new file mode 100644
index 0000000..37a2fb3
--- /dev/null
+++ b/internal/provider/resources/private_location_resource_test.go
@@ -0,0 +1,93 @@
+package resources_test
+
+import (
+	"regexp"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccPrivateLocationCheckRequiredFields(t *testing.T) {
+	config := `resource "checkly_private_location" "test" {}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "name" is required`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "slug_name" is required`),
+			},
+		},
+	})
+}
+
+func TestAccPrivateLocationSuccess(t *testing.T) {
+	config := `resource "checkly_private_location" "test" {
+		name     = "New Private Location"
+		slug_name   = "new-private-location"
+		icon       	= "bell-fill"
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: config,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_private_location.test",
+						"name",
+						"New Private Location",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_private_location.test",
+						"slug_name",
+						"new-private-location",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_private_location.test",
+						"icon",
+						"bell-fill",
+					),
+				),
+			},
+		},
+	})
+}
+
+func TestAccPrivateLocationDefaultIcon(t *testing.T) {
+	config := `resource "checkly_private_location" "without_icon" {
+		name     = "New Private Location"
+		slug_name   = "new-private-location"
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: config,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_private_location.without_icon",
+						"name",
+						"New Private Location",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_private_location.without_icon",
+						"slug_name",
+						"new-private-location",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_private_location.without_icon",
+						"icon",
+						"location",
+					),
+				),
+			},
+		},
+	})
+}
diff --git a/checkly/test_util.go b/internal/provider/resources/shared_test.go
similarity index 52%
rename from checkly/test_util.go
rename to internal/provider/resources/shared_test.go
index d95147e..38f31e0 100644
--- a/checkly/test_util.go
+++ b/internal/provider/resources/shared_test.go
@@ -1,46 +1,24 @@
-package checkly
+package resources_test
 
 import (
 	"encoding/json"
 	"fmt"
-	"os"
 	"regexp"
-	"testing"
 
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
-)
-
-var testAccProviders map[string]*schema.Provider
-
-func init() {
-	testAccProviders = map[string]*schema.Provider{
-		"checkly": Provider(),
-	}
-}
+	"github.com/hashicorp/terraform-plugin-framework/providerserver"
+	"github.com/hashicorp/terraform-plugin-go/tfprotov6"
+	"github.com/hashicorp/terraform-plugin-testing/terraform"
 
-func testAccPreCheck(t *testing.T) {
-	if os.Getenv("CHECKLY_API_KEY") == "" {
-		t.Fatal("CHECKLY_API_KEY must be set for acceptance tests")
-	}
+	"github.com/checkly/terraform-provider-checkly/internal/provider"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/globalregistry"
+)
 
-	if os.Getenv("CHECKLY_ACCOUNT_ID") == "" {
-		t.Fatal("CHECKLY_ACCOUNT_ID must be set for acceptance tests")
+func protoV6ProviderFactories() map[string]func() (tfprotov6.ProviderServer, error) {
+	return map[string]func() (tfprotov6.ProviderServer, error){
+		"checkly": providerserver.NewProtocol6WithError(provider.New("test", globalregistry.Registry)()),
 	}
 }
 
-func accTestCase(t *testing.T, steps []resource.TestStep) {
-	resource.Test(t, resource.TestCase{
-		PreCheck: func() {
-			testAccPreCheck(t)
-		},
-		Providers:    testAccProviders,
-		CheckDestroy: nil,
-		Steps:        steps,
-	})
-}
-
 // test resource using regular expressions
 // this helps testing arrays which have irregular indices;
 // needed because we get things like "alert_settings.2888461220.escalation_type": "RUN_BASED"
diff --git a/internal/provider/resources/snippet_resource.go b/internal/provider/resources/snippet_resource.go
new file mode 100644
index 0000000..706ae09
--- /dev/null
+++ b/internal/provider/resources/snippet_resource.go
@@ -0,0 +1,277 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"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/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/resources/attributes"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ resource.Resource                = (*SnippetResource)(nil)
+	_ resource.ResourceWithConfigure   = (*SnippetResource)(nil)
+	_ resource.ResourceWithImportState = (*SnippetResource)(nil)
+)
+
+type SnippetResource struct {
+	client checkly.Client
+}
+
+func NewSnippetResource() resource.Resource {
+	return &SnippetResource{}
+}
+
+func (r *SnippetResource) Metadata(
+	ctx context.Context,
+	req resource.MetadataRequest,
+	resp *resource.MetadataResponse,
+) {
+	resp.TypeName = req.ProviderTypeName + "_snippet"
+}
+
+func (r *SnippetResource) Schema(
+	ctx context.Context,
+	req resource.SchemaRequest,
+	resp *resource.SchemaResponse,
+) {
+	resp.Schema = schema.Schema{
+		Attributes: map[string]schema.Attribute{
+			"id": attributes.IDAttributeSchema,
+			"name": schema.StringAttribute{
+				Required:    true,
+				Description: "The name of the snippet.",
+			},
+			"script": schema.StringAttribute{
+				Required: true,
+				Description: "Your Node.js code that interacts with the API " +
+					"check lifecycle, or functions as a partial for browser " +
+					"checks.",
+			},
+		},
+	}
+}
+
+func (r *SnippetResource) Configure(
+	ctx context.Context,
+	req resource.ConfigureRequest,
+	resp *resource.ConfigureResponse,
+) {
+	client, diags := interop.ClientFromProviderData(req.ProviderData)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	r.client = client
+}
+
+func (r *SnippetResource) ImportState(
+	ctx context.Context,
+	req resource.ImportStateRequest,
+	resp *resource.ImportStateResponse,
+) {
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *SnippetResource) Create(
+	ctx context.Context,
+	req resource.CreateRequest,
+	resp *resource.CreateResponse,
+) {
+	var plan SnippetResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	var desiredModel checkly.Snippet
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.CreateSnippet(ctx, desiredModel)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Creating Checkly Snippet",
+			fmt.Sprintf("Could not create snippet, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Created)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *SnippetResource) Delete(
+	ctx context.Context,
+	req resource.DeleteRequest,
+	resp *resource.DeleteResponse,
+) {
+	var state SnippetResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	id, diags := SnippetID.FromString(state.ID)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	err := r.client.DeleteSnippet(ctx, id)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Deleting Checkly Snippet",
+			fmt.Sprintf("Could not delete snippet, unexpected error: %s", err),
+		)
+
+		return
+	}
+}
+
+func (r *SnippetResource) Read(
+	ctx context.Context,
+	req resource.ReadRequest,
+	resp *resource.ReadResponse,
+) {
+	var state SnippetResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	id, diags := SnippetID.FromString(state.ID)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	realizedModel, err := r.client.GetSnippet(ctx, id)
+	if err != nil {
+		if sdkutil.IsHTTPNotFoundError(err) {
+			resp.State.RemoveResource(ctx)
+			return
+		}
+
+		resp.Diagnostics.AddError(
+			"Error Reading Checkly Snippet",
+			fmt.Sprintf("Could not retrieve snippet, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(state.Refresh(ctx, realizedModel, interop.Loaded)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *SnippetResource) Update(
+	ctx context.Context,
+	req resource.UpdateRequest,
+	resp *resource.UpdateResponse,
+) {
+	var plan SnippetResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	id, diags := SnippetID.FromString(plan.ID)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	var desiredModel checkly.Snippet
+	resp.Diagnostics.Append(plan.Render(ctx, &desiredModel)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.UpdateSnippet(
+		ctx,
+		id,
+		desiredModel,
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Updating Checkly Snippet",
+			fmt.Sprintf("Could not update snippet, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Updated)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+var SnippetID = sdkutil.Identifier{
+	Path:  path.Root("id"),
+	Title: "Checkly Snippet ID",
+}
+
+var (
+	_ interop.Model[checkly.Snippet] = (*SnippetResourceModel)(nil)
+)
+
+type SnippetResourceModel struct {
+	ID     types.String `tfsdk:"id"`
+	Name   types.String `tfsdk:"name"`
+	Script types.String `tfsdk:"script"`
+}
+
+func (m *SnippetResourceModel) Refresh(ctx context.Context, from *checkly.Snippet, flags interop.RefreshFlags) diag.Diagnostics {
+	if flags.Created() {
+		m.ID = SnippetID.IntoString(from.ID)
+	}
+
+	m.Name = types.StringValue(from.Name)
+	m.Script = types.StringValue(from.Script)
+
+	return nil
+}
+
+func (m *SnippetResourceModel) Render(ctx context.Context, into *checkly.Snippet) diag.Diagnostics {
+	into.Name = m.Name.ValueString()
+	into.Script = m.Script.ValueString()
+
+	return nil
+}
diff --git a/internal/provider/resources/snippet_resource_test.go b/internal/provider/resources/snippet_resource_test.go
new file mode 100644
index 0000000..9daab74
--- /dev/null
+++ b/internal/provider/resources/snippet_resource_test.go
@@ -0,0 +1,54 @@
+package resources_test
+
+import (
+	"regexp"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccSnippetCheckRequiredFields(t *testing.T) {
+	config := `resource "checkly_snippet" "test" {}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "name" is required`),
+			},
+			{
+				Config:      config,
+				ExpectError: regexp.MustCompile(`The argument "script" is required`),
+			},
+		},
+	})
+}
+
+func TestAccSnippetSuccess(t *testing.T) {
+	config := `resource "checkly_snippet" "test" {
+		name     = "foo"
+		script   = "console.log('bar')"
+	}`
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV6ProviderFactories: protoV6ProviderFactories(),
+
+		Steps: []resource.TestStep{
+			{
+				Config: config,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(
+						"checkly_snippet.test",
+						"name",
+						"foo",
+					),
+					resource.TestCheckResourceAttr(
+						"checkly_snippet.test",
+						"script",
+						"console.log('bar')",
+					),
+				),
+			},
+		},
+	})
+}
diff --git a/internal/provider/resources/trigger_check_resource.go b/internal/provider/resources/trigger_check_resource.go
new file mode 100644
index 0000000..032da93
--- /dev/null
+++ b/internal/provider/resources/trigger_check_resource.go
@@ -0,0 +1,260 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"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/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/resources/attributes"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ resource.Resource                = (*TriggerCheckResource)(nil)
+	_ resource.ResourceWithConfigure   = (*TriggerCheckResource)(nil)
+	_ resource.ResourceWithImportState = (*TriggerCheckResource)(nil)
+)
+
+type TriggerCheckResource struct {
+	client checkly.Client
+}
+
+func NewTriggerCheckResource() resource.Resource {
+	return &TriggerCheckResource{}
+}
+
+func (r *TriggerCheckResource) Metadata(
+	ctx context.Context,
+	req resource.MetadataRequest,
+	resp *resource.MetadataResponse,
+) {
+	resp.TypeName = req.ProviderTypeName + "_trigger_check"
+}
+
+func (r *TriggerCheckResource) Schema(
+	ctx context.Context,
+	req resource.SchemaRequest,
+	resp *resource.SchemaResponse,
+) {
+	resp.Schema = schema.Schema{
+		Attributes: map[string]schema.Attribute{
+			"id": attributes.IDAttributeSchema,
+			"check_id": schema.StringAttribute{
+				Required:    true,
+				Description: "The ID of the check that you want to attach the trigger to.",
+			},
+			"token": schema.StringAttribute{
+				Optional:    true,
+				Computed:    true,
+				Description: "The token value created to trigger the check.",
+			},
+			"url": schema.StringAttribute{
+				Optional:    true,
+				Computed:    true,
+				Description: "The request URL to trigger the check run.",
+			},
+		},
+	}
+}
+
+func (r *TriggerCheckResource) Configure(
+	ctx context.Context,
+	req resource.ConfigureRequest,
+	resp *resource.ConfigureResponse,
+) {
+	client, diags := interop.ClientFromProviderData(req.ProviderData)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	r.client = client
+}
+
+func (r *TriggerCheckResource) ImportState(
+	ctx context.Context,
+	req resource.ImportStateRequest,
+	resp *resource.ImportStateResponse,
+) {
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *TriggerCheckResource) Create(
+	ctx context.Context,
+	req resource.CreateRequest,
+	resp *resource.CreateResponse,
+) {
+	var plan TriggerCheckResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.CreateTriggerCheck(
+		ctx,
+		plan.CheckID.ValueString(),
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Creating Checkly Trigger Check",
+			fmt.Sprintf("Could not create trigger check, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Created)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *TriggerCheckResource) Delete(
+	ctx context.Context,
+	req resource.DeleteRequest,
+	resp *resource.DeleteResponse,
+) {
+	var state TriggerCheckResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	err := r.client.DeleteTriggerCheck(ctx, state.CheckID.ValueString())
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Deleting Checkly Trigger Check",
+			fmt.Sprintf("Could not delete trigger check, unexpected error: %s", err),
+		)
+
+		return
+	}
+}
+
+func (r *TriggerCheckResource) Read(
+	ctx context.Context,
+	req resource.ReadRequest,
+	resp *resource.ReadResponse,
+) {
+	var state TriggerCheckResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.GetTriggerCheck(
+		ctx,
+		state.CheckID.ValueString(),
+	)
+	if err != nil {
+		if sdkutil.IsHTTPNotFoundError(err) {
+			resp.State.RemoveResource(ctx)
+			return
+		}
+
+		resp.Diagnostics.AddError(
+			"Error Reading Checkly Trigger Check",
+			fmt.Sprintf("Could not retrieve trigger check, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(state.Refresh(ctx, realizedModel, interop.Loaded)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *TriggerCheckResource) Update(
+	ctx context.Context,
+	req resource.UpdateRequest,
+	resp *resource.UpdateResponse,
+) {
+	var plan TriggerCheckResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.GetTriggerCheck(
+		ctx,
+		plan.CheckID.ValueString(),
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Updating Checkly Trigger Check",
+			fmt.Sprintf("Could not update trigger check, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Updated)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+var TriggerCheckID = sdkutil.Identifier{
+	Path:  path.Root("id"),
+	Title: "Checkly Trigger Check ID",
+}
+
+var (
+	_ interop.Model[checkly.TriggerCheck] = (*TriggerCheckResourceModel)(nil)
+)
+
+type TriggerCheckResourceModel struct {
+	ID      types.String `tfsdk:"id"`
+	CheckID types.String `tfsdk:"check_id"`
+	Token   types.String `tfsdk:"token"`
+	URL     types.String `tfsdk:"url"`
+}
+
+func (m *TriggerCheckResourceModel) Refresh(ctx context.Context, from *checkly.TriggerCheck, flags interop.RefreshFlags) diag.Diagnostics {
+	// TODO: Always update ID? CheckID, which is used for lookup, is user-modifiable,
+	// and we could receive back a complete different ID.
+	if flags.Created() {
+		m.ID = TriggerCheckID.IntoString(from.ID)
+	}
+
+	m.CheckID = types.StringValue(from.CheckId)
+	m.Token = types.StringValue(from.Token)
+	m.URL = types.StringValue(from.URL)
+
+	return nil
+}
+
+func (m *TriggerCheckResourceModel) Render(ctx context.Context, into *checkly.TriggerCheck) diag.Diagnostics {
+	into.Token = m.Token.ValueString()
+	into.URL = m.URL.ValueString()
+
+	return nil
+}
diff --git a/internal/provider/resources/trigger_group_resource.go b/internal/provider/resources/trigger_group_resource.go
new file mode 100644
index 0000000..b31ff56
--- /dev/null
+++ b/internal/provider/resources/trigger_group_resource.go
@@ -0,0 +1,258 @@
+package resources
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"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/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/interop"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/resources/attributes"
+	"github.com/checkly/terraform-provider-checkly/internal/sdkutil"
+)
+
+var (
+	_ resource.Resource                = (*TriggerGroupResource)(nil)
+	_ resource.ResourceWithConfigure   = (*TriggerGroupResource)(nil)
+	_ resource.ResourceWithImportState = (*TriggerGroupResource)(nil)
+)
+
+type TriggerGroupResource struct {
+	client checkly.Client
+}
+
+func NewTriggerGroupResource() resource.Resource {
+	return &TriggerGroupResource{}
+}
+
+func (r *TriggerGroupResource) Metadata(
+	ctx context.Context,
+	req resource.MetadataRequest,
+	resp *resource.MetadataResponse,
+) {
+	resp.TypeName = req.ProviderTypeName + "_trigger_group"
+}
+
+func (r *TriggerGroupResource) Schema(
+	ctx context.Context,
+	req resource.SchemaRequest,
+	resp *resource.SchemaResponse,
+) {
+	resp.Schema = schema.Schema{
+		Attributes: map[string]schema.Attribute{
+			"id": attributes.IDAttributeSchema,
+			"group_id": schema.Int64Attribute{
+				Required:    true,
+				Description: "The ID of the group that you want to attach the trigger to.",
+			},
+			"token": schema.StringAttribute{
+				Optional:    true,
+				Computed:    true,
+				Description: "The token value created to trigger the group.",
+			},
+			"url": schema.StringAttribute{
+				Optional:    true,
+				Computed:    true,
+				Description: "The request URL to trigger the group run.",
+			},
+		},
+	}
+}
+
+func (r *TriggerGroupResource) Configure(
+	ctx context.Context,
+	req resource.ConfigureRequest,
+	resp *resource.ConfigureResponse,
+) {
+	client, diags := interop.ClientFromProviderData(req.ProviderData)
+	if diags.HasError() {
+		resp.Diagnostics.Append(diags...)
+		return
+	}
+
+	r.client = client
+}
+
+func (r *TriggerGroupResource) ImportState(
+	ctx context.Context,
+	req resource.ImportStateRequest,
+	resp *resource.ImportStateResponse,
+) {
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *TriggerGroupResource) Create(
+	ctx context.Context,
+	req resource.CreateRequest,
+	resp *resource.CreateResponse,
+) {
+	var plan TriggerGroupResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.CreateTriggerGroup(
+		ctx,
+		plan.GroupID.ValueInt64(),
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Creating Checkly Trigger Group",
+			fmt.Sprintf("Could not create trigger group, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Created)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *TriggerGroupResource) Delete(
+	ctx context.Context,
+	req resource.DeleteRequest,
+	resp *resource.DeleteResponse,
+) {
+	var state TriggerGroupResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	err := r.client.DeleteTriggerGroup(ctx, state.GroupID.ValueInt64())
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Deleting Checkly Trigger Group",
+			fmt.Sprintf("Could not delete trigger group, unexpected error: %s", err),
+		)
+
+		return
+	}
+}
+
+func (r *TriggerGroupResource) Read(
+	ctx context.Context,
+	req resource.ReadRequest,
+	resp *resource.ReadResponse,
+) {
+	var state TriggerGroupResourceModel
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.GetTriggerGroup(
+		ctx,
+		state.GroupID.ValueInt64(),
+	)
+	if err != nil {
+		if sdkutil.IsHTTPNotFoundError(err) {
+			resp.State.RemoveResource(ctx)
+			return
+		}
+
+		resp.Diagnostics.AddError(
+			"Error Reading Checkly Trigger Group",
+			fmt.Sprintf("Could not retrieve trigger group, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(state.Refresh(ctx, realizedModel, interop.Loaded)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *TriggerGroupResource) Update(
+	ctx context.Context,
+	req resource.UpdateRequest,
+	resp *resource.UpdateResponse,
+) {
+	var plan TriggerGroupResourceModel
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	realizedModel, err := r.client.GetTriggerGroup(
+		ctx,
+		plan.GroupID.ValueInt64(),
+	)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Error Updating Checkly Trigger Group",
+			fmt.Sprintf("Could not update trigger group, unexpected error: %s", err),
+		)
+
+		return
+	}
+
+	resp.Diagnostics.Append(plan.Refresh(ctx, realizedModel, interop.Updated)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+var TriggerGroupID = sdkutil.Identifier{
+	Path:  path.Root("id"),
+	Title: "Checkly Trigger Group ID",
+}
+
+var (
+	_ interop.Model[checkly.TriggerGroup] = (*TriggerGroupResourceModel)(nil)
+)
+
+type TriggerGroupResourceModel struct {
+	ID      types.String `tfsdk:"id"`
+	GroupID types.Int64  `tfsdk:"group_id"`
+	Token   types.String `tfsdk:"token"`
+	URL     types.String `tfsdk:"url"`
+}
+
+func (m *TriggerGroupResourceModel) Refresh(ctx context.Context, from *checkly.TriggerGroup, flags interop.RefreshFlags) diag.Diagnostics {
+	if flags.Created() {
+		m.ID = TriggerGroupID.IntoString(from.ID)
+	}
+
+	m.GroupID = types.Int64Value(from.GroupId)
+	m.Token = types.StringValue(from.Token)
+	m.URL = types.StringValue(from.URL)
+
+	return nil
+}
+
+func (m *TriggerGroupResourceModel) Render(ctx context.Context, into *checkly.TriggerGroup) diag.Diagnostics {
+	into.Token = m.Token.ValueString()
+	into.URL = m.URL.ValueString()
+
+	return nil
+}
diff --git a/internal/sdkutil/sdkutil.go b/internal/sdkutil/sdkutil.go
new file mode 100644
index 0000000..14aa748
--- /dev/null
+++ b/internal/sdkutil/sdkutil.go
@@ -0,0 +1,103 @@
+package sdkutil
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/hashicorp/terraform-plugin-framework/attr"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	checkly "github.com/checkly/checkly-go-sdk"
+)
+
+type Identifier struct {
+	Path  path.Path
+	Title string
+}
+
+func (i *Identifier) FromString(id types.String) (int64, diag.Diagnostics) {
+	if id.IsUnknown() {
+		return 0, diag.Diagnostics{
+			diag.NewAttributeErrorDiagnostic(
+				i.Path,
+				"Unknown "+i.Title,
+				"", // TODO
+			),
+		}
+	}
+
+	if id.IsNull() {
+		return 0, diag.Diagnostics{
+			diag.NewAttributeErrorDiagnostic(
+				i.Path,
+				"Missing "+i.Title,
+				"", // TODO
+			),
+		}
+	}
+
+	val, err := strconv.ParseInt(id.ValueString(), 10, 64)
+	if err != nil {
+		return 0, diag.Diagnostics{
+			diag.NewAttributeErrorDiagnostic(
+				i.Path,
+				"Invalid "+i.Title,
+				"Value must be numeric, but was not: "+err.Error(),
+			),
+		}
+	}
+
+	return val, nil
+}
+
+func (i *Identifier) IntoString(id int64) types.String {
+	return types.StringValue(fmt.Sprintf("%d", id))
+}
+
+func KeyValuesFromMap(m types.Map) []checkly.KeyValue {
+	if m.IsNull() {
+		return nil
+	}
+
+	var values []checkly.KeyValue
+	for key, val := range m.Elements() {
+		values = append(values, checkly.KeyValue{
+			Key:   key,
+			Value: val.(types.String).ValueString(),
+		})
+	}
+
+	return values
+}
+
+func KeyValuesIntoMap(values *[]checkly.KeyValue) types.Map {
+	if values == nil {
+		return types.MapNull(types.StringType)
+	}
+
+	mapValues := make(map[string]attr.Value, len(*values))
+	for _, kv := range *values {
+		mapValues[kv.Key] = types.StringValue(kv.Value)
+	}
+
+	return types.MapValueMust(types.StringType, mapValues)
+}
+
+func IsHTTPNotFoundError(err error) bool {
+	// Unfortunately the SDK presents HTTP errors in a completely unusable way,
+	// forcing us to match against string values.
+	msg := err.Error()
+
+	switch {
+	case strings.Contains(msg, "unexpected response status: 404"):
+		return true
+	// Unfortunate inconsistency.
+	case strings.Contains(msg, "unexpected response status 404"):
+		return true
+	}
+
+	return false
+}
diff --git a/main.go b/main.go
index fb402ba..69ce3c8 100644
--- a/main.go
+++ b/main.go
@@ -1,25 +1,38 @@
 package main
 
 import (
+	"context"
 	"flag"
+	"log"
 
-	"github.com/checkly/terraform-provider-checkly/checkly"
-	"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"
+	"github.com/hashicorp/terraform-plugin-framework/providerserver"
+
+	"github.com/checkly/terraform-provider-checkly/internal/provider"
+	"github.com/checkly/terraform-provider-checkly/internal/provider/globalregistry"
 )
 
-//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs
+var (
+	version = "dev"
+)
 
 func main() {
-	var debugMode bool
+	var debug bool
 
-	flag.BoolVar(&debugMode, "debug", false, "set to true to run the provider with support for debuggers like delve")
+	flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
 	flag.Parse()
 
-	opts := &plugin.ServeOpts{
-		Debug:        debugMode,
-		ProviderAddr: "registry.terraform.io/checkly/checkly",
-		ProviderFunc: checkly.Provider,
+	opts := providerserver.ServeOpts{
+		Address: "registry.terraform.io/checkly/checkly",
+		Debug:   debug,
 	}
 
-	plugin.Serve(opts)
+	err := providerserver.Serve(
+		context.Background(),
+		provider.New(version, globalregistry.Registry),
+		opts,
+	)
+
+	if err != nil {
+		log.Fatal(err.Error())
+	}
 }
diff --git a/terraform-registry-manifest.json b/terraform-registry-manifest.json
index 5a294ba..8f42373 100644
--- a/terraform-registry-manifest.json
+++ b/terraform-registry-manifest.json
@@ -1,7 +1,8 @@
 {
   "version": 1,
   "metadata": {
-    "protocol_versions": ["5.0"]
+    "protocol_versions": [
+      "6.0"
+    ]
   }
-}
-
+}
\ No newline at end of file
diff --git a/tools/go.mod b/tools/go.mod
new file mode 100644
index 0000000..19925b2
--- /dev/null
+++ b/tools/go.mod
@@ -0,0 +1,57 @@
+module tools
+
+go 1.23.3
+
+require github.com/hashicorp/terraform-plugin-docs v0.20.0
+
+require (
+	github.com/BurntSushi/toml v1.2.1 // indirect
+	github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect
+	github.com/Masterminds/goutils v1.1.1 // indirect
+	github.com/Masterminds/semver/v3 v3.2.0 // indirect
+	github.com/Masterminds/sprig/v3 v3.2.3 // indirect
+	github.com/ProtonMail/go-crypto v1.1.3 // indirect
+	github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
+	github.com/armon/go-radix v1.0.0 // indirect
+	github.com/bgentry/speakeasy v0.1.0 // indirect
+	github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect
+	github.com/cloudflare/circl v1.5.0 // indirect
+	github.com/fatih/color v1.18.0 // indirect
+	github.com/google/uuid v1.6.0 // indirect
+	github.com/hashicorp/cli v1.1.6 // indirect
+	github.com/hashicorp/errwrap v1.1.0 // indirect
+	github.com/hashicorp/go-checkpoint v0.5.0 // indirect
+	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
+	github.com/hashicorp/go-multierror v1.1.1 // indirect
+	github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
+	github.com/hashicorp/go-uuid v1.0.3 // indirect
+	github.com/hashicorp/go-version v1.7.0 // indirect
+	github.com/hashicorp/hc-install v0.9.0 // indirect
+	github.com/hashicorp/terraform-exec v0.21.0 // indirect
+	github.com/hashicorp/terraform-json v0.23.0 // indirect
+	github.com/huandu/xstrings v1.3.3 // indirect
+	github.com/imdario/mergo v0.3.15 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/mattn/go-runewidth v0.0.16 // indirect
+	github.com/mitchellh/copystructure v1.2.0 // indirect
+	github.com/mitchellh/reflectwalk v1.0.2 // indirect
+	github.com/posener/complete v1.2.3 // indirect
+	github.com/rivo/uniseg v0.4.7 // indirect
+	github.com/shopspring/decimal v1.3.1 // indirect
+	github.com/spf13/cast v1.5.0 // indirect
+	github.com/stretchr/testify v1.9.0 // indirect
+	github.com/yuin/goldmark v1.7.7 // indirect
+	github.com/yuin/goldmark-meta v1.1.0 // indirect
+	github.com/zclconf/go-cty v1.15.0 // indirect
+	go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect
+	golang.org/x/crypto v0.29.0 // indirect
+	golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
+	golang.org/x/mod v0.22.0 // indirect
+	golang.org/x/net v0.31.0 // indirect
+	golang.org/x/sys v0.27.0 // indirect
+	golang.org/x/text v0.20.0 // indirect
+	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+	gopkg.in/yaml.v2 v2.4.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/tools/go.sum b/tools/go.sum
new file mode 100644
index 0000000..adff740
--- /dev/null
+++ b/tools/go.sum
@@ -0,0 +1,203 @@
+dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
+dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
+github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
+github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/Kunde21/markdownfmt/v3 v3.1.0 h1:KiZu9LKs+wFFBQKhrZJrFZwtLnCCWJahL+S+E/3VnM0=
+github.com/Kunde21/markdownfmt/v3 v3.1.0/go.mod h1:tPXN1RTyOzJwhfHoon9wUr4HGYmWgVxSQN6VBJDkrVc=
+github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
+github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
+github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
+github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
+github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
+github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
+github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
+github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
+github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
+github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
+github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
+github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bmatcuk/doublestar/v4 v4.7.1 h1:fdDeAqgT47acgwd9bd9HxJRDmc9UAmPpc+2m0CXv75Q=
+github.com/bmatcuk/doublestar/v4 v4.7.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
+github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
+github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
+github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
+github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
+github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
+github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
+github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
+github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
+github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
+github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
+github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
+github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
+github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/hashicorp/cli v1.1.6 h1:CMOV+/LJfL1tXCOKrgAX0uRKnzjj/mpmqNXloRSy2K8=
+github.com/hashicorp/cli v1.1.6/go.mod h1:MPon5QYlgjjo0BSoAiN0ESeT5fRzDjVRp+uioJ0piz4=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
+github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
+github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
+github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
+github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
+github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
+github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/hc-install v0.9.0 h1:2dIk8LcvANwtv3QZLckxcjyF5w8KVtiMxu6G6eLhghE=
+github.com/hashicorp/hc-install v0.9.0/go.mod h1:+6vOP+mf3tuGgMApVYtmsnDoKWMDcFXeTxCACYZ8SFg=
+github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ=
+github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg=
+github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2xoR+lppBkI=
+github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c=
+github.com/hashicorp/terraform-plugin-docs v0.20.0 h1:ox7rm1FN0dVZaJBUzkVVh10R1r3+FeMQWL0QopQ9d7o=
+github.com/hashicorp/terraform-plugin-docs v0.20.0/go.mod h1:A/+4SVMdAkQYtIBtaxV0H7AU862TxVZk/hhKaMDQB6Y=
+github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
+github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
+github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
+github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
+github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
+github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
+github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
+github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
+github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
+github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
+github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
+github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
+github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
+github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
+github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
+github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yuin/goldmark v1.7.7 h1:5m9rrB1sW3JUMToKFQfb+FGt1U7r57IHu5GrYrG2nqU=
+github.com/yuin/goldmark v1.7.7/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
+github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
+github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
+github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ=
+github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
+go.abhg.dev/goldmark/frontmatter v0.2.0 h1:P8kPG0YkL12+aYk2yU3xHv4tcXzeVnN+gU0tJ5JnxRw=
+go.abhg.dev/goldmark/frontmatter v0.2.0/go.mod h1:XqrEkZuM57djk7zrlRUB02x8I5J0px76YjkOzhB4YlU=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
+golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
+golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
+golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
+golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
+golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
+golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
+golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
+golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
+golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/tools/tools.go b/tools/tools.go
index 7d8afd6..efef263 100644
--- a/tools/tools.go
+++ b/tools/tools.go
@@ -1,8 +1,15 @@
-//go:build tools
+//go:build generate
 
 package tools
 
 import (
-	// [tfplugindocs](https://github.com/hashicorp/terraform-plugin-docs).
 	_ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs"
 )
+
+// Format Terraform code for use in documentation.
+// If you do not have Terraform installed, you can remove the formatting command, but it is suggested
+// to ensure the documentation is formatted properly.
+//go:generate terraform fmt -recursive ../examples/
+
+// Generate documentation.
+//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs generate --provider-dir ..