Repository: cloudflare/cloudflare-go
Pull request #1014 (2022-08-03 23:49:26)

Support for attaching a Worker to a Domain
## Description

Support for the new Custom Domain API at https://api.cloudflare.com/#worker-domain-attach-to-domain

## Has your change been tested?

Works for me locally, unit tests will be added in PR review.

## Screenshots (if appropriate):

## Types of changes

What sort of change does your code introduce/modify?

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Checklist:

- [x] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [x] I have added tests to cover my changes.
- [x] All new and existing tests passed.
- [x] This change is using publicly documented (api.cloudflare.com or developers.cloudflare.com) 
- [ ] ... and stable APIs. **unclear**.

[1]: https://help.github.com/articles/closing-issues-using-keywords/


github-actions[bot]: Oops! It looks like no changelog entry is attached to this PR. Please include a release note as described in https://github.com/cloudflare/cloudflare-go/blob/master/docs/changelog-process.md.

Example: 

~~~
```release-note:TYPE
Release note
```
~~~

If you do not require a release note to be included, please add the `workflow/skip-changelog-entry` label.
codecov-commenter: # [Codecov](https://codecov.io/gh/cloudflare/cloudflare-go/pull/1014?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudflare) Report
> Merging [#1014](https://codecov.io/gh/cloudflare/cloudflare-go/pull/1014?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudflare) (3c3ae65) into [master](https://codecov.io/gh/cloudflare/cloudflare-go/commit/6c5ea4aae34d51ef65c6898d105fa4f3694e21d4?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudflare) (6c5ea4a) will **decrease** coverage by `0.08%`.
> The diff coverage is `0.00%`.

```diff
@@            Coverage Diff             @@
##           master    #1014      +/-   ##
==========================================
- Coverage   49.06%   48.97%   -0.09%     
==========================================
  Files         108      108              
  Lines       10428    10446      +18     
==========================================
  Hits         5116     5116              
- Misses       4200     4218      +18     
  Partials     1112     1112              
```


| [Impacted Files](https://codecov.io/gh/cloudflare/cloudflare-go/pull/1014?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudflare) | Coverage Δ | |
|---|---|---|
| [access\_application.go](https://codecov.io/gh/cloudflare/cloudflare-go/pull/1014/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudflare#diff-YWNjZXNzX2FwcGxpY2F0aW9uLmdv) | `76.52% <ø> (ø)` | |
| [access\_bookmark.go](https://codecov.io/gh/cloudflare/cloudflare-go/pull/1014/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudflare#diff-YWNjZXNzX2Jvb2ttYXJrLmdv) | `72.44% <ø> (ø)` | |
| [workers.go](https://codecov.io/gh/cloudflare/cloudflare-go/pull/1014/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudflare#diff-d29ya2Vycy5nbw==) | `66.27% <0.00%> (-2.44%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudflare).


Patch:
diff --git a/.changelog/1010.txt b/.changelog/1010.txt
deleted file mode 100644
index df85b31f4..000000000
--- a/.changelog/1010.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:enhancement
-workers: Add support to upload module workers
-```
diff --git a/.changelog/1014.txt b/.changelog/1014.txt
new file mode 100644
index 000000000..a9bbb904d
--- /dev/null
+++ b/.changelog/1014.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+workers: Add support for attaching a worker to a domain
+```
diff --git a/.changelog/1016.txt b/.changelog/1016.txt
deleted file mode 100644
index 753e4646b..000000000
--- a/.changelog/1016.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-```release-note:enhancement
-firewall_rule: fix double endpoint calls & moving towards common method signature
-```
-
-```release-note:enhancement
-filter: fix double endpoint calls & moving towards common method signature
-```
diff --git a/.changelog/1017.txt b/.changelog/1017.txt
deleted file mode 100644
index 56bd30386..000000000
--- a/.changelog/1017.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:enhancement
-lockdown: automatically paginate `List` results unless `Page` and `PerPage` are provided
-```
\ No newline at end of file
diff --git a/.changelog/1030.txt b/.changelog/1030.txt
deleted file mode 100644
index 7a5ff365a..000000000
--- a/.changelog/1030.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:bug
-tunnel_routes: Fix not removing route when it contains virtual network
-```
\ No newline at end of file
diff --git a/.changelog/1031.txt b/.changelog/1031.txt
deleted file mode 100644
index 3d039fe45..000000000
--- a/.changelog/1031.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:enhancement
-workers-subdomain: Add in support Workers Subdomain API
-```
\ No newline at end of file
diff --git a/.changelog/1034.txt b/.changelog/1034.txt
deleted file mode 100644
index bd57aca22..000000000
--- a/.changelog/1034.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-```release-note:enhancement
-email_routing_destination: Adds support for the email routing destination API
-```
-```release-note:enhancement
-email_routing_rules: Adds support for the email routing rules API
-```
-```release-note:enhancement
-email_routing_settings: Adds support for the email routing settings API
-```
\ No newline at end of file
diff --git a/.changelog/1037.txt b/.changelog/1037.txt
deleted file mode 100644
index 3159870ac..000000000
--- a/.changelog/1037.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:dependency
-provider: bumps golang.org/x/tools/gopls from 0.9.1 to 0.9.2
-```
diff --git a/.changelog/1038.txt b/.changelog/1038.txt
deleted file mode 100644
index 23286c802..000000000
--- a/.changelog/1038.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-```release-note:bug
-email_routing_destination: Update API reference URLs
-```
-```release-note:bug
-email_routing_rules: Update API reference URLs
-```
-```release-note:bug
-email_routing_settings: Update API reference URLs
-```
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index edc209db6..73a2af949 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,29 +2,13 @@
 
 ENHANCEMENTS:
 
-* email_routing_destination: Adds support for the email routing destination API ([#1034](https://github.com/cloudflare/cloudflare-go/issues/1034))
-* email_routing_rules: Adds support for the email routing rules API ([#1034](https://github.com/cloudflare/cloudflare-go/issues/1034))
-* email_routing_settings: Adds support for the email routing settings API ([#1034](https://github.com/cloudflare/cloudflare-go/issues/1034))
-* filter: fix double endpoint calls & moving towards common method signature ([#1016](https://github.com/cloudflare/cloudflare-go/issues/1016))
-* firewall_rule: fix double endpoint calls & moving towards common method signature ([#1016](https://github.com/cloudflare/cloudflare-go/issues/1016))
-* lockdown: automatically paginate `List` results unless `Page` and `PerPage` are provided ([#1017](https://github.com/cloudflare/cloudflare-go/issues/1017))
 * r2: Add in support for creating and deleting R2 buckets ([#1028](https://github.com/cloudflare/cloudflare-go/issues/1028))
 * workers-account-settings: Add in support for Workers account settings API ([#1027](https://github.com/cloudflare/cloudflare-go/issues/1027))
-* workers-subdomain: Add in support Workers Subdomain API ([#1031](https://github.com/cloudflare/cloudflare-go/issues/1031))
 * workers-tail: Add in support for Workers tail API ([#1026](https://github.com/cloudflare/cloudflare-go/issues/1026))
-* workers: Add support to upload module workers ([#1010](https://github.com/cloudflare/cloudflare-go/issues/1010))
-
-BUG FIXES:
-
-* email_routing_destination: Update API reference URLs ([#1038](https://github.com/cloudflare/cloudflare-go/issues/1038))
-* email_routing_rules: Update API reference URLs ([#1038](https://github.com/cloudflare/cloudflare-go/issues/1038))
-* email_routing_settings: Update API reference URLs ([#1038](https://github.com/cloudflare/cloudflare-go/issues/1038))
-* tunnel_routes: Fix not removing route when it contains virtual network ([#1030](https://github.com/cloudflare/cloudflare-go/issues/1030))
 
 DEPENDENCIES:
 
 * provider: bumps github.com/golangci/golangci-lint from 1.47.3 to 1.48.0 ([#1020](https://github.com/cloudflare/cloudflare-go/issues/1020))
-* provider: bumps golang.org/x/tools/gopls from 0.9.1 to 0.9.2 ([#1037](https://github.com/cloudflare/cloudflare-go/issues/1037))
 
 ## 0.46.0 (3rd August, 2022)
 
diff --git a/cmd/flarectl/zone.go b/cmd/flarectl/zone.go
index 5cd2c81a4..ad771b11c 100644
--- a/cmd/flarectl/zone.go
+++ b/cmd/flarectl/zone.go
@@ -133,25 +133,21 @@ func zoneCreateLockdown(c *cli.Context) error {
 			Value:  c.StringSlice("values")[index],
 		})
 	}
-	params := cloudflare.ZoneLockdownCreateParams{
+	lockdown := cloudflare.ZoneLockdown{
 		Description:    c.String("description"),
 		URLs:           c.StringSlice("urls"),
 		Configurations: zonelockdownconfigs,
 	}
 
-	resp, err := api.CreateZoneLockdown(context.Background(), cloudflare.ZoneIdentifier(zoneID), params)
+	var resp *cloudflare.ZoneLockdownResponse
+
+	resp, err = api.CreateZoneLockdown(context.Background(), zoneID, lockdown)
 	if err != nil {
 		fmt.Fprintln(os.Stderr, "Error creating ZONE lock down: ", err)
 		return err
 	}
-
 	output := make([][]string, 0, 1)
-
-	format := []string{
-		resp.ID,
-	}
-
-	output = append(output, format)
+	output = append(output, formatLockdownResponse(resp))
 
 	writeTable(c, output, "ID")
 
@@ -339,6 +335,12 @@ func formatCacheResponse(resp cloudflare.PurgeCacheResponse) []string {
 	}
 }
 
+func formatLockdownResponse(resp *cloudflare.ZoneLockdownResponse) []string {
+	return []string{
+		resp.Result.ID,
+	}
+}
+
 func zoneExport(c *cli.Context) error {
 	var zone string
 	if c.NArg() > 0 {
diff --git a/email_routing_destination.go b/email_routing_destination.go
deleted file mode 100644
index e9705e559..000000000
--- a/email_routing_destination.go
+++ /dev/null
@@ -1,155 +0,0 @@
-package cloudflare
-
-import (
-	"context"
-	"encoding/json"
-	"fmt"
-	"net/http"
-	"time"
-)
-
-type EmailRoutingDestinationAddress struct {
-	Tag      string     `json:"tag,omitempty"`
-	Email    string     `json:"email,omitempty"`
-	Verified *time.Time `json:"verified,omitempty"`
-	Created  *time.Time `json:"created,omitempty"`
-	Modified *time.Time `json:"modified,omitempty"`
-}
-
-type ListEmailRoutingAddressParameters struct {
-	ResultInfo
-	Direction string `url:"direction,omitempty"`
-	Verified  *bool  `url:"verified,omitempty"`
-}
-
-type ListEmailRoutingAddressResponse struct {
-	Result     []EmailRoutingDestinationAddress `json:"result"`
-	ResultInfo `json:"result_info"`
-	Response
-}
-
-type CreateEmailRoutingAddressParameters struct {
-	Email string `json:"email,omitempty"`
-}
-
-type CreateEmailRoutingAddressResponse struct {
-	Result EmailRoutingDestinationAddress `json:"result,omitempty"`
-	Response
-}
-
-// ListEmailRoutingDestinationAddresses Lists existing destination addresses.
-//
-// API reference: https://api.cloudflare.com/#email-routing-destination-addresses-list-destination-addresses
-func (api *API) ListEmailRoutingDestinationAddresses(ctx context.Context, rc *ResourceContainer, params ListEmailRoutingAddressParameters) ([]EmailRoutingDestinationAddress, *ResultInfo, error) {
-	if rc.Identifier == "" {
-		return []EmailRoutingDestinationAddress{}, &ResultInfo{}, ErrMissingAccountID
-	}
-
-	autoPaginate := true
-	if params.PerPage >= 1 || params.Page >= 1 {
-		autoPaginate = false
-	}
-
-	if params.PerPage < 1 {
-		params.PerPage = 50
-	}
-
-	if params.Page < 1 {
-		params.Page = 1
-	}
-
-	var addresses []EmailRoutingDestinationAddress
-	var eResponse ListEmailRoutingAddressResponse
-	for {
-		uri := buildURI(fmt.Sprintf("/accounts/%s/email/routing/addresses", rc.Identifier), params)
-
-		res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-		if err != nil {
-			return []EmailRoutingDestinationAddress{}, &ResultInfo{}, err
-		}
-		err = json.Unmarshal(res, &eResponse)
-		if err != nil {
-			return []EmailRoutingDestinationAddress{}, &ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-		}
-		addresses = append(addresses, eResponse.Result...)
-		params.ResultInfo = eResponse.ResultInfo.Next()
-		if params.ResultInfo.Done() || !autoPaginate {
-			break
-		}
-	}
-
-	return addresses, &eResponse.ResultInfo, nil
-}
-
-// CreateEmailRoutingDestinationAddress Create a destination address to forward your emails to.
-// Destination addresses need to be verified before they become active.
-//
-// API reference: https://api.cloudflare.com/#email-routing-destination-addresses-create-a-destination-address
-func (api *API) CreateEmailRoutingDestinationAddress(ctx context.Context, rc *ResourceContainer, params CreateEmailRoutingAddressParameters) (EmailRoutingDestinationAddress, error) {
-	if rc.Identifier == "" {
-		return EmailRoutingDestinationAddress{}, ErrMissingAccountID
-	}
-
-	uri := fmt.Sprintf("/accounts/%s/email/routing/addresses", rc.Identifier)
-
-	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params)
-	if err != nil {
-		return EmailRoutingDestinationAddress{}, ErrMissingAccountID
-	}
-
-	var r CreateEmailRoutingAddressResponse
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return EmailRoutingDestinationAddress{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-
-	return r.Result, nil
-}
-
-// GetEmailRoutingDestinationAddress Gets information for a specific destination email already created.
-//
-// API reference: https://api.cloudflare.com/#email-routing-destination-addresses-get-a-destination-address
-func (api *API) GetEmailRoutingDestinationAddress(ctx context.Context, rc *ResourceContainer, addressID string) (EmailRoutingDestinationAddress, error) {
-	if rc.Identifier == "" {
-		return EmailRoutingDestinationAddress{}, ErrMissingAccountID
-	}
-
-	uri := fmt.Sprintf("/accounts/%s/email/routing/addresses/%s", rc.Identifier, addressID)
-
-	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-	if err != nil {
-		return EmailRoutingDestinationAddress{}, ErrMissingAccountID
-	}
-
-	var r CreateEmailRoutingAddressResponse
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return EmailRoutingDestinationAddress{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-
-	return r.Result, nil
-}
-
-// DeleteEmailRoutingDestinationAddress Deletes a specific destination address.
-//
-// API reference: https://api.cloudflare.com/#email-routing-destination-addresses-delete-destination-address
-func (api *API) DeleteEmailRoutingDestinationAddress(ctx context.Context, rc *ResourceContainer, addressID string) (EmailRoutingDestinationAddress, error) {
-	if rc.Identifier == "" {
-		return EmailRoutingDestinationAddress{}, ErrMissingAccountID
-	}
-
-	uri := fmt.Sprintf("/accounts/%s/email/routing/addresses/%s", rc.Identifier, addressID)
-
-	res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
-	if err != nil {
-		return EmailRoutingDestinationAddress{}, ErrMissingAccountID
-	}
-
-	var r CreateEmailRoutingAddressResponse
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return EmailRoutingDestinationAddress{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-
-	return r.Result, nil
-}
diff --git a/email_routing_rules.go b/email_routing_rules.go
deleted file mode 100644
index aa3a694d1..000000000
--- a/email_routing_rules.go
+++ /dev/null
@@ -1,269 +0,0 @@
-package cloudflare
-
-import (
-	"context"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"net/http"
-)
-
-var ErrMissingRuleID = errors.New("required rule id missing")
-
-type EmailRoutingRuleMatcher struct {
-	Type  string `json:"type,omitempty"`
-	Field string `json:"field,omitempty"`
-	Value string `json:"value,omitempty"`
-}
-
-type EmailRoutingRuleAction struct {
-	Type  string   `json:"type,omitempty"`
-	Value []string `json:"value,omitempty"`
-}
-
-type EmailRoutingRule struct {
-	Tag      string                    `json:"tag,omitempty"`
-	Name     string                    `json:"name,omitempty"`
-	Priority int                       `json:"priority,omitempty"`
-	Enabled  *bool                     `json:"enabled,omitempty"`
-	Matchers []EmailRoutingRuleMatcher `json:"matchers,omitempty"`
-	Actions  []EmailRoutingRuleAction  `json:"actions,omitempty"`
-}
-
-type ListEmailRoutingRulesParameters struct {
-	Enabled *bool `url:"enabled,omitempty"`
-	ResultInfo
-}
-
-type ListEmailRoutingRuleResponse struct {
-	Result     []EmailRoutingRule `json:"result"`
-	ResultInfo `json:"result_info,omitempty"`
-	Response
-}
-
-type CreateEmailRoutingRuleParameters struct {
-	Matchers []EmailRoutingRuleMatcher `json:"matchers,omitempty"`
-	Actions  []EmailRoutingRuleAction  `json:"actions,omitempty"`
-	Name     string                    `json:"name,omitempty"`
-	Enabled  *bool                     `json:"enabled,omitempty"`
-	Priority int                       `json:"priority,omitempty"`
-}
-
-type CreateEmailRoutingRuleResponse struct {
-	Result EmailRoutingRule `json:"result"`
-	Response
-}
-
-type GetEmailRoutingRuleResponse struct {
-	Result EmailRoutingRule `json:"result"`
-	Response
-}
-
-type UpdateEmailRoutingRuleParameters struct {
-	Matchers []EmailRoutingRuleMatcher `json:"matchers,omitempty"`
-	Actions  []EmailRoutingRuleAction  `json:"actions,omitempty"`
-	Name     string                    `json:"name,omitempty"`
-	Enabled  *bool                     `json:"enabled,omitempty"`
-	Priority int                       `json:"priority,omitempty"`
-	RuleID   string
-}
-
-type EmailRoutingCatchAllRule struct {
-	Tag      string                    `json:"tag,omitempty"`
-	Name     string                    `json:"name,omitempty"`
-	Enabled  *bool                     `json:"enabled,omitempty"`
-	Matchers []EmailRoutingRuleMatcher `json:"matchers,omitempty"`
-	Actions  []EmailRoutingRuleAction  `json:"actions,omitempty"`
-}
-
-// ListEmailRoutingRules Lists existing routing rules.
-//
-// API reference: https://api.cloudflare.com/#email-routing-routing-rules-list-routing-rules
-func (api *API) ListEmailRoutingRules(ctx context.Context, rc *ResourceContainer, params ListEmailRoutingRulesParameters) ([]EmailRoutingRule, *ResultInfo, error) {
-	if rc.Identifier == "" {
-		return []EmailRoutingRule{}, &ResultInfo{}, ErrMissingZoneID
-	}
-
-	autoPaginate := true
-	if params.PerPage >= 1 || params.Page >= 1 {
-		autoPaginate = false
-	}
-	if params.PerPage < 1 {
-		params.PerPage = 50
-	}
-	if params.Page < 1 {
-		params.Page = 1
-	}
-
-	var rules []EmailRoutingRule
-	var rResponse ListEmailRoutingRuleResponse
-	for {
-		uri := buildURI(fmt.Sprintf("/zones/%s/email/routing/rules", rc.Identifier), params)
-
-		res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-		if err != nil {
-			return []EmailRoutingRule{}, &ResultInfo{}, err
-		}
-
-		err = json.Unmarshal(res, &rResponse)
-		if err != nil {
-			return []EmailRoutingRule{}, &ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-		}
-
-		rules = append(rules, rResponse.Result...)
-		params.ResultInfo = rResponse.ResultInfo.Next()
-		if params.ResultInfo.Done() || !autoPaginate {
-			break
-		}
-	}
-
-	return rules, &rResponse.ResultInfo, nil
-}
-
-// CreateEmailRoutingRule Rules consist of a set of criteria for matching emails (such as an email being sent to a specific custom email address) plus a set of actions to take on the email (like forwarding it to a specific destination address).
-//
-// API reference: https://api.cloudflare.com/#email-routing-routing-rules-create-routing-rule
-func (api *API) CreateEmailRoutingRule(ctx context.Context, rc *ResourceContainer, params CreateEmailRoutingRuleParameters) (EmailRoutingRule, error) {
-	if rc.Identifier == "" {
-		return EmailRoutingRule{}, ErrMissingZoneID
-	}
-
-	uri := fmt.Sprintf("/zones/%s/email/routing/rules", rc.Identifier)
-
-	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params)
-	if err != nil {
-		return EmailRoutingRule{}, err
-	}
-
-	var r CreateEmailRoutingRuleResponse
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return EmailRoutingRule{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-
-	return r.Result, nil
-}
-
-// GetEmailRoutingRule Get information for a specific routing rule already created.
-//
-// API reference: https://api.cloudflare.com/#email-routing-routing-rules-get-routing-rule
-func (api *API) GetEmailRoutingRule(ctx context.Context, rc *ResourceContainer, ruleID string) (EmailRoutingRule, error) {
-	if rc.Identifier == "" {
-		return EmailRoutingRule{}, ErrMissingZoneID
-	}
-
-	uri := fmt.Sprintf("/zones/%s/email/routing/rules/%s", rc.Identifier, ruleID)
-
-	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-	if err != nil {
-		return EmailRoutingRule{}, err
-	}
-
-	var r GetEmailRoutingRuleResponse
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return EmailRoutingRule{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-
-	return r.Result, nil
-}
-
-// UpdateEmailRoutingRule Update actions, matches, or enable/disable specific routing rules
-//
-// API reference: https://api.cloudflare.com/#email-routing-routing-rules-update-routing-rule
-func (api *API) UpdateEmailRoutingRule(ctx context.Context, rc *ResourceContainer, params UpdateEmailRoutingRuleParameters) (EmailRoutingRule, error) {
-	if rc.Identifier == "" {
-		return EmailRoutingRule{}, ErrMissingZoneID
-	}
-
-	if params.RuleID == "" {
-		return EmailRoutingRule{}, ErrMissingRuleID
-	}
-
-	uri := fmt.Sprintf("/zones/%s/email/routing/rules/%s", rc.Identifier, params.RuleID)
-
-	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params)
-	if err != nil {
-		return EmailRoutingRule{}, err
-	}
-
-	var r GetEmailRoutingRuleResponse
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return EmailRoutingRule{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-
-	return r.Result, nil
-}
-
-// DeleteEmailRoutingRule Delete a specific routing rule.
-//
-// API reference: https://api.cloudflare.com/#email-routing-routing-rules-delete-routing-rule
-func (api *API) DeleteEmailRoutingRule(ctx context.Context, rc *ResourceContainer, ruleID string) (EmailRoutingRule, error) {
-	if rc.Identifier == "" {
-		return EmailRoutingRule{}, ErrMissingZoneID
-	}
-
-	uri := fmt.Sprintf("/zones/%s/email/routing/rules/%s", rc.Identifier, ruleID)
-
-	res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
-	if err != nil {
-		return EmailRoutingRule{}, err
-	}
-
-	var r GetEmailRoutingRuleResponse
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return EmailRoutingRule{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-
-	return r.Result, nil
-}
-
-// GetEmailRoutingCatchAllRule Get information on the default catch-all routing rule.
-//
-// API reference: https://api.cloudflare.com/#email-routing-routing-rules-get-catch-all-rule
-func (api *API) GetEmailRoutingCatchAllRule(ctx context.Context, rc *ResourceContainer) (EmailRoutingCatchAllRule, error) {
-	if rc.Identifier == "" {
-		return EmailRoutingCatchAllRule{}, ErrMissingZoneID
-	}
-
-	uri := fmt.Sprintf("/zones/%s/email/routing/rules/catch_all", rc.Identifier)
-
-	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-	if err != nil {
-		return EmailRoutingCatchAllRule{}, err
-	}
-
-	var r EmailRoutingCatchAllRule
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return EmailRoutingCatchAllRule{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-
-	return r, nil
-}
-
-// UpdateEmailRoutingCatchAllRule Enable or disable catch-all routing rule, or change action to forward to specific destination address.
-//
-// API reference: https://api.cloudflare.com/#email-routing-routing-rules-update-catch-all-rule
-func (api *API) UpdateEmailRoutingCatchAllRule(ctx context.Context, rc *ResourceContainer, params EmailRoutingCatchAllRule) (EmailRoutingCatchAllRule, error) {
-	if rc.Identifier == "" {
-		return EmailRoutingCatchAllRule{}, ErrMissingZoneID
-	}
-
-	uri := fmt.Sprintf("/zones/%s/email/routing/rules/catch_all", rc.Identifier)
-
-	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params)
-	if err != nil {
-		return EmailRoutingCatchAllRule{}, err
-	}
-
-	var r EmailRoutingCatchAllRule
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return EmailRoutingCatchAllRule{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-
-	return r, nil
-}
diff --git a/email_routing_settings.go b/email_routing_settings.go
deleted file mode 100644
index 016605536..000000000
--- a/email_routing_settings.go
+++ /dev/null
@@ -1,117 +0,0 @@
-package cloudflare
-
-import (
-	"context"
-	"encoding/json"
-	"fmt"
-	"net/http"
-	"time"
-)
-
-type EmailRoutingSettings struct {
-	Tag        string     `json:"tag,omitempty"`
-	Name       string     `json:"name,omitempty"`
-	Enabled    bool       `json:"enabled,omitempty"`
-	Created    *time.Time `json:"created,omitempty"`
-	Modified   *time.Time `json:"modified,omitempty"`
-	SkipWizard *bool      `json:"skip_wizard,omitempty"`
-	Status     string     `json:"status,omitempty"`
-}
-
-type EmailRoutingSettingsResponse struct {
-	Result EmailRoutingSettings `json:"result,omitempty"`
-	Response
-}
-
-type EmailRoutingDNSSettingsResponse struct {
-	Result []DNSRecord `json:"result,omitempty"`
-	Response
-}
-
-// GetEmailRoutingSettings Get information about the settings for your Email Routing zone.
-//
-// API reference: https://api.cloudflare.com/#email-routing-settings-get-email-routing-settings
-func (api *API) GetEmailRoutingSettings(ctx context.Context, rc *ResourceContainer) (EmailRoutingSettings, error) {
-	if rc.Identifier == "" {
-		return EmailRoutingSettings{}, ErrMissingZoneID
-	}
-
-	uri := fmt.Sprintf("/zones/%s/email/routing", rc.Identifier)
-	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-	if err != nil {
-		return EmailRoutingSettings{}, err
-	}
-
-	var r EmailRoutingSettingsResponse
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return EmailRoutingSettings{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-
-	return r.Result, nil
-}
-
-// EnableEmailRouting Enable you Email Routing zone. Add and lock the necessary MX and SPF records.
-//
-// API reference: https://api.cloudflare.com/#email-routing-settings-enable-email-routing
-func (api *API) EnableEmailRouting(ctx context.Context, rc *ResourceContainer) (EmailRoutingSettings, error) {
-	if rc.Identifier == "" {
-		return EmailRoutingSettings{}, ErrMissingZoneID
-	}
-	uri := fmt.Sprintf("/zones/%s/email/routing/enabled", rc.Identifier)
-	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, nil)
-	if err != nil {
-		return EmailRoutingSettings{}, err
-	}
-
-	var r EmailRoutingSettingsResponse
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return EmailRoutingSettings{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-
-	return r.Result, nil
-}
-
-// DisableEmailRouting Disable your Email Routing zone. Also removes additional MX records previously required for Email Routing to work.
-//
-// API reference: https://api.cloudflare.com/#email-routing-settings-disable-email-routing
-func (api *API) DisableEmailRouting(ctx context.Context, rc *ResourceContainer) (EmailRoutingSettings, error) {
-	if rc.Identifier == "" {
-		return EmailRoutingSettings{}, ErrMissingZoneID
-	}
-
-	uri := fmt.Sprintf("/zones/%s/email/routing/disable", rc.Identifier)
-	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, nil)
-	if err != nil {
-		return EmailRoutingSettings{}, err
-	}
-
-	var r EmailRoutingSettingsResponse
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return EmailRoutingSettings{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-	return r.Result, nil
-}
-
-// GetEmailRoutingDNSSettings Show the DNS records needed to configure your Email Routing zone.
-//
-// API reference: https://api.cloudflare.com/#email-routing-settings-email-routing---dns-settings
-func (api *API) GetEmailRoutingDNSSettings(ctx context.Context, rc *ResourceContainer) ([]DNSRecord, error) {
-	if rc.Identifier == "" {
-		return []DNSRecord{}, ErrMissingZoneID
-	}
-	uri := fmt.Sprintf("/zones/%s/email/routing/dns", rc.Identifier)
-	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-	if err != nil {
-		return []DNSRecord{}, err
-	}
-
-	var r EmailRoutingDNSSettingsResponse
-	err = json.Unmarshal(res, &r)
-	if err != nil {
-		return []DNSRecord{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-	return r.Result, nil
-}
diff --git a/filter.go b/filter.go
index 532bf5617..2b342feb0 100644
--- a/filter.go
+++ b/filter.go
@@ -60,26 +60,6 @@ type FilterValidationExpressionMessage struct {
 	Message string `json:"message"`
 }
 
-// FilterCreateParams contains required and optional params
-// for creating a filter.
-type FilterCreateParams struct {
-	ID          string `json:"id,omitempty"`
-	Expression  string `json:"expression"`
-	Paused      bool   `json:"paused"`
-	Description string `json:"description"`
-	Ref         string `json:"ref,omitempty"`
-}
-
-// FilterUpdateParams contains required and optional params
-// for updating a filter.
-type FilterUpdateParams struct {
-	ID          string `json:"id"`
-	Expression  string `json:"expression"`
-	Paused      bool   `json:"paused"`
-	Description string `json:"description"`
-	Ref         string `json:"ref,omitempty"`
-}
-
 type FilterListParams struct {
 	ResultInfo
 }
@@ -104,57 +84,62 @@ func (api *API) Filter(ctx context.Context, rc *ResourceContainer, filterID stri
 	return filterResponse.Result, nil
 }
 
-// Filters returns filters for a zone.
+// Filters returns all filters for a zone.
 //
 // Automatically paginates all results unless `params.PerPage` and `params.Page`
 // is set.
 //
 // API reference: https://developers.cloudflare.com/firewall/api/cf-filters/get/#get-all-filters
 func (api *API) Filters(ctx context.Context, rc *ResourceContainer, params FilterListParams) ([]Filter, *ResultInfo, error) {
-	autoPaginate := true
-	if params.PerPage >= 1 || params.Page >= 1 {
-		autoPaginate = false
-	}
-	if params.PerPage < 1 {
-		params.PerPage = 50
+	uri := buildURI(fmt.Sprintf("/zones/%s/filters", rc.Identifier), params)
+
+	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return []Filter{}, &ResultInfo{}, err
 	}
-	if params.Page < 1 {
-		params.Page = 1
+
+	var filtersResponse FiltersDetailResponse
+	err = json.Unmarshal(res, &filtersResponse)
+
+	if err != nil {
+		return []Filter{}, &ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
 	}
 
-	var filters []Filter
-	var fResponse FiltersDetailResponse
-	for {
-		uri := buildURI(fmt.Sprintf("/zones/%s/filters", rc.Identifier), params)
+	if params.PerPage < 1 && params.Page < 1 {
+		var filters []Filter
+		params.PerPage = 50
+		params.Page = 1
 
-		res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-		if err != nil {
-			return []Filter{}, &ResultInfo{}, err
-		}
+		for !params.ResultInfo.Done() {
+			uri := buildURI(fmt.Sprintf("/zones/%s/filters", rc.Identifier), params)
 
-		err = json.Unmarshal(res, &fResponse)
-		if err != nil {
-			return []Filter{}, &ResultInfo{}, fmt.Errorf("failed to unmarshal filters JSON data: %w", err)
-		}
+			res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
+			if err != nil {
+				return []Filter{}, &ResultInfo{}, err
+			}
 
-		filters = append(filters, fResponse.Result...)
-		params.ResultInfo = fResponse.ResultInfo.Next()
+			var fResponse FiltersDetailResponse
+			err = json.Unmarshal(res, &fResponse)
+			if err != nil {
+				return []Filter{}, &ResultInfo{}, fmt.Errorf("failed to unmarshal filters JSON data: %w", err)
+			}
 
-		if params.ResultInfo.Done() || !autoPaginate {
-			break
+			filters = append(filters, fResponse.Result...)
+			params.ResultInfo = fResponse.ResultInfo.Next()
 		}
+		filtersResponse.Result = filters
 	}
 
-	return filters, &fResponse.ResultInfo, nil
+	return filtersResponse.Result, &filtersResponse.ResultInfo, nil
 }
 
 // CreateFilters creates new filters.
 //
 // API reference: https://developers.cloudflare.com/firewall/api/cf-filters/post/
-func (api *API) CreateFilters(ctx context.Context, rc *ResourceContainer, params []FilterCreateParams) ([]Filter, error) {
+func (api *API) CreateFilters(ctx context.Context, rc *ResourceContainer, filters []Filter) ([]Filter, error) {
 	uri := fmt.Sprintf("/zones/%s/filters", rc.Identifier)
 
-	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params)
+	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, filters)
 	if err != nil {
 		return []Filter{}, err
 	}
@@ -171,14 +156,14 @@ func (api *API) CreateFilters(ctx context.Context, rc *ResourceContainer, params
 // UpdateFilter updates a single filter.
 //
 // API reference: https://developers.cloudflare.com/firewall/api/cf-filters/put/#update-a-single-filter
-func (api *API) UpdateFilter(ctx context.Context, rc *ResourceContainer, params FilterUpdateParams) (Filter, error) {
-	if params.ID == "" {
+func (api *API) UpdateFilter(ctx context.Context, rc *ResourceContainer, filter Filter) (Filter, error) {
+	if filter.ID == "" {
 		return Filter{}, fmt.Errorf("filter ID cannot be empty")
 	}
 
-	uri := fmt.Sprintf("/zones/%s/filters/%s", rc.Identifier, params.ID)
+	uri := fmt.Sprintf("/zones/%s/filters/%s", rc.Identifier, filter.ID)
 
-	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params)
+	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, filter)
 	if err != nil {
 		return Filter{}, err
 	}
@@ -195,8 +180,8 @@ func (api *API) UpdateFilter(ctx context.Context, rc *ResourceContainer, params
 // UpdateFilters updates many filters at once.
 //
 // API reference: https://developers.cloudflare.com/firewall/api/cf-filters/put/#update-multiple-filters
-func (api *API) UpdateFilters(ctx context.Context, rc *ResourceContainer, params []FilterUpdateParams) ([]Filter, error) {
-	for _, filter := range params {
+func (api *API) UpdateFilters(ctx context.Context, rc *ResourceContainer, filters []Filter) ([]Filter, error) {
+	for _, filter := range filters {
 		if filter.ID == "" {
 			return []Filter{}, fmt.Errorf("filter ID cannot be empty")
 		}
@@ -204,7 +189,7 @@ func (api *API) UpdateFilters(ctx context.Context, rc *ResourceContainer, params
 
 	uri := fmt.Sprintf("/zones/%s/filters", rc.Identifier)
 
-	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params)
+	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, filters)
 	if err != nil {
 		return []Filter{}, err
 	}
diff --git a/firewall_rules.go b/firewall_rules.go
index 4d5636c37..a0026b4a8 100644
--- a/firewall_rules.go
+++ b/firewall_rules.go
@@ -18,7 +18,6 @@ type FirewallRule struct {
 	Priority    interface{} `json:"priority"`
 	Filter      Filter      `json:"filter"`
 	Products    []string    `json:"products,omitempty"`
-	Ref         string      `json:"ref,omitempty"`
 	CreatedOn   time.Time   `json:"created_on,omitempty"`
 	ModifiedOn  time.Time   `json:"modified_on,omitempty"`
 }
@@ -39,78 +38,53 @@ type FirewallRuleResponse struct {
 	Response
 }
 
-// FirewallRuleCreateParams contains required and optional params
-// for creating a firewall rule.
-type FirewallRuleCreateParams struct {
-	ID          string      `json:"id,omitempty"`
-	Paused      bool        `json:"paused"`
-	Description string      `json:"description"`
-	Action      string      `json:"action"`
-	Priority    interface{} `json:"priority"`
-	Filter      Filter      `json:"filter"`
-	Products    []string    `json:"products,omitempty"`
-	Ref         string      `json:"ref,omitempty"`
-}
-
-// FirewallRuleUpdateParams contains required and optional params
-// for updating a firewall rule.
-type FirewallRuleUpdateParams struct {
-	ID          string      `json:"id"`
-	Paused      bool        `json:"paused"`
-	Description string      `json:"description"`
-	Action      string      `json:"action"`
-	Priority    interface{} `json:"priority"`
-	Filter      Filter      `json:"filter"`
-	Products    []string    `json:"products,omitempty"`
-	Ref         string      `json:"ref,omitempty"`
-}
-
 type FirewallRuleListParams struct {
 	ResultInfo
 }
 
 // FirewallRules returns all firewall rules.
 //
-// Automatically paginates all results unless `params.PerPage` and `params.Page`
-// is set.
-//
 // API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/get/#get-all-rules
 func (api *API) FirewallRules(ctx context.Context, rc *ResourceContainer, params FirewallRuleListParams) ([]FirewallRule, *ResultInfo, error) {
-	autoPaginate := true
-	if params.PerPage >= 1 || params.Page >= 1 {
-		autoPaginate = false
-	}
-	if params.PerPage < 1 {
-		params.PerPage = 50
+	uri := buildURI(fmt.Sprintf("/zones/%s/firewall/rules", rc.Identifier), params)
+
+	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return []FirewallRule{}, &ResultInfo{}, err
 	}
-	if params.Page < 1 {
-		params.Page = 1
+
+	var firewallDetailResponse FirewallRulesDetailResponse
+	err = json.Unmarshal(res, &firewallDetailResponse)
+	if err != nil {
+		return []FirewallRule{}, &ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
 	}
 
-	var firewallRules []FirewallRule
-	var fResponse FirewallRulesDetailResponse
-	for {
-		uri := buildURI(fmt.Sprintf("/zones/%s/firewall/rules", rc.Identifier), params)
+	if params.PerPage < 1 && params.Page < 1 {
+		var firewallRules []FirewallRule
+		params.PerPage = 50
+		params.Page = 1
 
-		res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-		if err != nil {
-			return []FirewallRule{}, &ResultInfo{}, err
-		}
+		for !params.ResultInfo.Done() {
+			uri := buildURI(fmt.Sprintf("/zones/%s/firewall/rules", rc.Identifier), params)
 
-		err = json.Unmarshal(res, &fResponse)
-		if err != nil {
-			return []FirewallRule{}, &ResultInfo{}, fmt.Errorf("failed to unmarshal filters JSON data: %w", err)
-		}
+			res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
+			if err != nil {
+				return []FirewallRule{}, &ResultInfo{}, err
+			}
 
-		firewallRules = append(firewallRules, fResponse.Result...)
-		params.ResultInfo = fResponse.ResultInfo.Next()
+			var fResponse FirewallRulesDetailResponse
+			err = json.Unmarshal(res, &fResponse)
+			if err != nil {
+				return []FirewallRule{}, &ResultInfo{}, fmt.Errorf("failed to unmarshal filters JSON data: %w", err)
+			}
 
-		if params.ResultInfo.Done() || !autoPaginate {
-			break
+			firewallRules = append(firewallRules, fResponse.Result...)
+			params.ResultInfo = fResponse.ResultInfo.Next()
 		}
+		firewallDetailResponse.Result = firewallRules
 	}
 
-	return firewallRules, &fResponse.ResultInfo, nil
+	return firewallDetailResponse.Result, &firewallDetailResponse.ResultInfo, nil
 }
 
 // FirewallRule returns a single firewall rule based on the ID.
@@ -136,10 +110,10 @@ func (api *API) FirewallRule(ctx context.Context, rc *ResourceContainer, firewal
 // CreateFirewallRules creates new firewall rules.
 //
 // API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/post/
-func (api *API) CreateFirewallRules(ctx context.Context, rc *ResourceContainer, params []FirewallRuleCreateParams) ([]FirewallRule, error) {
+func (api *API) CreateFirewallRules(ctx context.Context, rc *ResourceContainer, firewallRules []FirewallRule) ([]FirewallRule, error) {
 	uri := fmt.Sprintf("/zones/%s/firewall/rules", rc.Identifier)
 
-	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params)
+	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, firewallRules)
 	if err != nil {
 		return []FirewallRule{}, err
 	}
@@ -156,14 +130,14 @@ func (api *API) CreateFirewallRules(ctx context.Context, rc *ResourceContainer,
 // UpdateFirewallRule updates a single firewall rule.
 //
 // API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/put/#update-a-single-rule
-func (api *API) UpdateFirewallRule(ctx context.Context, rc *ResourceContainer, params FirewallRuleUpdateParams) (FirewallRule, error) {
-	if params.ID == "" {
+func (api *API) UpdateFirewallRule(ctx context.Context, rc *ResourceContainer, firewallRule FirewallRule) (FirewallRule, error) {
+	if firewallRule.ID == "" {
 		return FirewallRule{}, fmt.Errorf("firewall rule ID cannot be empty")
 	}
 
-	uri := fmt.Sprintf("/zones/%s/firewall/rules/%s", rc.Identifier, params.ID)
+	uri := fmt.Sprintf("/zones/%s/firewall/rules/%s", rc.Identifier, firewallRule.ID)
 
-	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params)
+	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, firewallRule)
 	if err != nil {
 		return FirewallRule{}, err
 	}
@@ -180,8 +154,8 @@ func (api *API) UpdateFirewallRule(ctx context.Context, rc *ResourceContainer, p
 // UpdateFirewallRules updates a single firewall rule.
 //
 // API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/put/#update-multiple-rules
-func (api *API) UpdateFirewallRules(ctx context.Context, rc *ResourceContainer, params []FirewallRuleUpdateParams) ([]FirewallRule, error) {
-	for _, firewallRule := range params {
+func (api *API) UpdateFirewallRules(ctx context.Context, rc *ResourceContainer, firewallRules []FirewallRule) ([]FirewallRule, error) {
+	for _, firewallRule := range firewallRules {
 		if firewallRule.ID == "" {
 			return []FirewallRule{}, fmt.Errorf("firewall ID cannot be empty")
 		}
@@ -189,7 +163,7 @@ func (api *API) UpdateFirewallRules(ctx context.Context, rc *ResourceContainer,
 
 	uri := fmt.Sprintf("/zones/%s/firewall/rules", rc.Identifier)
 
-	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params)
+	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, firewallRules)
 	if err != nil {
 		return []FirewallRule{}, err
 	}
diff --git a/go.mod b/go.mod
index 5e4f56828..d3a03d072 100644
--- a/go.mod
+++ b/go.mod
@@ -22,7 +22,7 @@ require (
 	golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
 	golang.org/x/net v0.0.0-20220722155237-a158d28d115b
 	golang.org/x/time v0.0.0-20220224211638-0e9765cccd65
-	golang.org/x/tools/gopls v0.9.2
+	golang.org/x/tools/gopls v0.9.1
 )
 
 require (
@@ -224,14 +224,14 @@ require (
 	go.uber.org/multierr v1.6.0 // indirect
 	go.uber.org/zap v1.17.0 // indirect
 	golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4 // indirect
-	golang.org/x/exp/typeparams v0.0.0-20220722155223-a9213eeb770e // indirect
+	golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d // indirect
 	golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
 	golang.org/x/oauth2 v0.0.0-20220718184931-c8730f7fcb92
 	golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
 	golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
 	golang.org/x/text v0.3.7 // indirect
-	golang.org/x/tools v0.1.13-0.20220808185556-e884e0ef6dcd // indirect
-	golang.org/x/vuln v0.0.0-20220725105440-4151a5aca1df // indirect
+	golang.org/x/tools v0.1.12 // indirect
+	golang.org/x/vuln v0.0.0-20220613164644-4eb5ba49563c // indirect
 	google.golang.org/protobuf v1.28.0 // indirect
 	gopkg.in/ini.v1 v1.66.6 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index 7c1123436..6ae87bca1 100644
--- a/go.sum
+++ b/go.sum
@@ -74,6 +74,7 @@ github.com/Antonboom/nilnil v0.1.1 h1:PHhrh5ANKFWRBh7TdYmyyq2gyT2lotnvFvvFbylF81
 github.com/Antonboom/nilnil v0.1.1/go.mod h1:L1jBqoWM7AOeTD+tSquifKSesRHs4ZdaxvZR+xdJEaI=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
 github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
 github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
 github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
@@ -1236,9 +1237,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk
 golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 h1:FR+oGxGfbQu1d+jglI3rCkjAjUnhRSZcUxr+DqlDLNo=
 golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
 golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d h1:+W8Qf4iJtMGKkyAygcKohjxTk4JPsL9DpzApJ22m5Ic=
 golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
-golang.org/x/exp/typeparams v0.0.0-20220722155223-a9213eeb770e h1:7Xs2YCOpMlNqSQSmrrnhlzBXIE/bpMecZplbLePTJvE=
-golang.org/x/exp/typeparams v0.0.0-20220722155223-a9213eeb770e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
 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=
@@ -1625,13 +1625,13 @@ golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f/go.mod h1:SgwaegtQh8clI
 golang.org/x/tools v0.1.11-0.20220523181440-ccb10502d1a5/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
 golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
 golang.org/x/tools v0.1.12-0.20220628192153-7743d1d949f1/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
+golang.org/x/tools v0.1.12-0.20220713141851-7464a5a40219/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
+golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.1.13-0.20220808185556-e884e0ef6dcd h1:Rzj/yc/uLVufpyZHLXp15/1D21FZXqcNTby8xIi0CQA=
-golang.org/x/tools v0.1.13-0.20220808185556-e884e0ef6dcd/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools/gopls v0.9.2 h1:iHtOeH75M+RhCxj5Dwgvx29z3Ok0VkmyTNL2Xj7chj4=
-golang.org/x/tools/gopls v0.9.2/go.mod h1:lr+LHF9Az8coBj71HqUHv+0kNja1oL/7TaJXVZseC+M=
-golang.org/x/vuln v0.0.0-20220725105440-4151a5aca1df h1:BkeW9/QJhcigekDUPS9N9bIb0v7gPKKmLYeczVAqr2s=
-golang.org/x/vuln v0.0.0-20220725105440-4151a5aca1df/go.mod h1:UZshlUPxXeGUM9I14UOawXQg6yosDE9cr1vKY/DzgWo=
+golang.org/x/tools/gopls v0.9.1 h1:SigsTL4Hpv3a6b/a7oPCLRv5QUeSM6PZNdta1oKY4B0=
+golang.org/x/tools/gopls v0.9.1/go.mod h1:fkgIFE0meep1WkUekyJZAgyUIVrbjkTNtc1JEZxZYg8=
+golang.org/x/vuln v0.0.0-20220613164644-4eb5ba49563c h1:r5bbIROBQtRRgoutV8Q3sFY58VzHW6jMBYl48ANSyS4=
+golang.org/x/vuln v0.0.0-20220613164644-4eb5ba49563c/go.mod h1:UZshlUPxXeGUM9I14UOawXQg6yosDE9cr1vKY/DzgWo=
 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=
@@ -1887,6 +1887,7 @@ honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
 honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw=
 honnef.co/go/tools v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=
 honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw=
+mvdan.cc/gofumpt v0.3.0/go.mod h1:0+VyGZWleeIj5oostkOex+nDBA0eyavuDnDusAJ8ylo=
 mvdan.cc/gofumpt v0.3.1 h1:avhhrOmv0IuvQVK7fvwV91oFSGAk5/6Po8GXTzICeu8=
 mvdan.cc/gofumpt v0.3.1/go.mod h1:w3ymliuxvzVx8DAutBnVyDqYb1Niy/yCJt/lk821YCE=
 mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I=
diff --git a/lockdown.go b/lockdown.go
index bcbdd11f5..50009f796 100644
--- a/lockdown.go
+++ b/lockdown.go
@@ -5,6 +5,8 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
+	"net/url"
+	"strconv"
 	"time"
 )
 
@@ -44,145 +46,109 @@ type ZoneLockdownListResponse struct {
 	ResultInfo `json:"result_info"`
 }
 
-// ZoneLockdownCreateParams contains required and optional params
-// for creating a zone lockdown.
-type ZoneLockdownCreateParams struct {
-	Description    string               `json:"description"`
-	URLs           []string             `json:"urls"`
-	Configurations []ZoneLockdownConfig `json:"configurations"`
-	Paused         bool                 `json:"paused"`
-}
-
-// ZoneLockdownUpdateParams contains required and optional params
-// for updating a zone lockdown.
-type ZoneLockdownUpdateParams struct {
-	ID             string               `json:"id"`
-	Description    string               `json:"description"`
-	URLs           []string             `json:"urls"`
-	Configurations []ZoneLockdownConfig `json:"configurations"`
-	Paused         bool                 `json:"paused"`
-}
-
-type LockdownListParams struct {
-	ResultInfo
-}
-
 // CreateZoneLockdown creates a Zone ZoneLockdown rule for the given zone ID.
 //
 // API reference: https://api.cloudflare.com/#zone-ZoneLockdown-create-a-ZoneLockdown-rule
-func (api *API) CreateZoneLockdown(ctx context.Context, rc *ResourceContainer, params ZoneLockdownCreateParams) (ZoneLockdown, error) {
-	uri := fmt.Sprintf("/zones/%s/firewall/lockdowns", rc.Identifier)
-	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params)
+func (api *API) CreateZoneLockdown(ctx context.Context, zoneID string, ld ZoneLockdown) (*ZoneLockdownResponse, error) {
+	uri := fmt.Sprintf("/zones/%s/firewall/lockdowns", zoneID)
+	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, ld)
 	if err != nil {
-		return ZoneLockdown{}, err
+		return nil, err
 	}
 
 	response := &ZoneLockdownResponse{}
 	err = json.Unmarshal(res, &response)
 	if err != nil {
-		return ZoneLockdown{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
+		return nil, fmt.Errorf("%s: %w", errUnmarshalError, err)
 	}
 
-	return response.Result, nil
+	return response, nil
 }
 
-// UpdateZoneLockdown updates a Zone ZoneLockdown rule (based on the ID) for the given zone ID.
+// UpdateZoneLockdown updates a Zone ZoneLockdown rule (based on the ID) for the
+// given zone ID.
 //
 // API reference: https://api.cloudflare.com/#zone-ZoneLockdown-update-ZoneLockdown-rule
-func (api *API) UpdateZoneLockdown(ctx context.Context, rc *ResourceContainer, params ZoneLockdownUpdateParams) (ZoneLockdown, error) {
-	uri := fmt.Sprintf("/zones/%s/firewall/lockdowns/%s", rc.Identifier, params.ID)
-	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params)
+func (api *API) UpdateZoneLockdown(ctx context.Context, zoneID string, id string, ld ZoneLockdown) (*ZoneLockdownResponse, error) {
+	uri := fmt.Sprintf("/zones/%s/firewall/lockdowns/%s", zoneID, id)
+	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, ld)
 	if err != nil {
-		return ZoneLockdown{}, err
+		return nil, err
 	}
 
 	response := &ZoneLockdownResponse{}
 	err = json.Unmarshal(res, &response)
 	if err != nil {
-		return ZoneLockdown{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
+		return nil, fmt.Errorf("%s: %w", errUnmarshalError, err)
 	}
 
-	return response.Result, nil
+	return response, nil
 }
 
-// DeleteZoneLockdown deletes a Zone ZoneLockdown rule (based on the ID) for the given zone ID.
+// DeleteZoneLockdown deletes a Zone ZoneLockdown rule (based on the ID) for the
+// given zone ID.
 //
 // API reference: https://api.cloudflare.com/#zone-ZoneLockdown-delete-ZoneLockdown-rule
-func (api *API) DeleteZoneLockdown(ctx context.Context, rc *ResourceContainer, id string) (ZoneLockdown, error) {
-	uri := fmt.Sprintf("/zones/%s/firewall/lockdowns/%s", rc.Identifier, id)
+func (api *API) DeleteZoneLockdown(ctx context.Context, zoneID string, id string) (*ZoneLockdownResponse, error) {
+	uri := fmt.Sprintf("/zones/%s/firewall/lockdowns/%s", zoneID, id)
 	res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
-		return ZoneLockdown{}, err
+		return nil, err
 	}
 
 	response := &ZoneLockdownResponse{}
 	err = json.Unmarshal(res, &response)
 	if err != nil {
-		return ZoneLockdown{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
+		return nil, fmt.Errorf("%s: %w", errUnmarshalError, err)
 	}
 
-	return response.Result, nil
+	return response, nil
 }
 
-// ZoneLockdown retrieves a Zone ZoneLockdown rule (based on the ID) for the given zone ID.
+// ZoneLockdown retrieves a Zone ZoneLockdown rule (based on the ID) for the
+// given zone ID.
 //
 // API reference: https://api.cloudflare.com/#zone-ZoneLockdown-ZoneLockdown-rule-details
-func (api *API) ZoneLockdown(ctx context.Context, rc *ResourceContainer, id string) (ZoneLockdown, error) {
-	uri := fmt.Sprintf("/zones/%s/firewall/lockdowns/%s", rc.Identifier, id)
+func (api *API) ZoneLockdown(ctx context.Context, zoneID string, id string) (*ZoneLockdownResponse, error) {
+	uri := fmt.Sprintf("/zones/%s/firewall/lockdowns/%s", zoneID, id)
 	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return ZoneLockdown{}, err
+		return nil, err
 	}
 
 	response := &ZoneLockdownResponse{}
 	err = json.Unmarshal(res, &response)
 	if err != nil {
-		return ZoneLockdown{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
+		return nil, fmt.Errorf("%s: %w", errUnmarshalError, err)
 	}
 
-	return response.Result, nil
+	return response, nil
 }
 
-// ListZoneLockdowns retrieves every Zone ZoneLockdown rules for a given zone ID.
-//
-// Automatically paginates all results unless `params.PerPage` and `params.Page`
-// is set.
+// ListZoneLockdowns retrieves a list of Zone ZoneLockdown rules for a given
+// zone ID by page number.
 //
 // API reference: https://api.cloudflare.com/#zone-ZoneLockdown-list-ZoneLockdown-rules
-func (api *API) ListZoneLockdowns(ctx context.Context, rc *ResourceContainer, params LockdownListParams) ([]ZoneLockdown, *ResultInfo, error) {
-	autoPaginate := true
-	if params.PerPage >= 1 || params.Page >= 1 {
-		autoPaginate = false
+func (api *API) ListZoneLockdowns(ctx context.Context, zoneID string, page int) (*ZoneLockdownListResponse, error) {
+	v := url.Values{}
+	if page <= 0 {
+		page = 1
 	}
-	if params.PerPage < 1 {
-		params.PerPage = 50
-	}
-	if params.Page < 1 {
-		params.Page = 1
-	}
-
-	var zoneLockdowns []ZoneLockdown
-	var zResponse ZoneLockdownListResponse
-	for {
-		uri := buildURI(fmt.Sprintf("/zones/%s/firewall/lockdowns", rc.Identifier), params)
 
-		res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-		if err != nil {
-			return []ZoneLockdown{}, &ResultInfo{}, err
-		}
+	v.Set("page", strconv.Itoa(page))
+	v.Set("per_page", strconv.Itoa(100))
 
-		err = json.Unmarshal(res, &zResponse)
-		if err != nil {
-			return []ZoneLockdown{}, &ResultInfo{}, fmt.Errorf("failed to unmarshal filters JSON data: %w", err)
-		}
-
-		zoneLockdowns = append(zoneLockdowns, zResponse.Result...)
-		params.ResultInfo = zResponse.ResultInfo.Next()
+	uri := fmt.Sprintf("/zones/%s/firewall/lockdowns?%s", zoneID, v.Encode())
+	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
+	}
 
-		if params.ResultInfo.Done() || !autoPaginate {
-			break
-		}
+	response := &ZoneLockdownListResponse{}
+	err = json.Unmarshal(res, &response)
+	if err != nil {
+		return nil, fmt.Errorf("%s: %w", errUnmarshalError, err)
 	}
 
-	return zoneLockdowns, &zResponse.ResultInfo, nil
+	return response, nil
 }
diff --git a/tunnel_routes.go b/tunnel_routes.go
index fbd48d8d3..966c5a71d 100644
--- a/tunnel_routes.go
+++ b/tunnel_routes.go
@@ -59,7 +59,7 @@ type TunnelRoutesForIPParams struct {
 }
 
 type TunnelRoutesDeleteParams struct {
-	Network          string `url:"-"`
+	Network          string `json:"-"`
 	VirtualNetworkID string `url:"virtual_network_id,omitempty"`
 }
 
@@ -170,9 +170,7 @@ func (api *API) DeleteTunnelRoute(ctx context.Context, rc *ResourceContainer, pa
 		return ErrMissingNetwork
 	}
 
-	// Cannot fully utilize buildURI here because it tries to escape "%" sign
-	// from the already escaped "/" sign from Network field.
-	uri := fmt.Sprintf("/%s/%s/teamnet/routes/network/%s%s", AccountRouteRoot, rc.Identifier, url.PathEscape(params.Network), buildURI("", params))
+	uri := fmt.Sprintf("/%s/%s/teamnet/routes/network/%s", AccountRouteRoot, rc.Identifier, url.PathEscape(params.Network))
 
 	responseBody, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
diff --git a/workers.go b/workers.go
index 59db346e6..a2988f731 100644
--- a/workers.go
+++ b/workers.go
@@ -26,10 +26,6 @@ type WorkerRequestParams struct {
 type WorkerScriptParams struct {
 	Script string
 
-	// Module changes the Content-Type header to specify the script is an
-	// ES Module syntax script.
-	Module bool
-
 	// Bindings should be a map where the keys are the binding name, and the
 	// values are the binding content
 	Bindings map[string]WorkerBinding
@@ -596,16 +592,11 @@ func (api *API) ListWorkerScripts(ctx context.Context) (WorkerListResponse, erro
 // UploadWorker push raw script content for your worker.
 //
 // API reference: https://api.cloudflare.com/#worker-script-upload-worker
-func (api *API) UploadWorker(ctx context.Context, requestParams *WorkerRequestParams, params *WorkerScriptParams) (WorkerScriptResponse, error) {
-	if params.Module {
-		return api.UploadWorkerWithBindings(ctx, requestParams, params)
-	}
-
-	contentType := "application/javascript"
+func (api *API) UploadWorker(ctx context.Context, requestParams *WorkerRequestParams, data string) (WorkerScriptResponse, error) {
 	if requestParams.ScriptName != "" {
-		return api.uploadWorkerWithName(ctx, requestParams.ScriptName, contentType, []byte(params.Script))
+		return api.uploadWorkerWithName(ctx, requestParams.ScriptName, "application/javascript", []byte(data))
 	}
-	return api.uploadWorkerForZone(ctx, requestParams.ZoneID, contentType, []byte(params.Script))
+	return api.uploadWorkerForZone(ctx, requestParams.ZoneID, "application/javascript", []byte(data))
 }
 
 // UploadWorkerWithBindings push raw script content and bindings for your worker
@@ -664,23 +655,15 @@ func formatMultipartBody(params *WorkerScriptParams) (string, []byte, error) {
 	defer mpw.Close()
 
 	// Write metadata part
-	var scriptPartName string
+	scriptPartName := "script"
 	meta := struct {
-		BodyPart   string              `json:"body_part,omitempty"`
-		MainModule string              `json:"main_module,omitempty"`
-		Bindings   []workerBindingMeta `json:"bindings"`
+		BodyPart string              `json:"body_part"`
+		Bindings []workerBindingMeta `json:"bindings"`
 	}{
+		BodyPart: scriptPartName,
 		Bindings: make([]workerBindingMeta, 0, len(params.Bindings)),
 	}
 
-	if params.Module {
-		scriptPartName = "worker.mjs"
-		meta.MainModule = scriptPartName
-	} else {
-		scriptPartName = "script"
-		meta.BodyPart = scriptPartName
-	}
-
 	bodyWriters := make([]workerBindingBodyWriter, 0, len(params.Bindings))
 	for name, b := range params.Bindings {
 		bindingMeta, bodyWriter, err := b.serialize(name)
@@ -710,16 +693,8 @@ func formatMultipartBody(params *WorkerScriptParams) (string, []byte, error) {
 
 	// Write script part
 	hdr = textproto.MIMEHeader{}
-
-	contentType := "application/javascript"
-	if params.Module {
-		contentType = "application/javascript+module"
-		hdr.Set("content-disposition", fmt.Sprintf(`form-data; name="%s"; filename="%[1]s"`, scriptPartName))
-	} else {
-		hdr.Set("content-disposition", fmt.Sprintf(`form-data; name="%s"`, scriptPartName))
-	}
-	hdr.Set("content-type", contentType)
-
+	hdr.Set("content-disposition", fmt.Sprintf(`form-data; name="%s"`, scriptPartName))
+	hdr.Set("content-type", "application/javascript")
 	pw, err = mpw.CreatePart(hdr)
 	if err != nil {
 		return "", nil, err
@@ -874,3 +849,43 @@ func getRouteEndpoint(route WorkerRoute) (string, error) {
 
 	return "routes", nil
 }
+
+type WorkerDomainParams struct {
+	ZoneID      string `json:"zone_id"`
+	Hostname    string `json:"hostname"`
+	Service     string `json:"service"`
+	Environment string `json:"environment,omitempty"`
+}
+
+type WorkerDomainResult struct {
+	ID          string `json:"id"`
+	ZoneID      string `json:"zone_id"`
+	ZoneName    string `json:"zone_name"`
+	Hostname    string `json:"hostname"`
+	Service     string `json:"service"`
+	Environment string `json:"environment"`
+}
+
+type WorkerDomainResponse struct {
+	Response
+	WorkerDomainResult `json:"result"`
+}
+
+// AttachWorkerToDomain attaches a worker to a zone and hostname
+//
+// API reference: https://api.cloudflare.com/#worker-domain-attach-to-domain
+func (api *API) AttachWorkerToDomain(ctx context.Context, rc *ResourceContainer, params *WorkerDomainParams) (WorkerDomainResponse, error) {
+	uri := fmt.Sprintf("/accounts/%s/workers/domains", rc.Identifier)
+	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params)
+	if err != nil {
+		return WorkerDomainResponse{}, err
+	}
+
+	var r WorkerDomainResponse
+	err = json.Unmarshal(res, &r)
+	if err != nil {
+		return WorkerDomainResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
+	}
+
+	return r, nil
+}
diff --git a/workers_account_settings.go b/workers_account_settings.go
index d8e58516a..942db6dd0 100644
--- a/workers_account_settings.go
+++ b/workers_account_settings.go
@@ -45,7 +45,7 @@ func (api *API) CreateWorkersAccountSettings(ctx context.Context, rc *ResourceCo
 
 	var workersAccountSettingsResponse CreateWorkersAccountSettingsResponse
 	if err := json.Unmarshal(res, &workersAccountSettingsResponse); err != nil {
-		return WorkersAccountSettings{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
+		return WorkersAccountSettings{}, err
 	}
 
 	return workersAccountSettingsResponse.Result, nil
@@ -67,7 +67,7 @@ func (api *API) WorkersAccountSettings(ctx context.Context, rc *ResourceContaine
 
 	var workersAccountSettingsResponse CreateWorkersAccountSettingsResponse
 	if err := json.Unmarshal(res, &workersAccountSettingsResponse); err != nil {
-		return WorkersAccountSettings{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
+		return WorkersAccountSettings{}, err
 	}
 
 	return workersAccountSettingsResponse.Result, nil
diff --git a/workers_subdomain.go b/workers_subdomain.go
deleted file mode 100644
index f67e7ad02..000000000
--- a/workers_subdomain.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package cloudflare
-
-import (
-	"context"
-	"encoding/json"
-	"fmt"
-	"net/http"
-)
-
-type WorkersSubdomain struct {
-	Name string `json:"name,omitempty"`
-}
-
-type WorkersSubdomainResponse struct {
-	Response
-	Result WorkersSubdomain
-}
-
-// WorkersCreateSubdomain Creates a Workers subdomain for an account.
-//
-// API reference: https://api.cloudflare.com/#worker-subdomain-create-subdomain
-func (api *API) WorkersCreateSubdomain(ctx context.Context, rc *ResourceContainer, params WorkersSubdomain) (WorkersSubdomain, error) {
-	if rc.Identifier == "" {
-		return WorkersSubdomain{}, ErrMissingAccountID
-	}
-
-	uri := fmt.Sprintf("/accounts/%s/workers/subdomain", rc.Identifier)
-	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params)
-	if err != nil {
-		return WorkersSubdomain{}, err
-	}
-	var r WorkersSubdomainResponse
-	if err := json.Unmarshal(res, &r); err != nil {
-		return WorkersSubdomain{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-	return r.Result, nil
-}
-
-// WorkersGetSubdomain Creates a Workers subdomain for an account.
-//
-// API reference: https://api.cloudflare.com/#worker-subdomain-get-subdomain
-func (api *API) WorkersGetSubdomain(ctx context.Context, rc *ResourceContainer) (WorkersSubdomain, error) {
-	if rc.Identifier == "" {
-		return WorkersSubdomain{}, ErrMissingAccountID
-	}
-
-	uri := fmt.Sprintf("/accounts/%s/workers/subdomain", rc.Identifier)
-	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-	if err != nil {
-		return WorkersSubdomain{}, err
-	}
-	var r WorkersSubdomainResponse
-	if err := json.Unmarshal(res, &r); err != nil {
-		return WorkersSubdomain{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-	return r.Result, nil
-}
diff --git a/workers_tail.go b/workers_tail.go
index 478112b4a..672f82191 100644
--- a/workers_tail.go
+++ b/workers_tail.go
@@ -54,7 +54,7 @@ func (api *API) StartWorkersTail(ctx context.Context, rc *ResourceContainer, scr
 
 	var workerstailResponse StartWorkersTailResponse
 	if err := json.Unmarshal(res, &workerstailResponse); err != nil {
-		return WorkersTail{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
+		return WorkersTail{}, err
 	}
 
 	return workerstailResponse.Result, nil
@@ -80,7 +80,7 @@ func (api *API) ListWorkersTail(ctx context.Context, rc *ResourceContainer, para
 
 	var workerstailResponse ListWorkersTailResponse
 	if err := json.Unmarshal(res, &workerstailResponse); err != nil {
-		return WorkersTail{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
+		return WorkersTail{}, err
 	}
 
 	return workerstailResponse.Result, nil


Test patch:
diff --git a/access_audit_log_test.go b/access_audit_log_test.go
index b71c3f99b..f851aefcd 100644
--- a/access_audit_log_test.go
+++ b/access_audit_log_test.go
@@ -24,7 +24,7 @@ func TestAccessAuditLogs(t *testing.T) {
   "result": [
     {
       "user_email": "michelle@example.com",
-      "ip_address": "198.51.100.1",
+      "ip_address": "198.41.129.166",
       "app_uid": "df7e2w5f-02b7-4d9d-af26-8d1988fca630",
       "app_domain": "test.example.com/admin",
       "action": "login",
@@ -43,7 +43,7 @@ func TestAccessAuditLogs(t *testing.T) {
 
 	want := []AccessAuditLogRecord{{
 		UserEmail:  "michelle@example.com",
-		IPAddress:  "198.51.100.1",
+		IPAddress:  "198.41.129.166",
 		AppUID:     "df7e2w5f-02b7-4d9d-af26-8d1988fca630",
 		AppDomain:  "test.example.com/admin",
 		Action:     "login",
diff --git a/api_token_test.go b/api_token_test.go
index a48759832..524b83e1d 100644
--- a/api_token_test.go
+++ b/api_token_test.go
@@ -350,11 +350,11 @@ func TestUpdateAPIToken(t *testing.T) {
     "condition": {
       "request.ip": {
         "in": [
-          "198.51.100.0/24",
+          "199.27.128.0/21",
           "2400:cb00::/32"
         ],
         "not_in": [
-          "198.51.100.0/24",
+          "199.27.128.0/21",
           "2400:cb00::/32"
         ]
       }
@@ -395,8 +395,8 @@ func TestUpdateAPIToken(t *testing.T) {
 		},
 		Condition: &APITokenCondition{
 			RequestIP: &APITokenRequestIPCondition{
-				In:    []string{"198.51.100.0/24", "2400:cb00::/32"},
-				NotIn: []string{"198.51.100.0/24", "2400:cb00::/32"},
+				In:    []string{"199.27.128.0/21", "2400:cb00::/32"},
+				NotIn: []string{"199.27.128.0/21", "2400:cb00::/32"},
 			},
 		},
 	}
diff --git a/cloudflare_test.go b/cloudflare_test.go
index ed5f2662e..89aaa90b3 100644
--- a/cloudflare_test.go
+++ b/cloudflare_test.go
@@ -153,7 +153,7 @@ func TestClient_RetryCanSucceedAfterErrors(t *testing.T) {
             "success": true,
             "errors": [],
             "messages": [],
-            "result":
+            "result": 
                 {
                     "id": "17b5962d775c646f3f9725cbc7a53df4",
                     "created_on": "2014-01-01T05:20:00.12345Z",
@@ -165,7 +165,7 @@ func TestClient_RetryCanSucceedAfterErrors(t *testing.T) {
                     "origins": [
                       {
                         "name": "app-server-1",
-                        "address": "198.51.100.1",
+                        "address": "0.0.0.0",
                         "enabled": true
                       }
                     ],
diff --git a/dns_example_test.go b/dns_example_test.go
index 8f0a5f33c..8e72450c8 100644
--- a/dns_example_test.go
+++ b/dns_example_test.go
@@ -41,8 +41,8 @@ func ExampleAPI_DNSRecords_filterByContent() {
 		log.Fatal(err)
 	}
 
-	// Fetch only records whose content is 198.51.100.1
-	localhost := cloudflare.DNSRecord{Content: "198.51.100.1"}
+	// Fetch only records whose content is 127.0.0.1
+	localhost := cloudflare.DNSRecord{Content: "127.0.0.1"}
 	recs, err := api.DNSRecords(context.Background(), zoneID, localhost)
 	if err != nil {
 		log.Fatal(err)
diff --git a/email_routing_destination_test.go b/email_routing_destination_test.go
deleted file mode 100644
index b4451d366..000000000
--- a/email_routing_destination_test.go
+++ /dev/null
@@ -1,171 +0,0 @@
-package cloudflare
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/assert"
-)
-
-const testEmailID = "ea95132c15732412d22c1476fa83f27a"
-
-func createTestDestinationAddress() EmailRoutingDestinationAddress {
-	verified, _ := time.Parse(time.RFC3339, "2014-01-02T02:20:00Z")
-	created, _ := time.Parse(time.RFC3339, "2014-01-02T02:20:00Z")
-	modified, _ := time.Parse(time.RFC3339, "2014-01-02T02:20:00Z")
-	return EmailRoutingDestinationAddress{
-		Tag:      testEmailID,
-		Email:    "user@example.com",
-		Verified: &verified,
-		Created:  &created,
-		Modified: &modified,
-	}
-}
-
-func TestEmailRouting_ListDestinationAddress(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/accounts/"+testAccountID+"/email/routing/addresses", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": [
-    {
-      "tag": "ea95132c15732412d22c1476fa83f27a",
-      "email": "user@example.com",
-      "verified": "2014-01-02T02:20:00Z",
-      "created": "2014-01-02T02:20:00Z",
-      "modified": "2014-01-02T02:20:00Z"
-    }
-  ],
-  "result_info": {
-    "page": 1,
-    "per_page": 20,
-    "count": 1,
-    "total_count": 1
-  }
-}`)
-	})
-
-	_, _, err := client.ListEmailRoutingDestinationAddresses(context.Background(), AccountIdentifier(""), ListEmailRoutingAddressParameters{})
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingAccountID, err)
-	}
-
-	want := createTestDestinationAddress()
-
-	res, resInfo, err := client.ListEmailRoutingDestinationAddresses(context.Background(), AccountIdentifier(testAccountID), ListEmailRoutingAddressParameters{})
-	if assert.NoError(t, err) {
-		assert.Equal(t, resInfo.Page, 1)
-		assert.Equal(t, want, res[0])
-	}
-}
-
-func TestEmailRouting_CreateDestinationAddress(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/accounts/"+testAccountID+"/email/routing/addresses", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": {
-    "tag": "ea95132c15732412d22c1476fa83f27a",
-    "email": "user@example.com",
-    "verified": "2014-01-02T02:20:00Z",
-    "created": "2014-01-02T02:20:00Z",
-    "modified": "2014-01-02T02:20:00Z"
-  }
-}`)
-	})
-
-	_, err := client.CreateEmailRoutingDestinationAddress(context.Background(), AccountIdentifier(""), CreateEmailRoutingAddressParameters{})
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingAccountID, err)
-	}
-
-	want := createTestDestinationAddress()
-
-	res, err := client.CreateEmailRoutingDestinationAddress(context.Background(), AccountIdentifier(testAccountID), CreateEmailRoutingAddressParameters{Email: "user@example.com"})
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, res)
-	}
-}
-
-func TestEmailRouting_GetDestinationAddress(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/accounts/"+testAccountID+"/email/routing/addresses/"+testEmailID, func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": {
-    "tag": "ea95132c15732412d22c1476fa83f27a",
-    "email": "user@example.com",
-    "verified": "2014-01-02T02:20:00Z",
-    "created": "2014-01-02T02:20:00Z",
-    "modified": "2014-01-02T02:20:00Z"
-  }
-}`)
-	})
-
-	_, err := client.GetEmailRoutingDestinationAddress(context.Background(), AccountIdentifier(""), "")
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingAccountID, err)
-	}
-
-	want := createTestDestinationAddress()
-
-	res, err := client.GetEmailRoutingDestinationAddress(context.Background(), AccountIdentifier(testAccountID), testEmailID)
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, res)
-	}
-}
-
-func TestEmailRouting_DeleteDestinationAddress(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/accounts/"+testAccountID+"/email/routing/addresses/"+testEmailID, func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": {
-    "tag": "ea95132c15732412d22c1476fa83f27a",
-    "email": "user@example.com",
-    "verified": "2014-01-02T02:20:00Z",
-    "created": "2014-01-02T02:20:00Z",
-    "modified": "2014-01-02T02:20:00Z"
-  }
-}`)
-	})
-
-	_, err := client.DeleteEmailRoutingDestinationAddress(context.Background(), AccountIdentifier(""), "")
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingAccountID, err)
-	}
-
-	want := createTestDestinationAddress()
-
-	res, err := client.DeleteEmailRoutingDestinationAddress(context.Background(), AccountIdentifier(testAccountID), testEmailID)
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, res)
-	}
-}
diff --git a/email_routing_rules_test.go b/email_routing_rules_test.go
deleted file mode 100644
index 502f88ef2..000000000
--- a/email_routing_rules_test.go
+++ /dev/null
@@ -1,383 +0,0 @@
-package cloudflare
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-var testEmailRoutingRule = EmailRoutingRule{
-	Tag:      "a7e6fb77503c41d8a7f3113c6918f10c",
-	Name:     "Rule send to user@example.net",
-	Priority: 0,
-	Enabled:  BoolPtr(true),
-	Matchers: []EmailRoutingRuleMatcher{
-		{
-			Type:  "literal",
-			Field: "to",
-			Value: "test@example.com",
-		},
-	},
-	Actions: []EmailRoutingRuleAction{
-		{
-			Type:  "forward",
-			Value: []string{"destinationaddress@example.net"},
-		},
-	},
-}
-
-func TestEmailRouting_ListRoutingRules(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/zones/"+testZoneID+"/email/routing/rules", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": [
-    {
-      "tag": "a7e6fb77503c41d8a7f3113c6918f10c",
-      "name": "Rule send to user@example.net",
-      "priority": 0,
-      "enabled": true,
-      "matchers": [
-        {
-          "type": "literal",
-          "field": "to",
-          "value": "test@example.com"
-        }
-      ],
-      "actions": [
-        {
-          "type": "forward",
-          "value": [
-            "destinationaddress@example.net"
-          ]
-        }
-      ]
-    }
-  ],
-  "result_info": {
-    "page": 1,
-    "per_page": 20,
-    "count": 1,
-    "total_count": 1
-  }
-}`)
-	})
-
-	_, _, err := client.ListEmailRoutingRules(context.Background(), AccountIdentifier(""), ListEmailRoutingRulesParameters{})
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingZoneID, err)
-	}
-
-	res, resInfo, err := client.ListEmailRoutingRules(context.Background(), AccountIdentifier(testZoneID), ListEmailRoutingRulesParameters{Enabled: BoolPtr(true)})
-	if assert.NoError(t, err) {
-		assert.Equal(t, resInfo.Page, 1)
-		assert.Equal(t, testEmailRoutingRule, res[0])
-	}
-}
-
-func TestEmailRouting_CreateRoutingRule(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/zones/"+testZoneID+"/email/routing/rules", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": {
-    "tag": "a7e6fb77503c41d8a7f3113c6918f10c",
-    "name": "Rule send to user@example.net",
-    "priority": 0,
-    "enabled": true,
-    "matchers": [
-      {
-        "type": "literal",
-        "field": "to",
-        "value": "test@example.com"
-      }
-    ],
-    "actions": [
-      {
-        "type": "forward",
-        "value": [
-          "destinationaddress@example.net"
-        ]
-      }
-    ]
-  }
-}`)
-	})
-
-	_, err := client.CreateEmailRoutingRule(context.Background(), AccountIdentifier(""), CreateEmailRoutingRuleParameters{})
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingZoneID, err)
-	}
-
-	res, err := client.CreateEmailRoutingRule(context.Background(), AccountIdentifier(testZoneID), CreateEmailRoutingRuleParameters{Enabled: BoolPtr(true)})
-	if assert.NoError(t, err) {
-		assert.Equal(t, testEmailRoutingRule, res)
-	}
-}
-
-func TestEmailRouting_GetRoutingRule(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/zones/"+testZoneID+"/email/routing/rules/a7e6fb77503c41d8a7f3113c6918f10c", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": {
-    "tag": "a7e6fb77503c41d8a7f3113c6918f10c",
-    "name": "Rule send to user@example.net",
-    "priority": 0,
-    "enabled": true,
-    "matchers": [
-      {
-        "type": "literal",
-        "field": "to",
-        "value": "test@example.com"
-      }
-    ],
-    "actions": [
-      {
-        "type": "forward",
-        "value": [
-          "destinationaddress@example.net"
-        ]
-      }
-    ]
-  }
-}`)
-	})
-
-	_, err := client.GetEmailRoutingRule(context.Background(), ZoneIdentifier(""), "")
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingZoneID, err)
-	}
-
-	res, err := client.GetEmailRoutingRule(context.Background(), AccountIdentifier(testZoneID), "a7e6fb77503c41d8a7f3113c6918f10c")
-	if assert.NoError(t, err) {
-		assert.Equal(t, testEmailRoutingRule, res)
-	}
-}
-
-func TestEmailRouting_UpdateRoutingRule(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/zones/"+testZoneID+"/email/routing/rules/a7e6fb77503c41d8a7f3113c6918f10c", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": {
-    "tag": "a7e6fb77503c41d8a7f3113c6918f10c",
-    "name": "Rule send to user@example.net",
-    "priority": 0,
-    "enabled": true,
-    "matchers": [
-      {
-        "type": "literal",
-        "field": "to",
-        "value": "test@example.com"
-      }
-    ],
-    "actions": [
-      {
-        "type": "forward",
-        "value": [
-          "destinationaddress@example.net"
-        ]
-      }
-    ]
-  }
-}`)
-	})
-
-	_, err := client.UpdateEmailRoutingRule(context.Background(), ZoneIdentifier(""), UpdateEmailRoutingRuleParameters{})
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingZoneID, err)
-	}
-	_, err = client.UpdateEmailRoutingRule(context.Background(), ZoneIdentifier(testZoneID), UpdateEmailRoutingRuleParameters{})
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingRuleID, err)
-	}
-
-	res, err := client.UpdateEmailRoutingRule(context.Background(), AccountIdentifier(testZoneID), UpdateEmailRoutingRuleParameters{RuleID: "a7e6fb77503c41d8a7f3113c6918f10c"})
-	if assert.NoError(t, err) {
-		assert.Equal(t, testEmailRoutingRule, res)
-	}
-}
-
-func TestEmailRouting_DeleteRoutingRule(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/zones/"+testZoneID+"/email/routing/rules/a7e6fb77503c41d8a7f3113c6918f10c", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": {
-    "tag": "a7e6fb77503c41d8a7f3113c6918f10c",
-    "name": "Rule send to user@example.net",
-    "priority": 0,
-    "enabled": true,
-    "matchers": [
-      {
-        "type": "literal",
-        "field": "to",
-        "value": "test@example.com"
-      }
-    ],
-    "actions": [
-      {
-        "type": "forward",
-        "value": [
-          "destinationaddress@example.net"
-        ]
-      }
-    ]
-  }
-}`)
-	})
-
-	_, err := client.DeleteEmailRoutingRule(context.Background(), ZoneIdentifier(""), "")
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingZoneID, err)
-	}
-
-	res, err := client.DeleteEmailRoutingRule(context.Background(), AccountIdentifier(testZoneID), "a7e6fb77503c41d8a7f3113c6918f10c")
-	if assert.NoError(t, err) {
-		assert.Equal(t, testEmailRoutingRule, res)
-	}
-}
-
-func TestEmailRouting_GetAllRule(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/zones/"+testZoneID+"/email/routing/rules/catch_all", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'PUT', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "tag": "a7e6fb77503c41d8a7f3113c6918f10c",
-  "name": "Rule send to user@example.net",
-  "enabled": true,
-  "matchers": [
-    {
-      "type": "all"
-    }
-  ],
-  "actions": [
-    {
-      "type": "forward",
-      "value": [
-        "destinationaddress@example.net"
-      ]
-    }
-  ]
-}`)
-	})
-
-	_, err := client.GetEmailRoutingCatchAllRule(context.Background(), ZoneIdentifier(""))
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingZoneID, err)
-	}
-
-	want := EmailRoutingCatchAllRule{
-		Tag:     "a7e6fb77503c41d8a7f3113c6918f10c",
-		Name:    "Rule send to user@example.net",
-		Enabled: BoolPtr(true),
-		Matchers: []EmailRoutingRuleMatcher{
-			{
-				Type: "all",
-			},
-		},
-		Actions: []EmailRoutingRuleAction{
-			{
-				Type:  "forward",
-				Value: []string{"destinationaddress@example.net"},
-			},
-		},
-	}
-
-	res, err := client.GetEmailRoutingCatchAllRule(context.Background(), AccountIdentifier(testZoneID))
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, res)
-	}
-}
-
-func TestEmailRouting_UpdateAllRule(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/zones/"+testZoneID+"/email/routing/rules/catch_all", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "tag": "a7e6fb77503c41d8a7f3113c6918f10c",
-  "name": "Rule send to user@example.net",
-  "enabled": true,
-  "matchers": [
-    {
-      "type": "all"
-    }
-  ],
-  "actions": [
-    {
-      "type": "forward",
-      "value": [
-        "destinationaddress@example.net"
-      ]
-    }
-  ]
-}`)
-	})
-
-	_, err := client.UpdateEmailRoutingCatchAllRule(context.Background(), ZoneIdentifier(""), EmailRoutingCatchAllRule{})
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingZoneID, err)
-	}
-
-	want := EmailRoutingCatchAllRule{
-		Tag:     "a7e6fb77503c41d8a7f3113c6918f10c",
-		Name:    "Rule send to user@example.net",
-		Enabled: BoolPtr(true),
-		Matchers: []EmailRoutingRuleMatcher{
-			{
-				Type: "all",
-			},
-		},
-		Actions: []EmailRoutingRuleAction{
-			{
-				Type:  "forward",
-				Value: []string{"destinationaddress@example.net"},
-			},
-		},
-	}
-
-	res, err := client.UpdateEmailRoutingCatchAllRule(context.Background(), AccountIdentifier(testZoneID), EmailRoutingCatchAllRule{})
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, res)
-	}
-}
diff --git a/email_routing_settings_test.go b/email_routing_settings_test.go
deleted file mode 100644
index 6e937a69c..000000000
--- a/email_routing_settings_test.go
+++ /dev/null
@@ -1,178 +0,0 @@
-package cloudflare
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func createTestEmailRoutingSettings() EmailRoutingSettings {
-	created, _ := time.Parse(time.RFC3339, "2014-01-02T02:20:00Z")
-	modified, _ := time.Parse(time.RFC3339, "2014-01-02T02:20:00Z")
-	return EmailRoutingSettings{
-		Tag:        "75610dab9e69410a82cf7e400a09ecec",
-		Name:       "example.net",
-		Enabled:    true,
-		Created:    &created,
-		Modified:   &modified,
-		SkipWizard: BoolPtr(true),
-		Status:     "read",
-	}
-}
-
-func TestEmailRouting_GetSettings(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/zones/"+testZoneID+"/email/routing", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": {
-    "tag": "75610dab9e69410a82cf7e400a09ecec",
-    "name": "example.net",
-    "enabled": true,
-    "created": "2014-01-02T02:20:00Z",
-    "modified": "2014-01-02T02:20:00Z",
-    "skip_wizard": true,
-    "status": "read"
-  }
-}`)
-	})
-
-	_, err := client.GetEmailRoutingSettings(context.Background(), AccountIdentifier(""))
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingZoneID, err)
-	}
-
-	want := createTestEmailRoutingSettings()
-
-	res, err := client.GetEmailRoutingSettings(context.Background(), AccountIdentifier(testZoneID))
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, res)
-	}
-}
-
-func TestEmailRouting_Enable(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/zones/"+testZoneID+"/email/routing/enabled", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": {
-    "tag": "75610dab9e69410a82cf7e400a09ecec",
-    "name": "example.net",
-    "enabled": true,
-    "created": "2014-01-02T02:20:00Z",
-    "modified": "2014-01-02T02:20:00Z",
-    "skip_wizard": true,
-    "status": "read"
-  }
-}`)
-	})
-
-	_, err := client.EnableEmailRouting(context.Background(), AccountIdentifier(""))
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingZoneID, err)
-	}
-
-	want := createTestEmailRoutingSettings()
-
-	res, err := client.EnableEmailRouting(context.Background(), AccountIdentifier(testZoneID))
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, res)
-	}
-}
-
-func TestEmailRouting_Disabled(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/zones/"+testZoneID+"/email/routing/disable", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": {
-    "tag": "75610dab9e69410a82cf7e400a09ecec",
-    "name": "example.net",
-    "enabled": true,
-    "created": "2014-01-02T02:20:00Z",
-    "modified": "2014-01-02T02:20:00Z",
-    "skip_wizard": true,
-    "status": "read"
-  }
-}`)
-	})
-
-	_, err := client.DisableEmailRouting(context.Background(), AccountIdentifier(""))
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingZoneID, err)
-	}
-
-	want := createTestEmailRoutingSettings()
-
-	res, err := client.DisableEmailRouting(context.Background(), AccountIdentifier(testZoneID))
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, res)
-	}
-}
-
-func TestEmailRouting_DNSSettings(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/zones/"+testZoneID+"/email/routing/dns", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'DELETE', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": [
-    {
-      "type": "A",
-      "name": "example.com",
-      "content": "192.0.2.1",
-      "ttl": 3600,
-      "priority": 10
-    }
-  ]
-}`)
-	})
-
-	_, err := client.GetEmailRoutingDNSSettings(context.Background(), AccountIdentifier(""))
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingZoneID, err)
-	}
-
-	want := []DNSRecord{
-		{
-			Type:     "A",
-			Name:     "example.com",
-			Content:  "192.0.2.1",
-			TTL:      3600,
-			Priority: Uint16Ptr(10),
-		},
-	}
-
-	res, err := client.GetEmailRoutingDNSSettings(context.Background(), AccountIdentifier(testZoneID))
-	if assert.NoError(t, err) {
-		assert.Len(t, res, 1)
-		assert.Equal(t, want, res)
-	}
-}
diff --git a/filter_test.go b/filter_test.go
index b36c7cc8e..3dda4adda 100644
--- a/filter_test.go
+++ b/filter_test.go
@@ -21,7 +21,7 @@ func TestFilter(t *testing.T) {
 				"id": "b7ff25282d394be7b945e23c7106ce8a",
 				"paused": false,
 				"description": "Login from office",
-				"expression": "ip.src eq 198.51.100.1"
+				"expression": "ip.src eq 127.0.0.1"
 			},
 			"success": true,
 			"errors": null,
@@ -35,7 +35,7 @@ func TestFilter(t *testing.T) {
 		ID:          "b7ff25282d394be7b945e23c7106ce8a",
 		Paused:      false,
 		Description: "Login from office",
-		Expression:  "ip.src eq 198.51.100.1",
+		Expression:  "ip.src eq 127.0.0.1",
 	}
 
 	actual, err := client.Filter(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), "b7ff25282d394be7b945e23c7106ce8a")
@@ -146,7 +146,7 @@ func TestCreateSingleFilter(t *testing.T) {
 					"id": "b7ff25282d394be7b945e23c7106ce8a",
 					"paused": false,
 					"description": "Login from office",
-					"expression": "ip.src eq 198.51.100.1"
+					"expression": "ip.src eq 127.0.0.1"
 				}
 			],
 			"success": true,
@@ -157,25 +157,16 @@ func TestCreateSingleFilter(t *testing.T) {
 	}
 
 	mux.HandleFunc("/zones/d56084adb405e0b7e32c52321bf07be6/filters", handler)
-	params := []FilterCreateParams{
-		{
-			ID:          "b7ff25282d394be7b945e23c7106ce8a",
-			Paused:      false,
-			Description: "Login from office",
-			Expression:  "ip.src eq 198.51.100.1",
-		},
-	}
-
 	want := []Filter{
 		{
 			ID:          "b7ff25282d394be7b945e23c7106ce8a",
 			Paused:      false,
 			Description: "Login from office",
-			Expression:  "ip.src eq 198.51.100.1",
+			Expression:  "ip.src eq 127.0.0.1",
 		},
 	}
 
-	actual, err := client.CreateFilters(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), params)
+	actual, err := client.CreateFilters(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), want)
 
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
@@ -195,7 +186,7 @@ func TestCreateMultipleFilters(t *testing.T) {
 					"id": "b7ff25282d394be7b945e23c7106ce8a",
 					"paused": false,
 					"description": "Login from office",
-					"expression": "ip.src eq 198.51.100.1"
+					"expression": "ip.src eq 127.0.0.1"
 				},
 				{
 					"id": "b7ff25282d394be7b945e23c7106ce8a",
@@ -212,27 +203,12 @@ func TestCreateMultipleFilters(t *testing.T) {
 	}
 
 	mux.HandleFunc("/zones/d56084adb405e0b7e32c52321bf07be6/filters", handler)
-	params := []FilterCreateParams{
-		{
-			ID:          "b7ff25282d394be7b945e23c7106ce8a",
-			Paused:      false,
-			Description: "Login from office",
-			Expression:  "ip.src eq 198.51.100.1",
-		},
-		{
-			ID:          "b7ff25282d394be7b945e23c7106ce8a",
-			Paused:      false,
-			Description: "Login from second office",
-			Expression:  "ip.src eq 10.0.0.1",
-		},
-	}
-
 	want := []Filter{
 		{
 			ID:          "b7ff25282d394be7b945e23c7106ce8a",
 			Paused:      false,
 			Description: "Login from office",
-			Expression:  "ip.src eq 198.51.100.1",
+			Expression:  "ip.src eq 127.0.0.1",
 		},
 		{
 			ID:          "b7ff25282d394be7b945e23c7106ce8a",
@@ -242,7 +218,7 @@ func TestCreateMultipleFilters(t *testing.T) {
 		},
 	}
 
-	actual, err := client.CreateFilters(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), params)
+	actual, err := client.CreateFilters(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), want)
 
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
@@ -271,13 +247,6 @@ func TestUpdateSingleFilter(t *testing.T) {
 	}
 
 	mux.HandleFunc("/zones/d56084adb405e0b7e32c52321bf07be6/filters/60ee852f9cbb4802978d15600c7f3110", handler)
-	params := FilterUpdateParams{
-		ID:          "60ee852f9cbb4802978d15600c7f3110",
-		Paused:      false,
-		Description: "IP of example.org",
-		Expression:  "ip.src eq 93.184.216.0",
-	}
-
 	want := Filter{
 		ID:          "60ee852f9cbb4802978d15600c7f3110",
 		Paused:      false,
@@ -285,7 +254,7 @@ func TestUpdateSingleFilter(t *testing.T) {
 		Expression:  "ip.src eq 93.184.216.0",
 	}
 
-	actual, err := client.UpdateFilter(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), params)
+	actual, err := client.UpdateFilter(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), want)
 
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
@@ -311,7 +280,7 @@ func TestUpdateMultipleFilters(t *testing.T) {
 					"id": "c218c536b2bd406f958f278cf0fa8c0f",
 					"paused": false,
 					"description": "IP of example.com",
-					"expression": "ip.src ne 198.51.100.1"
+					"expression": "ip.src ne 127.0.0.1"
 				}
 			],
 			"success": true,
@@ -322,21 +291,6 @@ func TestUpdateMultipleFilters(t *testing.T) {
 	}
 
 	mux.HandleFunc("/zones/d56084adb405e0b7e32c52321bf07be6/filters", handler)
-	params := []FilterUpdateParams{
-		{
-			ID:          "60ee852f9cbb4802978d15600c7f3110",
-			Paused:      false,
-			Description: "IP of example.org",
-			Expression:  "ip.src eq 93.184.216.0",
-		},
-		{
-			ID:          "c218c536b2bd406f958f278cf0fa8c0f",
-			Paused:      false,
-			Description: "IP of example.com",
-			Expression:  "ip.src ne 198.51.100.1",
-		},
-	}
-
 	want := []Filter{
 		{
 			ID:          "60ee852f9cbb4802978d15600c7f3110",
@@ -348,11 +302,11 @@ func TestUpdateMultipleFilters(t *testing.T) {
 			ID:          "c218c536b2bd406f958f278cf0fa8c0f",
 			Paused:      false,
 			Description: "IP of example.com",
-			Expression:  "ip.src ne 198.51.100.1",
+			Expression:  "ip.src ne 127.0.0.1",
 		},
 	}
 
-	actual, err := client.UpdateFilters(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), params)
+	actual, err := client.UpdateFilters(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), want)
 
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
diff --git a/firewall_example_test.go b/firewall_example_test.go
index 571b61709..e6f08b3dc 100644
--- a/firewall_example_test.go
+++ b/firewall_example_test.go
@@ -41,9 +41,9 @@ func ExampleAPI_ListZoneAccessRules_filterByIP() {
 		log.Fatal(err)
 	}
 
-	// Fetch only access rules whose target is 198.51.100.1
+	// Fetch only access rules whose target is 127.0.0.1
 	localhost := cloudflare.AccessRule{
-		Configuration: cloudflare.AccessRuleConfiguration{Target: "198.51.100.1"},
+		Configuration: cloudflare.AccessRuleConfiguration{Target: "127.0.0.1"},
 	}
 	response, err := api.ListZoneAccessRules(context.Background(), zoneID, localhost, 1)
 	if err != nil {
diff --git a/firewall_rules_test.go b/firewall_rules_test.go
index 42db16192..76c2b1c7d 100644
--- a/firewall_rules_test.go
+++ b/firewall_rules_test.go
@@ -9,6 +9,11 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+var firewallRulePageOpts = PaginationOptions{
+	PerPage: 25,
+	Page:    1,
+}
+
 func TestFirewallRules(t *testing.T) {
 	setup()
 	defer teardown()
@@ -191,7 +196,7 @@ func TestFirewallRule(t *testing.T) {
 				"priority":null,
 				"filter":{
 					"id":"b7ff25282d394be7b945e23c7106ce8a",
-					"expression":"ip.src in {198.51.100.1} ~ \"^.*/login.php$\")",
+					"expression":"ip.src in {127.0.0.1} ~ \"^.*/login.php$\")",
 					"paused":false,
 					"description":"Login from office"
 				}
@@ -212,7 +217,7 @@ func TestFirewallRule(t *testing.T) {
 		Priority:    nil,
 		Filter: Filter{
 			ID:          "b7ff25282d394be7b945e23c7106ce8a",
-			Expression:  "ip.src in {198.51.100.1} ~ \"^.*/login.php$\")",
+			Expression:  "ip.src in {127.0.0.1} ~ \"^.*/login.php$\")",
 			Paused:      false,
 			Description: "Login from office",
 		},
@@ -242,7 +247,7 @@ func TestCreateSingleFirewallRule(t *testing.T) {
 					"priority":null,
 					"filter":{
 						"id":"b7ff25282d394be7b945e23c7106ce8a",
-						"expression":"ip.src in {198.51.100.0/24}",
+						"expression":"ip.src in {127.0.0.0/24}",
 						"paused":false,
 						"description":"Login from office"
 					}
@@ -256,22 +261,6 @@ func TestCreateSingleFirewallRule(t *testing.T) {
 	}
 
 	mux.HandleFunc("/zones/d56084adb405e0b7e32c52321bf07be6/firewall/rules", handler)
-	params := []FirewallRuleCreateParams{
-		{
-			ID:          "f2d427378e7542acb295380d352e2ebd",
-			Paused:      false,
-			Description: "do not challenge login from office",
-			Action:      "allow",
-			Priority:    nil,
-			Filter: Filter{
-				ID:          "b7ff25282d394be7b945e23c7106ce8a",
-				Expression:  "ip.src in {198.51.100.0/24}",
-				Paused:      false,
-				Description: "Login from office",
-			},
-		},
-	}
-
 	want := []FirewallRule{
 		{
 			ID:          "f2d427378e7542acb295380d352e2ebd",
@@ -281,14 +270,14 @@ func TestCreateSingleFirewallRule(t *testing.T) {
 			Priority:    nil,
 			Filter: Filter{
 				ID:          "b7ff25282d394be7b945e23c7106ce8a",
-				Expression:  "ip.src in {198.51.100.0/24}",
+				Expression:  "ip.src in {127.0.0.0/24}",
 				Paused:      false,
 				Description: "Login from office",
 			},
 		},
 	}
 
-	actual, err := client.CreateFirewallRules(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), params)
+	actual, err := client.CreateFirewallRules(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), want)
 
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
@@ -312,7 +301,7 @@ func TestCreateMultipleFirewallRules(t *testing.T) {
 					"priority":null,
 					"filter":{
 						"id":"b7ff25282d394be7b945e23c7106ce8a",
-						"expression":"ip.src in {198.51.100.0/24}",
+						"expression":"ip.src in {127.0.0.0/24}",
 						"paused":false,
 						"description":"Login from office"
 					}
@@ -339,35 +328,6 @@ func TestCreateMultipleFirewallRules(t *testing.T) {
 	}
 
 	mux.HandleFunc("/zones/d56084adb405e0b7e32c52321bf07be6/firewall/rules", handler)
-	params := []FirewallRuleCreateParams{
-		{
-			ID:          "f2d427378e7542acb295380d352e2ebd",
-			Paused:      false,
-			Description: "do not challenge login from office",
-			Action:      "allow",
-			Priority:    nil,
-			Filter: Filter{
-				ID:          "b7ff25282d394be7b945e23c7106ce8a",
-				Expression:  "ip.src in {198.51.100.0/24}",
-				Paused:      false,
-				Description: "Login from office",
-			},
-		},
-		{
-			ID:          "cbf4b7a5a2a24e59a03044d6d44ceb09",
-			Paused:      false,
-			Description: "challenge login",
-			Action:      "challenge",
-			Priority:    nil,
-			Filter: Filter{
-				ID:          "c218c536b2bd406f958f278cf0fa8c0f",
-				Expression:  "(http.request.uri.path ~ \"^.*/wp-login.php$\")",
-				Paused:      false,
-				Description: "Login",
-			},
-		},
-	}
-
 	want := []FirewallRule{
 		{
 			ID:          "f2d427378e7542acb295380d352e2ebd",
@@ -377,7 +337,7 @@ func TestCreateMultipleFirewallRules(t *testing.T) {
 			Priority:    nil,
 			Filter: Filter{
 				ID:          "b7ff25282d394be7b945e23c7106ce8a",
-				Expression:  "ip.src in {198.51.100.0/24}",
+				Expression:  "ip.src in {127.0.0.0/24}",
 				Paused:      false,
 				Description: "Login from office",
 			},
@@ -397,7 +357,7 @@ func TestCreateMultipleFirewallRules(t *testing.T) {
 		},
 	}
 
-	actual, err := client.CreateFirewallRules(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), params)
+	actual, err := client.CreateFirewallRules(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), want)
 
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
@@ -408,7 +368,7 @@ func TestUpdateFirewallRuleWithMissingID(t *testing.T) {
 	setup()
 	defer teardown()
 
-	want := FirewallRuleUpdateParams{
+	want := FirewallRule{
 		ID:          "",
 		Paused:      false,
 		Description: "challenge site",
@@ -455,20 +415,6 @@ func TestUpdateSingleFirewallRule(t *testing.T) {
 	}
 
 	mux.HandleFunc("/zones/d56084adb405e0b7e32c52321bf07be6/firewall/rules/52161eb6af4241bb9d4b32394be72fdf", handler)
-	params := FirewallRuleUpdateParams{
-		ID:          "52161eb6af4241bb9d4b32394be72fdf",
-		Paused:      false,
-		Description: "challenge site",
-		Action:      "challenge",
-		Priority:    nil,
-		Filter: Filter{
-			ID:          "f2a64520581a4209aab12187a0081364",
-			Expression:  "not http.request.uri.path matches \"^/api/.*$\"",
-			Paused:      false,
-			Description: "not /api",
-		},
-	}
-
 	want := FirewallRule{
 		ID:          "52161eb6af4241bb9d4b32394be72fdf",
 		Paused:      false,
@@ -483,7 +429,7 @@ func TestUpdateSingleFirewallRule(t *testing.T) {
 		},
 	}
 
-	actual, err := client.UpdateFirewallRule(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), params)
+	actual, err := client.UpdateFirewallRule(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), want)
 
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
@@ -507,7 +453,7 @@ func TestUpdateMultipleFirewallRules(t *testing.T) {
 					"priority":null,
 					"filter":{
 						"id":"b7ff25282d394be7b945e23c7106ce8a",
-						"expression":"ip.src in {198.51.100.0/24}",
+						"expression":"ip.src in {127.0.0.0/24}",
 						"paused":false,
 						"description":"Login from office"
 					}
@@ -534,35 +480,6 @@ func TestUpdateMultipleFirewallRules(t *testing.T) {
 	}
 
 	mux.HandleFunc("/zones/d56084adb405e0b7e32c52321bf07be6/firewall/rules", handler)
-	params := []FirewallRuleUpdateParams{
-		{
-			ID:          "f2d427378e7542acb295380d352e2ebd",
-			Paused:      false,
-			Description: "do not challenge login from office",
-			Action:      "allow",
-			Priority:    nil,
-			Filter: Filter{
-				ID:          "b7ff25282d394be7b945e23c7106ce8a",
-				Expression:  "ip.src in {198.51.100.0/24}",
-				Paused:      false,
-				Description: "Login from office",
-			},
-		},
-		{
-			ID:          "cbf4b7a5a2a24e59a03044d6d44ceb09",
-			Paused:      false,
-			Description: "challenge login",
-			Action:      "challenge",
-			Priority:    nil,
-			Filter: Filter{
-				ID:          "c218c536b2bd406f958f278cf0fa8c0f",
-				Expression:  "(http.request.uri.path ~ \"^.*/wp-login.php$\")",
-				Paused:      false,
-				Description: "Login",
-			},
-		},
-	}
-
 	want := []FirewallRule{
 		{
 			ID:          "f2d427378e7542acb295380d352e2ebd",
@@ -572,7 +489,7 @@ func TestUpdateMultipleFirewallRules(t *testing.T) {
 			Priority:    nil,
 			Filter: Filter{
 				ID:          "b7ff25282d394be7b945e23c7106ce8a",
-				Expression:  "ip.src in {198.51.100.0/24}",
+				Expression:  "ip.src in {127.0.0.0/24}",
 				Paused:      false,
 				Description: "Login from office",
 			},
@@ -592,7 +509,7 @@ func TestUpdateMultipleFirewallRules(t *testing.T) {
 		},
 	}
 
-	actual, err := client.UpdateFirewallRules(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), params)
+	actual, err := client.UpdateFirewallRules(context.Background(), ZoneIdentifier("d56084adb405e0b7e32c52321bf07be6"), want)
 
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
diff --git a/ips_test.go b/ips_test.go
index cc3b95930..c73b07e34 100644
--- a/ips_test.go
+++ b/ips_test.go
@@ -50,7 +50,7 @@ func Test_IPs(t *testing.T) {
   "errors": [],
   "messages": [],
   "result": {
-    "ipv4_cidrs": ["198.51.100.0/24"],
+    "ipv4_cidrs": ["199.27.128.0/21"],
     "ipv6_cidrs": ["ffff:ffff::/32"],
     "china_colos": ["42.81.6.0/25", "2408:871a:1801:7::/72"]
   }
@@ -62,7 +62,7 @@ func Test_IPs(t *testing.T) {
 	assert.NoError(t, err)
 
 	assert.Len(t, ipRanges.IPv4CIDRs, 1)
-	assert.Equal(t, "198.51.100.0/24", ipRanges.IPv4CIDRs[0])
+	assert.Equal(t, "199.27.128.0/21", ipRanges.IPv4CIDRs[0])
 	assert.Len(t, ipRanges.IPv6CIDRs, 1)
 	assert.Equal(t, "ffff:ffff::/32", ipRanges.IPv6CIDRs[0])
 	assert.Len(t, ipRanges.ChinaIPv4CIDRs, 1)
diff --git a/load_balancing_test.go b/load_balancing_test.go
index 1aef80a8c..6651ea3d3 100644
--- a/load_balancing_test.go
+++ b/load_balancing_test.go
@@ -40,7 +40,7 @@ func TestCreateLoadBalancerPool(t *testing.T) {
               "origins": [
                 {
                   "name": "app-server-1",
-                  "address": "198.51.100.1",
+                  "address": "0.0.0.0",
                   "enabled": true,
                   "weight": 1,
                   "header": {
@@ -83,7 +83,7 @@ func TestCreateLoadBalancerPool(t *testing.T) {
               "origins": [
                 {
                   "name": "app-server-1",
-                  "address": "198.51.100.1",
+                  "address": "0.0.0.0",
                   "enabled": true,
                   "weight": 1,
                   "header": {
@@ -131,7 +131,7 @@ func TestCreateLoadBalancerPool(t *testing.T) {
 		Origins: []LoadBalancerOrigin{
 			{
 				Name:    "app-server-1",
-				Address: "198.51.100.1",
+				Address: "0.0.0.0",
 				Enabled: true,
 				Weight:  1,
 				Header: map[string][]string{
@@ -163,7 +163,7 @@ func TestCreateLoadBalancerPool(t *testing.T) {
 		Origins: []LoadBalancerOrigin{
 			{
 				Name:    "app-server-1",
-				Address: "198.51.100.1",
+				Address: "0.0.0.0",
 				Enabled: true,
 				Weight:  1,
 				Header: map[string][]string{
@@ -209,7 +209,7 @@ func TestListLoadBalancerPools(t *testing.T) {
                     "origins": [
                       {
                         "name": "app-server-1",
-                        "address": "198.51.100.1",
+                        "address": "0.0.0.0",
                         "enabled": true,
                         "weight": 1
                       }
@@ -244,7 +244,7 @@ func TestListLoadBalancerPools(t *testing.T) {
 			Origins: []LoadBalancerOrigin{
 				{
 					Name:    "app-server-1",
-					Address: "198.51.100.1",
+					Address: "0.0.0.0",
 					Enabled: true,
 					Weight:  1,
 				},
@@ -284,7 +284,7 @@ func TestLoadBalancerPoolDetails(t *testing.T) {
               "origins": [
                 {
                   "name": "app-server-1",
-                  "address": "198.51.100.1",
+                  "address": "0.0.0.0",
                   "enabled": true,
                   "weight": 1
                 }
@@ -311,7 +311,7 @@ func TestLoadBalancerPoolDetails(t *testing.T) {
 		Origins: []LoadBalancerOrigin{
 			{
 				Name:    "app-server-1",
-				Address: "198.51.100.1",
+				Address: "0.0.0.0",
 				Enabled: true,
 				Weight:  1,
 			},
@@ -371,7 +371,7 @@ func TestModifyLoadBalancerPool(t *testing.T) {
               "origins": [
                 {
                   "name": "app-server-2",
-                  "address": "198.51.100.2",
+                  "address": "0.0.0.1",
                   "enabled": false,
                   "weight": 1,
                   "header": {
@@ -404,7 +404,7 @@ func TestModifyLoadBalancerPool(t *testing.T) {
               "origins": [
                 {
                   "name": "app-server-2",
-                  "address": "198.51.100.2",
+                  "address": "0.0.0.1",
                   "enabled": false,
                   "weight": 1,
                   "header": {
@@ -438,7 +438,7 @@ func TestModifyLoadBalancerPool(t *testing.T) {
 		Origins: []LoadBalancerOrigin{
 			{
 				Name:    "app-server-2",
-				Address: "198.51.100.2",
+				Address: "0.0.0.1",
 				Enabled: false,
 				Weight:  1,
 				Header: map[string][]string{
@@ -462,7 +462,7 @@ func TestModifyLoadBalancerPool(t *testing.T) {
 		Origins: []LoadBalancerOrigin{
 			{
 				Name:    "app-server-2",
-				Address: "198.51.100.2",
+				Address: "0.0.0.1",
 				Enabled: false,
 				Weight:  1,
 				Header: map[string][]string{
diff --git a/lockdown_example_test.go b/lockdown_example_test.go
index ffb1002f9..4f9d90844 100644
--- a/lockdown_example_test.go
+++ b/lockdown_example_test.go
@@ -21,12 +21,12 @@ func ExampleAPI_ListZoneLockdowns_all() {
 	}
 
 	// Fetch all Zone Lockdown rules for a zone, by page.
-	rules, _, err := api.ListZoneLockdowns(context.Background(), cloudflare.ZoneIdentifier(zoneID), cloudflare.LockdownListParams{})
+	rules, err := api.ListZoneLockdowns(context.Background(), zoneID, 1)
 	if err != nil {
 		log.Fatal(err)
 	}
 
-	for _, r := range rules {
+	for _, r := range rules.Result {
 		fmt.Printf("%s: %s\n", strings.Join(r.URLs, ", "), r.Configurations)
 	}
 }
@@ -42,7 +42,7 @@ func ExampleAPI_CreateZoneLockdown() {
 		log.Fatal(err)
 	}
 
-	newZoneLockdown := cloudflare.ZoneLockdownCreateParams{
+	newZoneLockdown := cloudflare.ZoneLockdown{
 		Description: "Test Zone Lockdown Rule",
 		URLs: []string{
 			"*.example.org/test",
@@ -50,13 +50,14 @@ func ExampleAPI_CreateZoneLockdown() {
 		Configurations: []cloudflare.ZoneLockdownConfig{
 			{
 				Target: "ip",
-				Value:  "198.51.100.1",
+				Value:  "127.0.0.1",
 			},
 		},
-		Paused: false,
+		Paused:   false,
+		Priority: 1,
 	}
 
-	response, err := api.CreateZoneLockdown(context.Background(), cloudflare.ZoneIdentifier(zoneID), newZoneLockdown)
+	response, err := api.CreateZoneLockdown(context.Background(), zoneID, newZoneLockdown)
 	if err != nil {
 		log.Fatal(err)
 	}
diff --git a/lockdown_test.go b/lockdown_test.go
index cd4b7c050..b5d152b86 100644
--- a/lockdown_test.go
+++ b/lockdown_test.go
@@ -16,17 +16,7 @@ func TestCreateZoneLockdown(t *testing.T) {
 	setup()
 	defer teardown()
 
-	input := ZoneLockdownCreateParams{
-		Description: "Restrict access to these endpoints to requests from a known IP address",
-		URLs:        []string{"api.mysite.com/some/endpoint*"},
-		Configurations: []ZoneLockdownConfig{{
-			Target: "ip",
-			Value:  "198.51.100.4",
-		}},
-		Paused: false,
-	}
-
-	want := ZoneLockdown{
+	input := ZoneLockdown{
 		Description: "Restrict access to these endpoints to requests from a known IP address",
 		URLs:        []string{"api.mysite.com/some/endpoint*"},
 		Configurations: []ZoneLockdownConfig{{
@@ -42,7 +32,7 @@ func TestCreateZoneLockdown(t *testing.T) {
 		var v ZoneLockdown
 		err := json.NewDecoder(r.Body).Decode(&v)
 		require.NoError(t, err)
-		assert.Equal(t, want, v)
+		assert.Equal(t, input, v)
 
 		w.Header().Set("content-type", "application/json")
 		fmt.Fprint(w, `{
@@ -70,35 +60,35 @@ func TestCreateZoneLockdown(t *testing.T) {
 
 	mux.HandleFunc("/zones/"+testZoneID+"/firewall/lockdowns", handler)
 
-	actual, err := client.CreateZoneLockdown(context.Background(), ZoneIdentifier(testZoneID), input)
+	actual, err := client.CreateZoneLockdown(context.Background(), testZoneID, input)
 	require.NoError(t, err)
 
-	want.ID = "372e67954025e0ba6aaa6d586b9e0b59"
 	createdOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00Z")
 	modifiedOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00Z")
-	want.CreatedOn = &createdOn
-	want.ModifiedOn = &modifiedOn
-
+	want := &ZoneLockdownResponse{
+		Result: ZoneLockdown{
+			ID:             "372e67954025e0ba6aaa6d586b9e0b59",
+			Description:    input.Description,
+			URLs:           input.URLs,
+			Configurations: input.Configurations,
+			Paused:         input.Paused,
+			CreatedOn:      &createdOn,
+			ModifiedOn:     &modifiedOn,
+		},
+		Response: Response{
+			Success:  true,
+			Errors:   []ResponseInfo{},
+			Messages: []ResponseInfo{},
+		},
+	}
 	assert.Equal(t, want, actual)
 }
 
-func TestUpdateZoneLockdown(t *testing.T) {
+func TestUpdateZoneLockdownt(t *testing.T) {
 	setup()
 	defer teardown()
 
-	input := ZoneLockdownUpdateParams{
-		ID:          "372e67954025e0ba6aaa6d586b9e0b59",
-		Description: "Restrict access to these endpoints to requests from a known IP address",
-		URLs:        []string{"api.mysite.com/some/endpoint*"},
-		Configurations: []ZoneLockdownConfig{{
-			Target: "ip",
-			Value:  "198.51.100.4",
-		}},
-		Paused: false,
-	}
-
-	want := ZoneLockdown{
-		ID:          "372e67954025e0ba6aaa6d586b9e0b59",
+	input := ZoneLockdown{
 		Description: "Restrict access to these endpoints to requests from a known IP address",
 		URLs:        []string{"api.mysite.com/some/endpoint*"},
 		Configurations: []ZoneLockdownConfig{{
@@ -114,7 +104,7 @@ func TestUpdateZoneLockdown(t *testing.T) {
 		var v ZoneLockdown
 		err := json.NewDecoder(r.Body).Decode(&v)
 		require.NoError(t, err)
-		assert.Equal(t, want, v)
+		assert.Equal(t, input, v)
 
 		w.Header().Set("content-type", "application/json")
 		fmt.Fprint(w, `{
@@ -140,16 +130,31 @@ func TestUpdateZoneLockdown(t *testing.T) {
 		}`)
 	}
 
-	mux.HandleFunc("/zones/"+testZoneID+"/firewall/lockdowns/372e67954025e0ba6aaa6d586b9e0b59", handler)
+	zoneLockdownID := "372e67954025e0ba6aaa6d586b9e0b59"
+
+	mux.HandleFunc("/zones/"+testZoneID+"/firewall/lockdowns/"+zoneLockdownID, handler)
 
-	actual, err := client.UpdateZoneLockdown(context.Background(), ZoneIdentifier(testZoneID), input)
+	actual, err := client.UpdateZoneLockdown(context.Background(), testZoneID, zoneLockdownID, input)
 	require.NoError(t, err)
 
 	createdOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00Z")
 	modifiedOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00Z")
-	want.CreatedOn = &createdOn
-	want.ModifiedOn = &modifiedOn
-
+	want := &ZoneLockdownResponse{
+		Result: ZoneLockdown{
+			ID:             zoneLockdownID,
+			Description:    input.Description,
+			URLs:           input.URLs,
+			Configurations: input.Configurations,
+			Paused:         input.Paused,
+			CreatedOn:      &createdOn,
+			ModifiedOn:     &modifiedOn,
+		},
+		Response: Response{
+			Success:  true,
+			Errors:   []ResponseInfo{},
+			Messages: []ResponseInfo{},
+		},
+	}
 	assert.Equal(t, want, actual)
 }
 
@@ -175,11 +180,18 @@ func TestDeleteZoneLockdown(t *testing.T) {
 
 	mux.HandleFunc("/zones/"+testZoneID+"/firewall/lockdowns/"+zoneLockdownID, handler)
 
-	actual, err := client.DeleteZoneLockdown(context.Background(), ZoneIdentifier(testZoneID), zoneLockdownID)
+	actual, err := client.DeleteZoneLockdown(context.Background(), testZoneID, zoneLockdownID)
 	require.NoError(t, err)
 
-	want := ZoneLockdown{
-		ID: zoneLockdownID,
+	want := &ZoneLockdownResponse{
+		Result: ZoneLockdown{
+			ID: zoneLockdownID,
+		},
+		Response: Response{
+			Success:  true,
+			Errors:   []ResponseInfo{},
+			Messages: []ResponseInfo{},
+		},
 	}
 	assert.Equal(t, want, actual)
 }
@@ -219,22 +231,29 @@ func TestZoneLockdown(t *testing.T) {
 
 	mux.HandleFunc("/zones/"+testZoneID+"/firewall/lockdowns/"+zoneLockdownID, handler)
 
-	actual, err := client.ZoneLockdown(context.Background(), ZoneIdentifier(testZoneID), zoneLockdownID)
+	actual, err := client.ZoneLockdown(context.Background(), testZoneID, zoneLockdownID)
 	require.NoError(t, err)
 
 	createdOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00Z")
 	modifiedOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00Z")
-	want := ZoneLockdown{
-		ID:          zoneLockdownID,
-		Description: "Restrict access to these endpoints to requests from a known IP address",
-		URLs:        []string{"api.mysite.com/some/endpoint*"},
-		Configurations: []ZoneLockdownConfig{{
-			Target: "ip",
-			Value:  "198.51.100.4",
-		}},
-		Paused:     false,
-		CreatedOn:  &createdOn,
-		ModifiedOn: &modifiedOn,
+	want := &ZoneLockdownResponse{
+		Result: ZoneLockdown{
+			ID:          zoneLockdownID,
+			Description: "Restrict access to these endpoints to requests from a known IP address",
+			URLs:        []string{"api.mysite.com/some/endpoint*"},
+			Configurations: []ZoneLockdownConfig{{
+				Target: "ip",
+				Value:  "198.51.100.4",
+			}},
+			Paused:     false,
+			CreatedOn:  &createdOn,
+			ModifiedOn: &modifiedOn,
+		},
+		Response: Response{
+			Success:  true,
+			Errors:   []ResponseInfo{},
+			Messages: []ResponseInfo{},
+		},
 	}
 	assert.Equal(t, want, actual)
 }
@@ -245,6 +264,7 @@ func TestListZoneLockdowns(t *testing.T) {
 
 	handler := func(w http.ResponseWriter, r *http.Request) {
 		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s")
+		assert.Equal(t, "1", r.URL.Query().Get("page"))
 
 		w.Header().Set("content-type", "application/json")
 		fmt.Fprint(w, `{
@@ -280,23 +300,35 @@ func TestListZoneLockdowns(t *testing.T) {
 
 	mux.HandleFunc("/zones/"+testZoneID+"/firewall/lockdowns", handler)
 
-	actual, _, err := client.ListZoneLockdowns(context.Background(), ZoneIdentifier(testZoneID), LockdownListParams{})
+	actual, err := client.ListZoneLockdowns(context.Background(), testZoneID, 1)
 	require.NoError(t, err)
 
 	createdOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00Z")
 	modifiedOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00Z")
-	want := []ZoneLockdown{{
-		ID:          "372e67954025e0ba6aaa6d586b9e0b59",
-		Description: "Restrict access to these endpoints to requests from a known IP address",
-		URLs:        []string{"api.mysite.com/some/endpoint*"},
-		Configurations: []ZoneLockdownConfig{{
-			Target: "ip",
-			Value:  "198.51.100.4",
+	want := &ZoneLockdownListResponse{
+		Result: []ZoneLockdown{{
+			ID:          "372e67954025e0ba6aaa6d586b9e0b59",
+			Description: "Restrict access to these endpoints to requests from a known IP address",
+			URLs:        []string{"api.mysite.com/some/endpoint*"},
+			Configurations: []ZoneLockdownConfig{{
+				Target: "ip",
+				Value:  "198.51.100.4",
+			}},
+			Paused:     false,
+			CreatedOn:  &createdOn,
+			ModifiedOn: &modifiedOn,
 		}},
-		Paused:     false,
-		CreatedOn:  &createdOn,
-		ModifiedOn: &modifiedOn,
-	},
+		Response: Response{
+			Success:  true,
+			Errors:   []ResponseInfo{},
+			Messages: []ResponseInfo{},
+		},
+		ResultInfo: ResultInfo{
+			Page:    1,
+			PerPage: 20,
+			Count:   1,
+			Total:   2000,
+		},
 	}
 	assert.Equal(t, want, actual)
 }
diff --git a/teams_locations_test.go b/teams_locations_test.go
index d37d336f3..5f88026b1 100644
--- a/teams_locations_test.go
+++ b/teams_locations_test.go
@@ -28,7 +28,7 @@ func TestTeamsLocations(t *testing.T) {
 					"name": "home",
 					"networks": [
 						{
-							"network": "198.51.100.1/32",
+							"network": "99.151.35.207/32",
 							"id": "8e4c7835436345f0ab395429b187a076"
 						}
 					],
@@ -53,7 +53,7 @@ func TestTeamsLocations(t *testing.T) {
 	want := []TeamsLocation{{
 		ID:                    "0f8185414dec4a5e9034f3d917c17890",
 		Name:                  "home",
-		Networks:              []TeamsLocationNetwork{{ID: "8e4c7835436345f0ab395429b187a076", Network: "198.51.100.1/32"}},
+		Networks:              []TeamsLocationNetwork{{ID: "8e4c7835436345f0ab395429b187a076", Network: "99.151.35.207/32"}},
 		PolicyIDs:             []string{},
 		Ip:                    "2a06:98c1:54::2419",
 		Subdomain:             "q15l7x2lbw",
@@ -88,7 +88,7 @@ func TestTeamsLocation(t *testing.T) {
 				"name": "home",
 				"networks": [
 					{
-						"network": "198.51.100.1/32",
+						"network": "99.151.35.207/32",
 						"id": "8e4c7835436345f0ab395429b187a076"
 					}
 				],
@@ -111,7 +111,7 @@ func TestTeamsLocation(t *testing.T) {
 	want := TeamsLocation{
 		ID:                    id,
 		Name:                  "home",
-		Networks:              []TeamsLocationNetwork{{ID: "8e4c7835436345f0ab395429b187a076", Network: "198.51.100.1/32"}},
+		Networks:              []TeamsLocationNetwork{{ID: "8e4c7835436345f0ab395429b187a076", Network: "99.151.35.207/32"}},
 		PolicyIDs:             []string{},
 		Ip:                    "2a06:98c1:54::2419",
 		Subdomain:             "q15l7x2lbw",
@@ -146,7 +146,7 @@ func TestCreateTeamsLocation(t *testing.T) {
 				"name": "test",
 				"networks": [
 					{
-						"network": "198.51.100.1/32",
+						"network": "99.151.35.207/32",
 						"id": "8e4c7835436345f0ab395429b187a076"
 					}
 				],
@@ -169,7 +169,7 @@ func TestCreateTeamsLocation(t *testing.T) {
 	want := TeamsLocation{
 		ID:                    id,
 		Name:                  "test",
-		Networks:              []TeamsLocationNetwork{{ID: "8e4c7835436345f0ab395429b187a076", Network: "198.51.100.1/32"}},
+		Networks:              []TeamsLocationNetwork{{ID: "8e4c7835436345f0ab395429b187a076", Network: "99.151.35.207/32"}},
 		PolicyIDs:             []string{},
 		Ip:                    "2a06:98c1:54::2419",
 		Subdomain:             "q15l7x2lbw",
@@ -208,7 +208,7 @@ func TestUpdateTeamsLocation(t *testing.T) {
 				"name": "new",
 				"networks": [
 					{
-						"network": "198.51.100.1/32",
+						"network": "99.151.35.207/32",
 						"id": "8e4c7835436345f0ab395429b187a076"
 					}
 				],
@@ -231,7 +231,7 @@ func TestUpdateTeamsLocation(t *testing.T) {
 	want := TeamsLocation{
 		ID:                    id,
 		Name:                  "new",
-		Networks:              []TeamsLocationNetwork{{ID: "8e4c7835436345f0ab395429b187a076", Network: "198.51.100.1/32"}},
+		Networks:              []TeamsLocationNetwork{{ID: "8e4c7835436345f0ab395429b187a076", Network: "99.151.35.207/32"}},
 		PolicyIDs:             []string{},
 		Ip:                    "2a06:98c1:54::2419",
 		Subdomain:             "q15l7x2lbw",
diff --git a/testdata/fixtures/tunnel/multiple_full.json b/testdata/fixtures/tunnel/multiple_full.json
index 409911a8f..524c22f35 100644
--- a/testdata/fixtures/tunnel/multiple_full.json
+++ b/testdata/fixtures/tunnel/multiple_full.json
@@ -16,7 +16,7 @@
           "client_id": "dc6472cc-f1ae-44a0-b795-6b8a0ce29f90",
           "client_version": "2022.2.0",
           "opened_at": "2021-01-25T18:22:34.317854Z",
-          "origin_ip": "198.51.100.1"
+          "origin_ip": "85.12.78.6"
         }
       ]
     }
diff --git a/testdata/fixtures/tunnel/single_full.json b/testdata/fixtures/tunnel/single_full.json
index 5408bdb56..b447c75c2 100644
--- a/testdata/fixtures/tunnel/single_full.json
+++ b/testdata/fixtures/tunnel/single_full.json
@@ -15,7 +15,7 @@
         "client_id": "dc6472cc-f1ae-44a0-b795-6b8a0ce29f90",
         "client_version": "2022.2.0",
         "opened_at": "2021-01-25T18:22:34.317854Z",
-        "origin_ip": "198.51.100.1"
+        "origin_ip": "85.12.78.6"
       }
     ]
   }
diff --git a/tunnel_test.go b/tunnel_test.go
index 48f8f386c..ab013a694 100644
--- a/tunnel_test.go
+++ b/tunnel_test.go
@@ -36,7 +36,7 @@ func TestTunnels(t *testing.T) {
 			ClientID:           "dc6472cc-f1ae-44a0-b795-6b8a0ce29f90",
 			ClientVersion:      "2022.2.0",
 			OpenedAt:           "2021-01-25T18:22:34.317854Z",
-			OriginIP:           "198.51.100.1",
+			OriginIP:           "85.12.78.6",
 		}},
 	}}
 
@@ -73,7 +73,7 @@ func TestTunnel(t *testing.T) {
 			ClientID:           "dc6472cc-f1ae-44a0-b795-6b8a0ce29f90",
 			ClientVersion:      "2022.2.0",
 			OpenedAt:           "2021-01-25T18:22:34.317854Z",
-			OriginIP:           "198.51.100.1",
+			OriginIP:           "85.12.78.6",
 		}},
 	}
 
@@ -110,7 +110,7 @@ func TestCreateTunnel(t *testing.T) {
 			ClientID:           "dc6472cc-f1ae-44a0-b795-6b8a0ce29f90",
 			ClientVersion:      "2022.2.0",
 			OpenedAt:           "2021-01-25T18:22:34.317854Z",
-			OriginIP:           "198.51.100.1",
+			OriginIP:           "85.12.78.6",
 		}},
 	}
 
@@ -249,7 +249,7 @@ func TestTunnelConnections(t *testing.T) {
 						"client_id": "dc6472cc-f1ae-44a0-b795-6b8a0ce29f90",
 						"client_version": "2022.2.0",
 						"opened_at": "2021-01-25T18:22:34.317854Z",
-						"origin_ip": "198.51.100.1"
+						"origin_ip": "85.12.78.6"
 					}
 				]
 			}]
@@ -278,7 +278,7 @@ func TestTunnelConnections(t *testing.T) {
 				ClientID:           "dc6472cc-f1ae-44a0-b795-6b8a0ce29f90",
 				ClientVersion:      "2022.2.0",
 				OpenedAt:           "2021-01-25T18:22:34.317854Z",
-				OriginIP:           "198.51.100.1",
+				OriginIP:           "85.12.78.6",
 			}},
 		},
 	}
diff --git a/workers_example_test.go b/workers_example_test.go
index 2206a3504..d3350fa81 100644
--- a/workers_example_test.go
+++ b/workers_example_test.go
@@ -23,7 +23,7 @@ func ExampleAPI_UploadWorker() {
 		log.Fatal(err)
 	}
 
-	res, err := api.UploadWorker(context.Background(), &cloudflare.WorkerRequestParams{ZoneID: zoneID}, &cloudflare.WorkerScriptParams{Script: workerScript})
+	res, err := api.UploadWorker(context.Background(), &cloudflare.WorkerRequestParams{ZoneID: zoneID}, workerScript)
 	if err != nil {
 		log.Fatal(err)
 	}
@@ -38,7 +38,7 @@ func UploadWorkerWithName() {
 		log.Fatal(err)
 	}
 
-	res, err := api.UploadWorker(context.Background(), &cloudflare.WorkerRequestParams{ScriptName: "baz"}, &cloudflare.WorkerScriptParams{Script: workerScript})
+	res, err := api.UploadWorker(context.Background(), &cloudflare.WorkerRequestParams{ScriptName: "baz"}, workerScript)
 	if err != nil {
 		log.Fatal(err)
 	}
diff --git a/workers_subdomain_test.go b/workers_subdomain_test.go
deleted file mode 100644
index 33b12886e..000000000
--- a/workers_subdomain_test.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package cloudflare
-
-import (
-	"context"
-	"fmt"
-	"github.com/stretchr/testify/assert"
-	"net/http"
-	"testing"
-)
-
-func TestWorkersSubdomain_CreateSubdomain(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc(fmt.Sprintf("/accounts/%s/workers/subdomain", testAccountID), func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprintf(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": {
-    "name": "example-subdomain"
-  }
-}`)
-	})
-
-	_, err := client.WorkersCreateSubdomain(context.Background(), AccountIdentifier(""), WorkersSubdomain{})
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingAccountID, err)
-	}
-
-	res, err := client.WorkersCreateSubdomain(context.Background(), AccountIdentifier(testAccountID), WorkersSubdomain{Name: "example-subdomain"})
-
-	want := WorkersSubdomain{Name: "example-subdomain"}
-
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, res)
-	}
-}
-
-func TestWorkersSubdomain_GetSubdomain(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc(fmt.Sprintf("/accounts/%s/workers/subdomain", testAccountID), func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprintf(w, `{
-  "success": true,
-  "errors": [],
-  "messages": [],
-  "result": {
-    "name": "example-subdomain"
-  }
-}`)
-	})
-
-	_, err := client.WorkersGetSubdomain(context.Background(), AccountIdentifier(""))
-	if assert.Error(t, err) {
-		assert.Equal(t, ErrMissingAccountID, err)
-	}
-
-	res, err := client.WorkersGetSubdomain(context.Background(), AccountIdentifier(testAccountID))
-
-	want := WorkersSubdomain{Name: "example-subdomain"}
-
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, res)
-	}
-}
diff --git a/workers_test.go b/workers_test.go
index d21819c0c..a9e329d36 100644
--- a/workers_test.go
+++ b/workers_test.go
@@ -5,7 +5,6 @@ import (
 	"encoding/json"
 	"fmt"
 	"io/ioutil"
-	"mime/multipart"
 	"net/http"
 	"strings"
 	"testing"
@@ -32,18 +31,6 @@ const (
     "errors": [],
     "messages": []
 }`
-
-	uploadWorkerModuleResponseData = `{
-    "result": {
-        "script": "export default {\n    async fetch(request, env, event) {\n     event.passThroughOnException()\n    return fetch(request)\n    }\n}",
-        "etag": "279cf40d86d70b82f6cd3ba90a646b3ad995912da446836d7371c21c6a43977a",
-        "size": 191,
-        "modified_on": "2018-06-09T15:17:01.989141Z"
-    },
-    "success": true,
-    "errors": [],
-    "messages": []
-}`
 	updateWorkerRouteResponse = `{
     "result": {
         "id": "e7a57d8746e74ae49c25994dadb421b1",
@@ -184,8 +171,20 @@ const (
 var (
 	successResponse               = Response{Success: true, Errors: []ResponseInfo{}, Messages: []ResponseInfo{}}
 	workerScript                  = "addEventListener('fetch', event => {\n    event.passThroughOnException()\nevent.respondWith(handleRequest(event.request))\n})\n\nasync function handleRequest(request) {\n    return fetch(request)\n}"
-	workerModuleScript            = "export default {\n    async fetch(request, env, event) {\n     event.passThroughOnException()\n    return fetch(request)\n    }\n}"
 	deleteWorkerRouteResponseData = createWorkerRouteResponse
+
+	attachWorkerToDomainResponse = fmt.Sprintf(`{
+    "result": {
+        "id": "e7a57d8746e74ae49c25994dadb421b1",
+	"zone_id": "%s",
+	"service":"test_script_1",
+	"hostname":"api4.example.com",
+	"environment":"production"
+    },
+    "success": true,
+    "errors": [],
+    "messages": []
+}`, testZoneID)
 )
 
 func getFormValue(r *http.Request, key string) ([]byte, error) {
@@ -217,21 +216,6 @@ func getFormValue(r *http.Request, key string) ([]byte, error) {
 	return nil, fmt.Errorf("no value found for key %v", key)
 }
 
-func getFileDetails(r *http.Request, key string) (*multipart.FileHeader, error) {
-	err := r.ParseMultipartForm(1024 * 1024)
-	if err != nil {
-		return nil, err
-	}
-
-	fileHeaders := r.MultipartForm.File[key]
-
-	if len(fileHeaders) > 0 {
-		return fileHeaders[0], nil
-	}
-
-	return nil, fmt.Errorf("no value found for key %v", key)
-}
-
 type multipartUpload struct {
 	Script      string
 	BindingMeta map[string]workerBindingMeta
@@ -245,9 +229,8 @@ func parseMultipartUpload(r *http.Request) (multipartUpload, error) {
 	}
 
 	var metadata struct {
-		BodyPart   string              `json:"body_part,omitempty"`
-		MainModule string              `json:"main_module,omitempty"`
-		Bindings   []workerBindingMeta `json:"bindings"`
+		BodyPart string              `json:"body_part"`
+		Bindings []workerBindingMeta `json:"bindings"`
 	}
 	err = json.Unmarshal(mdBytes, &metadata)
 	if err != nil {
@@ -257,11 +240,7 @@ func parseMultipartUpload(r *http.Request) (multipartUpload, error) {
 	// Get the script
 	script, err := getFormValue(r, metadata.BodyPart)
 	if err != nil {
-		script, err = getFormValue(r, metadata.MainModule)
-
-		if err != nil {
-			return multipartUpload{}, err
-		}
+		return multipartUpload{}, err
 	}
 
 	// Since bindings are specified in the Go API as a map but are uploaded as a
@@ -413,7 +392,7 @@ func TestWorkers_UploadWorker(t *testing.T) {
 		w.Header().Set("content-type", "application/json")
 		fmt.Fprintf(w, uploadWorkerResponseData) //nolint
 	})
-	res, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ZoneID: "foo"}, &WorkerScriptParams{Script: workerScript})
+	res, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ZoneID: "foo"}, workerScript)
 	formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z")
 	want := WorkerScriptResponse{
 		successResponse,
@@ -430,44 +409,6 @@ func TestWorkers_UploadWorker(t *testing.T) {
 	}
 }
 
-func TestWorkers_UploadWorkerAsModule(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/zones/foo/workers/script", func(w http.ResponseWriter, r *http.Request) {
-		mpUpload, err := parseMultipartUpload(r)
-		assert.NoError(t, err)
-
-		assert.Equal(t, workerModuleScript, mpUpload.Script)
-
-		workerFileDetails, err := getFileDetails(r, "worker.mjs")
-		if !assert.NoError(t, err) {
-			assert.FailNow(t, "worker file not found in multipart form body")
-		}
-		contentTypeHeader := workerFileDetails.Header.Get("content-type")
-		expectedContentType := "application/javascript+module"
-		assert.Equal(t, expectedContentType, contentTypeHeader, "Expected content-type request header to be %s, got %s", expectedContentType, contentTypeHeader)
-
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprintf(w, uploadWorkerModuleResponseData) //nolint
-	})
-	res, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ZoneID: "foo"}, &WorkerScriptParams{Script: workerModuleScript, Module: true})
-	formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z")
-	want := WorkerScriptResponse{
-		successResponse,
-		WorkerScript{
-			Script: workerModuleScript,
-			WorkerMetaData: WorkerMetaData{
-				ETAG:       "279cf40d86d70b82f6cd3ba90a646b3ad995912da446836d7371c21c6a43977a",
-				Size:       191,
-				ModifiedOn: formattedTime,
-			},
-		}}
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, res)
-	}
-}
-
 func TestWorkers_UploadWorkerWithName(t *testing.T) {
 	setup(UsingAccount("foo"))
 	defer teardown()
@@ -479,7 +420,7 @@ func TestWorkers_UploadWorkerWithName(t *testing.T) {
 		w.Header().Set("content-type", "application/json")
 		fmt.Fprintf(w, uploadWorkerResponseData) //nolint
 	})
-	res, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &WorkerScriptParams{Script: workerScript})
+	res, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, workerScript)
 	formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z")
 	want := WorkerScriptResponse{
 		successResponse,
@@ -507,7 +448,7 @@ func TestWorkers_UploadWorkerSingleScriptWithAccount(t *testing.T) {
 		w.Header().Set("content-type", "application/json")
 		fmt.Fprintf(w, uploadWorkerResponseData) //nolint
 	})
-	res, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ZoneID: "foo"}, &WorkerScriptParams{Script: workerScript})
+	res, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ZoneID: "foo"}, workerScript)
 	formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z")
 	want := WorkerScriptResponse{
 		successResponse,
@@ -528,7 +469,7 @@ func TestWorkers_UploadWorkerWithNameErrorsWithoutAccountId(t *testing.T) {
 	setup()
 	defer teardown()
 
-	_, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &WorkerScriptParams{Script: workerScript})
+	_, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, workerScript)
 	assert.Error(t, err)
 }
 
@@ -754,51 +695,6 @@ func TestWorkers_UploadWorkerWithPlainTextBinding(t *testing.T) {
 	assert.NoError(t, err)
 }
 
-func TestWorkers_UploadWorkerAsModuleWithPlainTextBinding(t *testing.T) {
-	setup(UsingAccount("foo"))
-	defer teardown()
-
-	mux.HandleFunc("/accounts/foo/workers/scripts/bar", func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method)
-
-		mpUpload, err := parseMultipartUpload(r)
-		assert.NoError(t, err)
-
-		expectedBindings := map[string]workerBindingMeta{
-			"b1": {
-				"name": "b1",
-				"type": "plain_text",
-				"text": "plain text value",
-			},
-		}
-		assert.Equal(t, workerModuleScript, mpUpload.Script)
-		assert.Equal(t, expectedBindings, mpUpload.BindingMeta)
-
-		workerFileDetails, err := getFileDetails(r, "worker.mjs")
-		if !assert.NoError(t, err) {
-			assert.FailNow(t, "worker file not found in multipart form body")
-		}
-		contentDispositonHeader := workerFileDetails.Header.Get("content-disposition")
-		expectedContentDisposition := fmt.Sprintf(`form-data; name="%s"; filename="%[1]s"`, "worker.mjs")
-		assert.Equal(t, expectedContentDisposition, contentDispositonHeader, "Expected content-disposition request header to be %s, got %s", expectedContentDisposition, contentDispositonHeader)
-
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprintf(w, uploadWorkerModuleResponseData) //nolint
-	})
-
-	scriptParams := WorkerScriptParams{
-		Script: workerModuleScript,
-		Module: true,
-		Bindings: map[string]WorkerBinding{
-			"b1": WorkerPlainTextBinding{
-				Text: "plain text value",
-			},
-		},
-	}
-	_, err := client.UploadWorkerWithBindings(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &scriptParams)
-	assert.NoError(t, err)
-}
-
 func TestWorkers_UploadWorkerWithSecretTextBinding(t *testing.T) {
 	setup(UsingAccount("foo"))
 	defer teardown()
@@ -1218,6 +1114,7 @@ func TestWorkers_UpdateWorkerRouteErrorsWhenMixingSingleAndMultiScriptProperties
 
 func TestWorkers_UpdateWorkerRouteWithNoScript(t *testing.T) {
 	setup(UsingAccount("foo"))
+	defer teardown()
 
 	mux.HandleFunc("/zones/foo/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) {
 		assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method)
@@ -1229,3 +1126,26 @@ func TestWorkers_UpdateWorkerRouteWithNoScript(t *testing.T) {
 	_, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route)
 	assert.NoError(t, err)
 }
+
+func TestWorkers_AttachWorkerToDomain(t *testing.T) {
+	setup(UsingAccount(testAccountID))
+	defer teardown()
+
+	mux.HandleFunc("/accounts/"+testAccountID+"/workers/domains", func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method)
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprintf(w, deleteWorkerResponseData) //nolint
+	})
+	res, err := client.AttachWorkerToDomain(context.Background(), AccountIdentifier(testAccountID), &WorkerDomainParams{
+		ZoneID:      testZoneID,
+		Hostname:    "app4.example.com",
+		Service:     "test_script_1",
+		Environment: "production",
+	})
+	want := WorkerDomainResponse{
+		successResponse,
+		WorkerDomainResult{}}
+	if assert.NoError(t, err) {
+		assert.Equal(t, want.Response, res.Response)
+	}
+}