diff --git a/alertmuting.go b/alertmuting.go
index 13b5ce5..d3bd24a 100644
--- a/alertmuting.go
+++ b/alertmuting.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -25,16 +24,13 @@ func (c *Client) CreateAlertMutingRule(ctx context.Context, muteRequest *alertmu
 	}
 
 	resp, err := c.doRequest(ctx, "POST", AlertMutingRuleAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusCreated {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusCreated); err != nil {
+		return nil, err
 	}
 
 	finalRule := &alertmuting.AlertMutingRule{}
@@ -48,16 +44,13 @@ func (c *Client) CreateAlertMutingRule(ctx context.Context, muteRequest *alertmu
 // DeleteAlertMutingRule deletes an alert muting rule.
 func (c *Client) DeleteAlertMutingRule(ctx context.Context, name string) error {
 	resp, err := c.doRequest(ctx, "DELETE", AlertMutingRuleAPIURL+"/"+name, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
@@ -67,16 +60,13 @@ func (c *Client) DeleteAlertMutingRule(ctx context.Context, name string) error {
 // GetAlertMutingRule gets an alert muting rule.
 func (c *Client) GetAlertMutingRule(ctx context.Context, id string) (*alertmuting.AlertMutingRule, error) {
 	resp, err := c.doRequest(ctx, "GET", AlertMutingRuleAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalRule := &alertmuting.AlertMutingRule{}
@@ -95,16 +85,13 @@ func (c *Client) UpdateAlertMutingRule(ctx context.Context, id string, muteReque
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", AlertMutingRuleAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalRule := &alertmuting.AlertMutingRule{}
@@ -124,12 +111,14 @@ func (c *Client) SearchAlertMutingRules(ctx context.Context, include string, lim
 	params.Add("offset", strconv.Itoa(offset))
 
 	resp, err := c.doRequest(ctx, "GET", AlertMutingRuleAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
+
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
+	}
 
 	finalRules := &alertmuting.SearchResult{}
 
diff --git a/aws_cloudwatch_integration.go b/aws_cloudwatch_integration.go
index 9981324..460369c 100644
--- a/aws_cloudwatch_integration.go
+++ b/aws_cloudwatch_integration.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -20,16 +19,13 @@ func (c *Client) CreateAWSCloudWatchIntegration(ctx context.Context, acwi *integ
 	}
 
 	resp, err := c.doRequest(ctx, "POST", IntegrationAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.AwsCloudWatchIntegration{}
@@ -43,16 +39,13 @@ func (c *Client) CreateAWSCloudWatchIntegration(ctx context.Context, acwi *integ
 // GetAWSCloudWatchIntegration retrieves an AWS CloudWatch integration.
 func (c *Client) GetAWSCloudWatchIntegration(ctx context.Context, id string) (*integration.AwsCloudWatchIntegration, error) {
 	resp, err := c.doRequest(ctx, "GET", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.AwsCloudWatchIntegration{}
@@ -71,16 +64,13 @@ func (c *Client) UpdateAWSCloudWatchIntegration(ctx context.Context, id string,
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", IntegrationAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.AwsCloudWatchIntegration{}
@@ -94,16 +84,13 @@ func (c *Client) UpdateAWSCloudWatchIntegration(ctx context.Context, id string,
 // DeleteAWSCloudWatchIntegration deletes an AWS CloudWatch integration.
 func (c *Client) DeleteAWSCloudWatchIntegration(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
diff --git a/azure_integration.go b/azure_integration.go
index 8800103..6ddf932 100644
--- a/azure_integration.go
+++ b/azure_integration.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -20,16 +19,13 @@ func (c *Client) CreateAzureIntegration(ctx context.Context, acwi *integration.A
 	}
 
 	resp, err := c.doRequest(ctx, "POST", IntegrationAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.AzureIntegration{}
@@ -43,16 +39,13 @@ func (c *Client) CreateAzureIntegration(ctx context.Context, acwi *integration.A
 // GetAzureIntegration retrieves an Azure integration.
 func (c *Client) GetAzureIntegration(ctx context.Context, id string) (*integration.AzureIntegration, error) {
 	resp, err := c.doRequest(ctx, "GET", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.AzureIntegration{}
@@ -71,16 +64,14 @@ func (c *Client) UpdateAzureIntegration(ctx context.Context, id string, acwi *in
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", IntegrationAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
+
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.AzureIntegration{}
@@ -94,16 +85,13 @@ func (c *Client) UpdateAzureIntegration(ctx context.Context, id string, acwi *in
 // DeleteAzureIntegration deletes an Azure integration.
 func (c *Client) DeleteAzureIntegration(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
diff --git a/chart.go b/chart.go
index 54bdfd3..10af821 100644
--- a/chart.go
+++ b/chart.go
@@ -4,8 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"errors"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -26,16 +24,13 @@ func (c *Client) CreateChart(ctx context.Context, chartRequest *chart.CreateUpda
 	}
 
 	resp, err := c.doRequest(ctx, "POST", ChartAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalChart := &chart.Chart{}
@@ -49,15 +44,13 @@ func (c *Client) CreateChart(ctx context.Context, chartRequest *chart.CreateUpda
 // DeleteChart deletes a chart.
 func (c *Client) DeleteChart(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", ChartAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		return errors.New("Unexpected status code: " + resp.Status)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
@@ -67,16 +60,13 @@ func (c *Client) DeleteChart(ctx context.Context, id string) error {
 // GetChart gets a chart.
 func (c *Client) GetChart(ctx context.Context, id string) (*chart.Chart, error) {
 	resp, err := c.doRequest(ctx, "GET", ChartAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalChart := &chart.Chart{}
@@ -95,16 +85,13 @@ func (c *Client) UpdateChart(ctx context.Context, id string, chartRequest *chart
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", ChartAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalChart := &chart.Chart{}
@@ -128,16 +115,13 @@ func (c *Client) SearchCharts(ctx context.Context, limit int, name string, offse
 	}
 
 	resp, err := c.doRequest(ctx, "GET", ChartAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalCharts := &chart.SearchResult{}
diff --git a/dashboard.go b/dashboard.go
index 9598fd0..0845e8b 100644
--- a/dashboard.go
+++ b/dashboard.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -27,16 +26,13 @@ func (c *Client) CreateDashboard(ctx context.Context, dashboardRequest *dashboar
 	}
 
 	resp, err := c.doRequest(ctx, "POST", DashboardAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDashboard := &dashboard.Dashboard{}
@@ -50,16 +46,13 @@ func (c *Client) CreateDashboard(ctx context.Context, dashboardRequest *dashboar
 // DeleteDashboard deletes a dashboard.
 func (c *Client) DeleteDashboard(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", DashboardAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
@@ -69,16 +62,13 @@ func (c *Client) DeleteDashboard(ctx context.Context, id string) error {
 // GetDashboard gets a dashboard.
 func (c *Client) GetDashboard(ctx context.Context, id string) (*dashboard.Dashboard, error) {
 	resp, err := c.doRequest(ctx, "GET", DashboardAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDashboard := &dashboard.Dashboard{}
@@ -97,16 +87,13 @@ func (c *Client) UpdateDashboard(ctx context.Context, id string, dashboardReques
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", DashboardAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDashboard := &dashboard.Dashboard{}
@@ -126,16 +113,13 @@ func (c *Client) SearchDashboard(ctx context.Context, limit int, name string, of
 	params.Add("tags", tags)
 
 	resp, err := c.doRequest(ctx, "GET", DashboardAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDashboards := &dashboard.SearchResult{}
diff --git a/dashboardgroup.go b/dashboardgroup.go
index e400f35..1415d84 100644
--- a/dashboardgroup.go
+++ b/dashboardgroup.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -32,16 +31,13 @@ func (c *Client) CreateDashboardGroup(ctx context.Context, dashboardGroupRequest
 	}
 
 	resp, err := c.doRequest(ctx, "POST", DashboardGroupAPIURL, params, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDashboardGroup := &dashboard_group.DashboardGroup{}
@@ -55,16 +51,13 @@ func (c *Client) CreateDashboardGroup(ctx context.Context, dashboardGroupRequest
 // DeleteDashboardGroup deletes a dashboard.
 func (c *Client) DeleteDashboardGroup(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", DashboardGroupAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
@@ -74,16 +67,13 @@ func (c *Client) DeleteDashboardGroup(ctx context.Context, id string) error {
 // GetDashboardGroup gets a dashboard group.
 func (c *Client) GetDashboardGroup(ctx context.Context, id string) (*dashboard_group.DashboardGroup, error) {
 	resp, err := c.doRequest(ctx, "GET", DashboardGroupAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDashboardGroup := &dashboard_group.DashboardGroup{}
@@ -102,16 +92,13 @@ func (c *Client) UpdateDashboardGroup(ctx context.Context, id string, dashboardG
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", DashboardGroupAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDashboardGroup := &dashboard_group.DashboardGroup{}
@@ -130,16 +117,13 @@ func (c *Client) SearchDashboardGroups(ctx context.Context, limit int, name stri
 	params.Add("offset", strconv.Itoa(offset))
 
 	resp, err := c.doRequest(ctx, "GET", DashboardGroupAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDashboardGroups := &dashboard_group.SearchResult{}
diff --git a/datalink.go b/datalink.go
index 8c123d8..15144ea 100644
--- a/datalink.go
+++ b/datalink.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -25,16 +24,13 @@ func (c *Client) CreateDataLink(ctx context.Context, dataLinkRequest *datalink.C
 	}
 
 	resp, err := c.doRequest(ctx, "POST", DataLinkAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDataLink := &datalink.DataLink{}
@@ -48,19 +44,17 @@ func (c *Client) CreateDataLink(ctx context.Context, dataLinkRequest *datalink.C
 // DeleteDataLink deletes a data link.
 func (c *Client) DeleteDataLink(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", DataLinkAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
 	// The API returns a 200 here, which I think is a mistake so covering for
 	// future changes.
-	if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent, http.StatusOK); err != nil {
+		return err
 	}
+
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
 	return nil
@@ -69,16 +63,13 @@ func (c *Client) DeleteDataLink(ctx context.Context, id string) error {
 // GetDataLink gets a data link.
 func (c *Client) GetDataLink(ctx context.Context, id string) (*datalink.DataLink, error) {
 	resp, err := c.doRequest(ctx, "GET", DataLinkAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDataLink := &datalink.DataLink{}
@@ -98,16 +89,14 @@ func (c *Client) UpdateDataLink(ctx context.Context, id string, dataLinkRequest
 
 	encodedName := url.PathEscape(id)
 	resp, err := c.doRequest(ctx, "PUT", DataLinkAPIURL+"/"+encodedName, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
+
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDataLink := &datalink.DataLink{}
@@ -126,16 +115,13 @@ func (c *Client) SearchDataLinks(ctx context.Context, limit int, context string,
 	params.Add("offset", strconv.Itoa(offset))
 
 	resp, err := c.doRequest(ctx, "GET", DataLinkAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDataLinks := &datalink.SearchResults{}
diff --git a/detector.go b/detector.go
index 8303783..c5a0f52 100644
--- a/detector.go
+++ b/detector.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -25,16 +24,13 @@ func (c *Client) CreateDetector(ctx context.Context, detectorRequest *detector.C
 	}
 
 	resp, err := c.doRequest(ctx, "POST", DetectorAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDetector := &detector.Detector{}
@@ -48,16 +44,13 @@ func (c *Client) CreateDetector(ctx context.Context, detectorRequest *detector.C
 // DeleteDetector deletes a detector.
 func (c *Client) DeleteDetector(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", DetectorAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
@@ -72,16 +65,13 @@ func (c *Client) DisableDetector(ctx context.Context, id string, labels []string
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", DetectorAPIURL+"/"+id+"/disable", nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
@@ -96,16 +86,13 @@ func (c *Client) EnableDetector(ctx context.Context, id string, labels []string)
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", DetectorAPIURL+"/"+id+"/enable", nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
@@ -115,16 +102,13 @@ func (c *Client) EnableDetector(ctx context.Context, id string, labels []string)
 // GetDetector gets a detector.
 func (c *Client) GetDetector(ctx context.Context, id string) (*detector.Detector, error) {
 	resp, err := c.doRequest(ctx, "GET", DetectorAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDetector := &detector.Detector{}
@@ -143,16 +127,13 @@ func (c *Client) UpdateDetector(ctx context.Context, id string, detectorRequest
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", DetectorAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDetector := &detector.Detector{}
@@ -174,16 +155,13 @@ func (c *Client) SearchDetectors(ctx context.Context, limit int, name string, of
 	}
 
 	resp, err := c.doRequest(ctx, "GET", DetectorAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDetectors := &detector.SearchResults{}
@@ -202,16 +180,13 @@ func (c *Client) GetDetectorEvents(ctx context.Context, id string, from int, to
 	params.Add("offset", strconv.Itoa(offset))
 	params.Add("limit", strconv.Itoa(limit))
 	resp, err := c.doRequest(ctx, "GET", DetectorAPIURL+"/"+id+"/events", params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	var events []*detector.Event
@@ -228,16 +203,13 @@ func (c *Client) GetDetectorIncidents(ctx context.Context, id string, offset int
 	params.Add("offset", strconv.Itoa(offset))
 	params.Add("limit", strconv.Itoa(limit))
 	resp, err := c.doRequest(ctx, "GET", DetectorAPIURL+"/"+id+"/incidents", params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	var incidents []*detector.Incident
@@ -256,16 +228,13 @@ func (c *Client) ValidateDetector(ctx context.Context, detectorRequest *detector
 	}
 
 	resp, err := c.doRequest(ctx, "POST", DetectorAPIURL+"/validate", nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
diff --git a/errors.go b/errors.go
new file mode 100644
index 0000000..eacb176
--- /dev/null
+++ b/errors.go
@@ -0,0 +1,80 @@
+package signalfx
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"net/http"
+	"slices"
+)
+
+// ResponseError captures the error details
+// and allows for it to be inspected by external libraries.
+type ResponseError struct {
+	code    int
+	route   string
+	details string
+}
+
+var _ error = (*ResponseError)(nil)
+
+func newResponseError(resp *http.Response, target int, targets ...int) error {
+	if resp == nil {
+		return nil
+	}
+
+	if slices.Contains(append([]int{target}, targets...), resp.StatusCode) {
+		return nil
+	}
+
+	details, _ := io.ReadAll(resp.Body)
+
+	return &ResponseError{
+		code:    resp.StatusCode,
+		route:   resp.Request.URL.Path,
+		details: string(details),
+	}
+}
+
+// AsResponseError is a convenience function to check the error
+// to see if it contains an `ResponseError` and returns the value with true.
+// If the error was initially joined using [errors.Join], it will check each error
+// within the list and return the first matching error.
+func AsResponseError(err error) (*ResponseError, bool) {
+	// When `errors.Join` is called, it returns an error that
+	// matches the provided interface.
+	if joined, ok := err.(interface{ Unwrap() []error }); ok {
+		for _, err := range joined.Unwrap() {
+			if re, ok := AsResponseError(err); ok {
+				return re, ok
+			}
+		}
+		return nil, false
+	}
+
+	for err != nil {
+		if re, ok := err.(*ResponseError); ok {
+			return re, true
+		}
+		// In case the error is wrapped using `fmt.Errorf`
+		// this will also account for that.
+		err = errors.Unwrap(err)
+	}
+	return nil, false
+}
+
+func (re *ResponseError) Error() string {
+	return fmt.Sprintf("route %q had issues with status code %d", re.route, re.code)
+}
+
+func (re *ResponseError) Code() int {
+	return re.code
+}
+
+func (re *ResponseError) Route() string {
+	return re.route
+}
+
+func (re *ResponseError) Details() string {
+	return re.details
+}
diff --git a/errors_test.go b/errors_test.go
new file mode 100644
index 0000000..0ed14de
--- /dev/null
+++ b/errors_test.go
@@ -0,0 +1,163 @@
+package signalfx
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"net/http"
+	"net/url"
+	"strings"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestRequestError(t *testing.T) {
+	t.Parallel()
+
+	for _, tc := range []struct {
+		name string
+		re   *ResponseError
+		err  string
+	}{
+		{
+			name: "simple request error",
+			re: &ResponseError{
+				code:    404,
+				route:   "/internal/heathz",
+				details: "failed due to overworked",
+			},
+			err: "route \"/internal/heathz\" had issues with status code 404",
+		},
+		{
+			name: "missed details",
+			re: &ResponseError{
+				code:  404,
+				route: "/internal/heathz",
+			},
+			err: "route \"/internal/heathz\" had issues with status code 404",
+		},
+		{
+			name: "missed code",
+			re: &ResponseError{
+				route: "/internal/heathz",
+			},
+			err: "route \"/internal/heathz\" had issues with status code 0",
+		},
+		{
+			name: "missed all info",
+			re:   &ResponseError{},
+			err:  "route \"\" had issues with status code 0",
+		},
+	} {
+		tc := tc
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+
+			assert.EqualError(t, tc.re, tc.err, "Must match the expected error string")
+		})
+	}
+}
+
+func TestNewRequestError(t *testing.T) {
+	t.Parallel()
+
+	for _, tc := range []struct {
+		name   string
+		resp   *http.Response
+		expect error
+	}{
+		{
+			name:   "no response",
+			resp:   nil,
+			expect: nil,
+		},
+		{
+			name: "successful response",
+			resp: &http.Response{
+				StatusCode: http.StatusOK,
+				Request: &http.Request{
+					URL: &url.URL{Host: "localhost", Path: "/internal/heathz"},
+				},
+				Body: io.NopCloser(strings.NewReader("successs")),
+			},
+			expect: nil,
+		},
+		{
+			name: "failed response",
+			resp: &http.Response{
+				StatusCode: http.StatusInternalServerError,
+				Request: &http.Request{
+					URL: &url.URL{Host: "localhost", Path: "/internal/heathz"},
+				},
+				Body: io.NopCloser(strings.NewReader("issue trying to connect")),
+			},
+			expect: &ResponseError{
+				code:    http.StatusInternalServerError,
+				route:   "/internal/heathz",
+				details: "issue trying to connect",
+			},
+		},
+	} {
+		tc := tc
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+
+			assert.Equal(t, tc.expect, newResponseError(tc.resp, http.StatusOK), "Must match the exected value")
+		})
+	}
+}
+
+func TestIsRequestError(t *testing.T) {
+	t.Parallel()
+
+	for _, tc := range []struct {
+		name     string
+		err      error
+		expected bool
+	}{
+		{
+			name:     "no error provided",
+			err:      nil,
+			expected: false,
+		},
+		{
+			name:     "not a request error",
+			err:      errors.New("failed"),
+			expected: false,
+		},
+		{
+			name:     "is a request error",
+			err:      &ResponseError{},
+			expected: true,
+		},
+		{
+			name:     "joined errors",
+			err:      errors.Join(errors.New("boom"), &ResponseError{}),
+			expected: true,
+		},
+		{
+			name:     "fmt error",
+			err:      fmt.Errorf("check permissions: %w", &ResponseError{}),
+			expected: true,
+		},
+	} {
+		tc := tc
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+
+			_, ok := AsResponseError(tc.err)
+			assert.Equal(t, tc.expected, ok, "Must match the expected value")
+		})
+	}
+}
+
+func TestRequestErrorMethods(t *testing.T) {
+	t.Parallel()
+
+	re := &ResponseError{code: http.StatusOK, route: "/heathz", details: "service alive"}
+
+	assert.Equal(t, 200, re.Code(), "Must match the expected code")
+	assert.Equal(t, "/heathz", re.Route(), "Must match the expected route")
+	assert.Equal(t, "service alive", re.Details(), "Must match the expected details")
+}
diff --git a/gcp_integration.go b/gcp_integration.go
index 47d6d3c..2aa8faa 100644
--- a/gcp_integration.go
+++ b/gcp_integration.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -20,16 +19,13 @@ func (c *Client) CreateGCPIntegration(ctx context.Context, gcpi *integration.GCP
 	}
 
 	resp, err := c.doRequest(ctx, "POST", IntegrationAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.GCPIntegration{}
@@ -43,16 +39,13 @@ func (c *Client) CreateGCPIntegration(ctx context.Context, gcpi *integration.GCP
 // GetGCPIntegration retrieves a GCP integration.
 func (c *Client) GetGCPIntegration(ctx context.Context, id string) (*integration.GCPIntegration, error) {
 	resp, err := c.doRequest(ctx, "GET", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.GCPIntegration{}
@@ -71,16 +64,13 @@ func (c *Client) UpdateGCPIntegration(ctx context.Context, id string, gcpi *inte
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", IntegrationAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.GCPIntegration{}
@@ -94,16 +84,13 @@ func (c *Client) UpdateGCPIntegration(ctx context.Context, id string, gcpi *inte
 // DeleteGCPIntegration deletes a GCP integration.
 func (c *Client) DeleteGCPIntegration(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
diff --git a/incident.go b/incident.go
index 57a6d86..50e8b05 100644
--- a/incident.go
+++ b/incident.go
@@ -3,7 +3,6 @@ package signalfx
 import (
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -19,16 +18,13 @@ const IncidentAPIURL = "/v2/incident"
 // Get incident with the given id
 func (c *Client) GetIncident(ctx context.Context, id string) (*detector.Incident, error) {
 	resp, err := c.doRequest(ctx, "GET", IncidentAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIncident := &detector.Incident{}
@@ -47,20 +43,14 @@ func (c *Client) GetIncidents(ctx context.Context, includeResolved bool, limit i
 	params.Add("query", query)
 	params.Add("offset", strconv.Itoa(offset))
 	resp, err := c.doRequest(ctx, "GET", IncidentAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
-	if resp.StatusCode != http.StatusOK {
-		body, err := io.ReadAll(resp.Body)
-		if err != nil {
-			return nil, err
-		}
-		return nil, fmt.Errorf(string(body))
-	}
 	if err != nil {
 		return nil, err
 	}
 
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
+	}
+
 	var incidents []*detector.Incident
 	err = json.NewDecoder(resp.Body).Decode(&incidents)
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
diff --git a/integration.go b/integration.go
index b96dcb3..a4b7bfa 100644
--- a/integration.go
+++ b/integration.go
@@ -10,7 +10,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -69,9 +68,8 @@ func (c *Client) doIntegrationRequest(ctx context.Context, url string, method st
 		return err
 	}
 
-	if resp.StatusCode != status {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, status); err != nil {
+		return err
 	}
 
 	if out != nil {
diff --git a/jira_integration.go b/jira_integration.go
index 8e6a5f2..545ea0e 100644
--- a/jira_integration.go
+++ b/jira_integration.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -20,16 +19,13 @@ func (c *Client) CreateJiraIntegration(ctx context.Context, ji *integration.Jira
 	}
 
 	resp, err := c.doRequest(ctx, "POST", IntegrationAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.JiraIntegration{}
@@ -43,16 +39,13 @@ func (c *Client) CreateJiraIntegration(ctx context.Context, ji *integration.Jira
 // GetJiraIntegration retrieves an Jira integration.
 func (c *Client) GetJiraIntegration(ctx context.Context, id string) (*integration.JiraIntegration, error) {
 	resp, err := c.doRequest(ctx, "GET", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.JiraIntegration{}
@@ -71,16 +64,13 @@ func (c *Client) UpdateJiraIntegration(ctx context.Context, id string, ji *integ
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", IntegrationAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.JiraIntegration{}
@@ -94,16 +84,13 @@ func (c *Client) UpdateJiraIntegration(ctx context.Context, id string, ji *integ
 // DeleteJiraIntegration deletes an Jira integration.
 func (c *Client) DeleteJiraIntegration(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
diff --git a/metric_ruleset.go b/metric_ruleset.go
index fe7f140..91d531d 100644
--- a/metric_ruleset.go
+++ b/metric_ruleset.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -18,16 +17,13 @@ const MetricRulesetApiURL = "/v2/metricruleset"
 // GetMetricRuleset gets a metric ruleset.
 func (c *Client) GetMetricRuleset(ctx context.Context, id string) (*metric_ruleset.GetMetricRulesetResponse, error) {
 	resp, err := c.doRequest(ctx, http.MethodGet, MetricRulesetApiURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	metricRuleset := &metric_ruleset.GetMetricRulesetResponse{}
@@ -53,9 +49,8 @@ func (c *Client) CreateMetricRuleset(ctx context.Context, metricRuleset *metric_
 		return nil, err
 	}
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	createdMetricRuleset := &metric_ruleset.CreateMetricRulesetResponse{}
@@ -73,17 +68,13 @@ func (c *Client) UpdateMetricRuleset(ctx context.Context, id string, metricRules
 	}
 
 	resp, err := c.doRequest(ctx, http.MethodPut, MetricRulesetApiURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
-
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	updatedMetricRuleset := &metric_ruleset.UpdateMetricRulesetResponse{}
@@ -96,17 +87,13 @@ func (c *Client) UpdateMetricRuleset(ctx context.Context, id string, metricRules
 // DeleteMetricRuleset deletes a metric ruleset.
 func (c *Client) DeleteMetricRuleset(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, http.MethodDelete, MetricRulesetApiURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
-
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 
 	io.Copy(ioutil.Discard, resp.Body)
@@ -121,16 +108,13 @@ func (c *Client) GenerateAggregationMetricName(ctx context.Context, generateAggr
 	}
 
 	resp, err := c.doRequest(ctx, http.MethodPost, MetricRulesetApiURL+"/generateAggregationMetricName", nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return "", err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return "", fmt.Errorf("bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return "", err
 	}
 
 	respBody, err := ioutil.ReadAll(resp.Body)
diff --git a/metrics_metadata.go b/metrics_metadata.go
index 341c555..4721b7b 100644
--- a/metrics_metadata.go
+++ b/metrics_metadata.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -29,16 +28,13 @@ const TagAPIURL = "/v2/tag"
 // GetDimension gets a dimension.
 func (c *Client) GetDimension(ctx context.Context, key string, value string) (*metrics_metadata.Dimension, error) {
 	resp, err := c.doRequest(ctx, "GET", DimensionAPIURL+"/"+key+"/"+value, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDimension := &metrics_metadata.Dimension{}
@@ -56,16 +52,13 @@ func (c *Client) UpdateDimension(ctx context.Context, key string, value string,
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", DimensionAPIURL+"/"+key+"/"+value, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDimension := &metrics_metadata.Dimension{}
@@ -87,16 +80,13 @@ func (c *Client) SearchDimension(ctx context.Context, query string, orderBy stri
 	params.Add("offset", strconv.Itoa(offset))
 
 	resp, err := c.doRequest(ctx, "GET", DimensionAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalDimensions := &metrics_metadata.DimensionQueryResponseModel{}
@@ -118,16 +108,13 @@ func (c *Client) SearchMetric(ctx context.Context, query string, orderBy string,
 	params.Add("offset", strconv.Itoa(offset))
 
 	resp, err := c.doRequest(ctx, "GET", MetricAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalMetrics := &metrics_metadata.RetrieveMetricMetadataResponseModel{}
@@ -141,16 +128,13 @@ func (c *Client) SearchMetric(ctx context.Context, query string, orderBy string,
 // GetMetric retrieves a single metric by name.
 func (c *Client) GetMetric(ctx context.Context, name string) (*metrics_metadata.Metric, error) {
 	resp, err := c.doRequest(ctx, "GET", MetricAPIURL+"/"+name, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalMetric := &metrics_metadata.Metric{}
@@ -169,16 +153,13 @@ func (c *Client) CreateUpdateMetric(ctx context.Context, name string, cumr *metr
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", MetricAPIURL+"/"+name, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalMetric := &metrics_metadata.Metric{}
@@ -192,16 +173,13 @@ func (c *Client) CreateUpdateMetric(ctx context.Context, name string, cumr *metr
 // GetMetricTimeSeries retrieves a metric time series by id.
 func (c *Client) GetMetricTimeSeries(ctx context.Context, id string) (*metrics_metadata.MetricTimeSeries, error) {
 	resp, err := c.doRequest(ctx, "GET", MetricTimeSeriesAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalMetricTimeSeries := &metrics_metadata.MetricTimeSeries{}
@@ -223,16 +201,13 @@ func (c *Client) SearchMetricTimeSeries(ctx context.Context, query string, order
 	params.Add("offset", strconv.Itoa(offset))
 
 	resp, err := c.doRequest(ctx, "GET", MetricTimeSeriesAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalMTS := &metrics_metadata.MetricTimeSeriesRetrieveResponseModel{}
@@ -254,16 +229,13 @@ func (c *Client) SearchTag(ctx context.Context, query string, orderBy string, li
 	params.Add("offset", strconv.Itoa(offset))
 
 	resp, err := c.doRequest(ctx, "GET", TagAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalTags := &metrics_metadata.TagRetrieveResponseModel{}
@@ -277,16 +249,13 @@ func (c *Client) SearchTag(ctx context.Context, query string, orderBy string, li
 // GetTag gets a tag by name
 func (c *Client) GetTag(ctx context.Context, name string) (*metrics_metadata.Tag, error) {
 	resp, err := c.doRequest(ctx, "GET", TagAPIURL+"/"+name, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalTag := &metrics_metadata.Tag{}
@@ -300,16 +269,13 @@ func (c *Client) GetTag(ctx context.Context, name string) (*metrics_metadata.Tag
 // DeleteTag deletes a tag.
 func (c *Client) DeleteTag(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", TagAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
@@ -324,16 +290,13 @@ func (c *Client) CreateUpdateTag(ctx context.Context, name string, cutr *metrics
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", TagAPIURL+"/"+name, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalTag := &metrics_metadata.Tag{}
diff --git a/opsgenie_integration.go b/opsgenie_integration.go
index b1f8279..579acc7 100644
--- a/opsgenie_integration.go
+++ b/opsgenie_integration.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -20,16 +19,13 @@ func (c *Client) CreateOpsgenieIntegration(ctx context.Context, oi *integration.
 	}
 
 	resp, err := c.doRequest(ctx, "POST", IntegrationAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.OpsgenieIntegration{}
@@ -43,16 +39,13 @@ func (c *Client) CreateOpsgenieIntegration(ctx context.Context, oi *integration.
 // GetOpsgenieIntegration retrieves an Opsgenie integration.
 func (c *Client) GetOpsgenieIntegration(ctx context.Context, id string) (*integration.OpsgenieIntegration, error) {
 	resp, err := c.doRequest(ctx, "GET", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.OpsgenieIntegration{}
@@ -71,16 +64,13 @@ func (c *Client) UpdateOpsgenieIntegration(ctx context.Context, id string, oi *i
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", IntegrationAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.OpsgenieIntegration{}
@@ -94,17 +84,15 @@ func (c *Client) UpdateOpsgenieIntegration(ctx context.Context, id string, oi *i
 // DeleteOpsgenieIntegration deletes an Opsgenie integration.
 func (c *Client) DeleteOpsgenieIntegration(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
+
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
 	return err
diff --git a/organization.go b/organization.go
index 0ef475c..e6945cf 100644
--- a/organization.go
+++ b/organization.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -22,16 +21,13 @@ const OrganizationMembersAPIURL = "/v2/organization/members"
 // GetOrganization gets an organization.
 func (c *Client) GetOrganization(ctx context.Context, id string) (*organization.Organization, error) {
 	resp, err := c.doRequest(ctx, "GET", OrganizationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalOrganization := &organization.Organization{}
@@ -45,16 +41,13 @@ func (c *Client) GetOrganization(ctx context.Context, id string) (*organization.
 // GetMember gets a member.
 func (c *Client) GetMember(ctx context.Context, id string) (*organization.Member, error) {
 	resp, err := c.doRequest(ctx, "GET", OrganizationMemberAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalMember := &organization.Member{}
@@ -68,16 +61,13 @@ func (c *Client) GetMember(ctx context.Context, id string) (*organization.Member
 // DeleteMember deletes a detector.
 func (c *Client) DeleteMember(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", OrganizationMemberAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
@@ -92,16 +82,13 @@ func (c *Client) InviteMember(ctx context.Context, inviteRequest *organization.C
 	}
 
 	resp, err := c.doRequest(ctx, "POST", OrganizationMemberAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalMember := &organization.Member{}
@@ -120,16 +107,13 @@ func (c *Client) UpdateMember(ctx context.Context, id string, updateRequest *org
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", OrganizationMemberAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalMember := &organization.Member{}
@@ -148,16 +132,13 @@ func (c *Client) InviteMembers(ctx context.Context, inviteRequest *organization.
 	}
 
 	resp, err := c.doRequest(ctx, "POST", OrganizationMembersAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalMembers := &organization.InviteMembersRequest{}
@@ -177,16 +158,13 @@ func (c *Client) GetOrganizationMembers(ctx context.Context, limit int, query st
 	params.Add("orderBy", orderBy)
 
 	resp, err := c.doRequest(ctx, "GET", OrganizationMemberAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalMembers := &organization.MemberSearchResults{}
diff --git a/orgtoken.go b/orgtoken.go
index 0af0c83..4377047 100644
--- a/orgtoken.go
+++ b/orgtoken.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -25,16 +24,13 @@ func (c *Client) CreateOrgToken(ctx context.Context, tokenRequest *orgtoken.Crea
 	}
 
 	resp, err := c.doRequest(ctx, "POST", TokenAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalToken := &orgtoken.Token{}
@@ -49,16 +45,13 @@ func (c *Client) CreateOrgToken(ctx context.Context, tokenRequest *orgtoken.Crea
 func (c *Client) DeleteOrgToken(ctx context.Context, name string) error {
 	encodedName := url.PathEscape(name)
 	resp, err := c.doRequest(ctx, "DELETE", TokenAPIURL+"/"+encodedName, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
@@ -69,16 +62,13 @@ func (c *Client) DeleteOrgToken(ctx context.Context, name string) error {
 func (c *Client) GetOrgToken(ctx context.Context, id string) (*orgtoken.Token, error) {
 	encodedName := url.PathEscape(id)
 	resp, err := c.doRequest(ctx, "GET", TokenAPIURL+"/"+encodedName, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalToken := &orgtoken.Token{}
@@ -98,16 +88,13 @@ func (c *Client) UpdateOrgToken(ctx context.Context, id string, tokenRequest *or
 
 	encodedName := url.PathEscape(id)
 	resp, err := c.doRequest(ctx, "PUT", TokenAPIURL+"/"+encodedName, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalToken := &orgtoken.Token{}
@@ -126,16 +113,13 @@ func (c *Client) SearchOrgTokens(ctx context.Context, limit int, name string, of
 	params.Add("offset", strconv.Itoa(offset))
 
 	resp, err := c.doRequest(ctx, "GET", TokenAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalTokens := &orgtoken.SearchResults{}
diff --git a/pagerduty_integration.go b/pagerduty_integration.go
index 8616d64..7f9b139 100644
--- a/pagerduty_integration.go
+++ b/pagerduty_integration.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -21,16 +20,13 @@ func (c *Client) CreatePagerDutyIntegration(ctx context.Context, pdi *integratio
 	}
 
 	resp, err := c.doRequest(ctx, "POST", IntegrationAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.PagerDutyIntegration{}
@@ -44,16 +40,13 @@ func (c *Client) CreatePagerDutyIntegration(ctx context.Context, pdi *integratio
 // GetPagerDutyIntegration retrieves a PagerDuty integration.
 func (c *Client) GetPagerDutyIntegration(ctx context.Context, id string) (*integration.PagerDutyIntegration, error) {
 	resp, err := c.doRequest(ctx, "GET", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.PagerDutyIntegration{}
@@ -71,16 +64,13 @@ func (c *Client) GetPagerDutyIntegrationByName(ctx context.Context, name string)
 	params.Add("name", name)
 
 	resp, err := c.doRequest(ctx, "GET", IntegrationAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	integrationList := integration.PagerDutyIntegrationList{}
@@ -109,16 +99,13 @@ func (c *Client) UpdatePagerDutyIntegration(ctx context.Context, id string, pdi
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", IntegrationAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.PagerDutyIntegration{}
@@ -132,16 +119,13 @@ func (c *Client) UpdatePagerDutyIntegration(ctx context.Context, id string, pdi
 // DeletePagerDutyIntegration deletes a PagerDuty integration.
 func (c *Client) DeletePagerDutyIntegration(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
diff --git a/sessiontoken.go b/sessiontoken.go
index 55e02a2..f42d9f8 100644
--- a/sessiontoken.go
+++ b/sessiontoken.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -25,16 +24,13 @@ func (c *Client) CreateSessionToken(ctx context.Context, tokenRequest *sessionto
 	// we need to explicitly pass an empty token (which means it wont get set in the header)
 	// the API accepts either no token or a valid token, but not an empty token.
 	resp, err := c.doRequestWithToken(ctx, "POST", SessionTokenAPIURL, nil, bytes.NewReader(payload), "")
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	sessionToken := &sessiontoken.Token{}
@@ -48,16 +44,13 @@ func (c *Client) CreateSessionToken(ctx context.Context, tokenRequest *sessionto
 // DeleteOrgToken deletes a token.
 func (c *Client) DeleteSessionToken(ctx context.Context, token string) error {
 	resp, err := c.doRequestWithToken(ctx, "DELETE", SessionTokenAPIURL, nil, nil, token)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
diff --git a/slack_integration.go b/slack_integration.go
index c165280..332e731 100644
--- a/slack_integration.go
+++ b/slack_integration.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -20,16 +19,13 @@ func (c *Client) CreateSlackIntegration(ctx context.Context, si *integration.Sla
 	}
 
 	resp, err := c.doRequest(ctx, "POST", IntegrationAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.SlackIntegration{}
@@ -43,16 +39,13 @@ func (c *Client) CreateSlackIntegration(ctx context.Context, si *integration.Sla
 // GetSlackIntegration retrieves a Slack integration.
 func (c *Client) GetSlackIntegration(ctx context.Context, id string) (*integration.SlackIntegration, error) {
 	resp, err := c.doRequest(ctx, "GET", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.SlackIntegration{}
@@ -71,16 +64,13 @@ func (c *Client) UpdateSlackIntegration(ctx context.Context, id string, si *inte
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", IntegrationAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.SlackIntegration{}
@@ -94,16 +84,13 @@ func (c *Client) UpdateSlackIntegration(ctx context.Context, id string, si *inte
 // DeleteSlackIntegration deletes a Slack integration.
 func (c *Client) DeleteSlackIntegration(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
diff --git a/slo.go b/slo.go
index 1f763ef..e90bec9 100644
--- a/slo.go
+++ b/slo.go
@@ -4,10 +4,10 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
-	"github.com/signalfx/signalfx-go/slo"
 	"io"
 	"net/http"
+
+	"github.com/signalfx/signalfx-go/slo"
 )
 
 const SloAPIURL = "/v2/slo"
@@ -47,17 +47,13 @@ func (c *Client) executeSloRequest(ctx context.Context, url string, method strin
 	}
 
 	resp, err := c.doRequest(ctx, method, url, nil, body)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
-
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != expectedValidStatus {
-		message, _ := io.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, expectedValidStatus); err != nil {
+		return nil, err
 	}
 
 	if resp.Body != nil {
diff --git a/team.go b/team.go
index e8adcb7..9cd44dd 100644
--- a/team.go
+++ b/team.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -26,16 +25,13 @@ func (c *Client) CreateTeam(ctx context.Context, t *team.CreateUpdateTeamRequest
 	}
 
 	resp, err := c.doRequest(ctx, "POST", TeamAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalTeam := &team.Team{}
@@ -49,15 +45,13 @@ func (c *Client) CreateTeam(ctx context.Context, t *team.CreateUpdateTeamRequest
 // DeleteTeam deletes a team.
 func (c *Client) DeleteTeam(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", TeamAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		return errors.New("Unexpected status code: " + resp.Status)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
@@ -67,15 +61,13 @@ func (c *Client) DeleteTeam(ctx context.Context, id string) error {
 // GetTeam gets a team.
 func (c *Client) GetTeam(ctx context.Context, id string) (*team.Team, error) {
 	resp, err := c.doRequest(ctx, "GET", TeamAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	defer resp.Body.Close()
+
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalTeam := &team.Team{}
@@ -94,15 +86,13 @@ func (c *Client) UpdateTeam(ctx context.Context, id string, t *team.CreateUpdate
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", TeamAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	defer resp.Body.Close()
+
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalTeam := &team.Team{}
@@ -122,16 +112,13 @@ func (c *Client) SearchTeam(ctx context.Context, limit int, name string, offset
 	params.Add("tags", tags)
 
 	resp, err := c.doRequest(ctx, "GET", TeamAPIURL, params, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalTeams := &team.SearchResults{}
@@ -147,16 +134,13 @@ func (c *Client) LinkDetectorToTeam(ctx context.Context, id string, detectorID s
 	targetURL := fmt.Sprintf("%s/%s/detector/%s", TeamAPIURL, id, detectorID)
 	resp, err := c.doRequest(ctx, "POST", targetURL, nil, nil)
 
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 
 	return nil
@@ -167,16 +151,13 @@ func (c *Client) UnlinkDetectorFromTeam(ctx context.Context, id string, detector
 	targetURL := fmt.Sprintf("%s/%s/detector/%s", TeamAPIURL, id, detectorID)
 	resp, err := c.doRequest(ctx, "DELETE", targetURL, nil, nil)
 
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 
 	return nil
@@ -186,17 +167,13 @@ func (c *Client) UnlinkDetectorFromTeam(ctx context.Context, id string, detector
 func (c *Client) LinkDashboardGroupToTeam(ctx context.Context, id string, dashboardGroupID string) error {
 	targetURL := fmt.Sprintf("%s/%s/dashboardgroup/%s", TeamAPIURL, id, dashboardGroupID)
 	resp, err := c.doRequest(ctx, "POST", targetURL, nil, nil)
-
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 
 	return nil
@@ -207,16 +184,13 @@ func (c *Client) UnlinkDashboardGroupFromTeam(ctx context.Context, id string, da
 	targetURL := fmt.Sprintf("%s/%s/dashboardgroup/%s", TeamAPIURL, id, dashboardGroupID)
 	resp, err := c.doRequest(ctx, "DELETE", targetURL, nil, nil)
 
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 
 	return nil
diff --git a/victor_ops_integration.go b/victor_ops_integration.go
index 76ae13e..9d1987c 100644
--- a/victor_ops_integration.go
+++ b/victor_ops_integration.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -20,16 +19,13 @@ func (c *Client) CreateVictorOpsIntegration(ctx context.Context, oi *integration
 	}
 
 	resp, err := c.doRequest(ctx, "POST", IntegrationAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.VictorOpsIntegration{}
@@ -43,16 +39,13 @@ func (c *Client) CreateVictorOpsIntegration(ctx context.Context, oi *integration
 // GetVictorOpsIntegration retrieves an VictorOps integration.
 func (c *Client) GetVictorOpsIntegration(ctx context.Context, id string) (*integration.VictorOpsIntegration, error) {
 	resp, err := c.doRequest(ctx, "GET", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.VictorOpsIntegration{}
@@ -71,16 +64,13 @@ func (c *Client) UpdateVictorOpsIntegration(ctx context.Context, id string, oi *
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", IntegrationAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.VictorOpsIntegration{}
@@ -94,16 +84,13 @@ func (c *Client) UpdateVictorOpsIntegration(ctx context.Context, id string, oi *
 // DeleteVictorOpsIntegration deletes an VictorOps integration.
 func (c *Client) DeleteVictorOpsIntegration(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)
 
diff --git a/webhook_integration.go b/webhook_integration.go
index 8fbb250..84876a5 100644
--- a/webhook_integration.go
+++ b/webhook_integration.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -20,16 +19,13 @@ func (c *Client) CreateWebhookIntegration(ctx context.Context, oi *integration.W
 	}
 
 	resp, err := c.doRequest(ctx, "POST", IntegrationAPIURL, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.WebhookIntegration{}
@@ -43,16 +39,13 @@ func (c *Client) CreateWebhookIntegration(ctx context.Context, oi *integration.W
 // GetWebhookIntegration retrieves an Webhook integration.
 func (c *Client) GetWebhookIntegration(ctx context.Context, id string) (*integration.WebhookIntegration, error) {
 	resp, err := c.doRequest(ctx, "GET", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.WebhookIntegration{}
@@ -71,16 +64,13 @@ func (c *Client) UpdateWebhookIntegration(ctx context.Context, id string, oi *in
 	}
 
 	resp, err := c.doRequest(ctx, "PUT", IntegrationAPIURL+"/"+id, nil, bytes.NewReader(payload))
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return nil, fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusOK); err != nil {
+		return nil, err
 	}
 
 	finalIntegration := integration.WebhookIntegration{}
@@ -94,16 +84,13 @@ func (c *Client) UpdateWebhookIntegration(ctx context.Context, id string, oi *in
 // DeleteWebhookIntegration deletes an Webhook integration.
 func (c *Client) DeleteWebhookIntegration(ctx context.Context, id string) error {
 	resp, err := c.doRequest(ctx, "DELETE", IntegrationAPIURL+"/"+id, nil, nil)
-	if resp != nil {
-		defer resp.Body.Close()
-	}
 	if err != nil {
 		return err
 	}
+	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusNoContent {
-		message, _ := ioutil.ReadAll(resp.Body)
-		return fmt.Errorf("Unexpected status code: %d: %s", resp.StatusCode, message)
+	if err = newResponseError(resp, http.StatusNoContent); err != nil {
+		return err
 	}
 	_, _ = io.Copy(ioutil.Discard, resp.Body)