Repository: PagerDuty/go-pagerduty
Pull request #312 (2021-03-11 20:26:07)

teams and services analytics endpoints
Add aggregated analytics endpoints for Teams and Services

https://developer.pagerduty.com/api-reference/reference/REST/openapiv3.json/paths/~1analytics~1metrics~1incidents~1services/post

https://developer.pagerduty.com/api-reference/reference/REST/openapiv3.json/paths/~1analytics~1metrics~1incidents~1teams/post


Patch:
diff --git a/analytics.go b/analytics.go
index 95cb70c..8cd1322 100644
--- a/analytics.go
+++ b/analytics.go
@@ -4,18 +4,24 @@ import (
 	"context"
 )
 
+// AnalyticsRequest represents the request to be sent to PagerDuty when you want
+// aggregated analytics.
 type AnalyticsRequest struct {
-	AnalyticsFilter *AnalyticsFilter `json:"filters,omitempty"`
-	AggregateUnit   string           `json:"aggregate_unit,omitempty"`
-	TimeZone        string           `json:"time_zone,omitempty"`
+	Filters       *AnalyticsFilter `json:"filters,omitempty"`
+	AggregateUnit string           `json:"aggregate_unit,omitempty"`
+	TimeZone      string           `json:"time_zone,omitempty"`
 }
+
+// AnalyticsResponse represents the response from the PagerDuty API.
 type AnalyticsResponse struct {
-	Data            []AnalyticsData  `json:"data,omitempty"`
-	AnalyticsFilter *AnalyticsFilter `json:"filters,omitempty"`
-	AggregateUnit   string           `json:"aggregate_unit,omitempty"`
-	TimeZone        string           `json:"time_zone,omitempty"`
+	Data          []AnalyticsData  `json:"data,omitempty"`
+	Filters       *AnalyticsFilter `json:"filters,omitempty"`
+	AggregateUnit string           `json:"aggregate_unit,omitempty"`
+	TimeZone      string           `json:"time_zone,omitempty"`
 }
 
+// AnalyticsFilter represents the set of filters as part of the request to PagerDuty when
+// requesting analytics.
 type AnalyticsFilter struct {
 	CreatedAtStart string   `json:"created_at_start,omitempty"`
 	CreatedAtEnd   string   `json:"created_at_end,omitempty"`
@@ -24,42 +30,87 @@ type AnalyticsFilter struct {
 	ServiceIDs     []string `json:"service_ids,omitempty"`
 	TeamIDs        []string `json:"team_ids,omitempty"`
 	PriorityIDs    []string `json:"priority_ids,omitempty"`
-	PriorityName   []string `json:"priority_name,omitempty"`
+	PriorityNames  []string `json:"priority_names,omitempty"`
 }
 
+// AnalyticsData represents the structure of the analytics we have available.
 type AnalyticsData struct {
-	ServiceID                      string `json:"service_id,omitempty"`
-	ServiceName                    string `json:"service_name,omitempty"`
-	TeamID                         string `json:"team_id,omitempty"`
-	TeamName                       string `json:"team_name,omitempty"`
-	MeanSecondsToResolve           int    `json:"mean_seconds_to_resolve,omitempty"`
-	MeanSecondsToFirstAck          int    `json:"mean_seconds_to_first_ack,omitempty"`
-	MeanSecondsToEngage            int    `json:"mean_seconds_to_engage,omitempty"`
-	MeanSecondsToMobilize          int    `json:"mean_seconds_to_mobilize,omitempty"`
-	MeanEngagedSeconds             int    `json:"mean_engaged_seconds,omitempty"`
-	MeanEngagedUserCount           int    `json:"mean_engaged_user_count,omitempty"`
-	TotalEscalationCount           int    `json:"total_escalation_count,omitempty"`
-	MeanAssignmentCount            int    `json:"mean_assignment_count,omitempty"`
-	TotalBusinessHourInterruptions int    `json:"total_business_hour_interruptions,omitempty"`
-	TotalSleepHourInterruptions    int    `json:"total_sleep_hour_interruptions,omitempty"`
-	TotalOffHourInterruptions      int    `json:"total_off_hour_interruptions,omitempty"`
-	TotalSnoozedSeconds            int    `json:"total_snoozed_seconds,omitempty"`
-	TotalEngagedSeconds            int    `json:"total_engaged_seconds,omitempty"`
-	TotalIncidentCount             int    `json:"total_incident_count,omitempty"`
-	UpTimePct                      int    `json:"up_time_pct,omitempty"`
-	UserDefinedEffortSeconds       int    `json:"user_defined_effort_seconds,omitempty"`
-	RangeStart                     string `json:"range_start,omitempty"`
+	ServiceID                      string  `json:"service_id,omitempty"`
+	ServiceName                    string  `json:"service_name,omitempty"`
+	TeamID                         string  `json:"team_id,omitempty"`
+	TeamName                       string  `json:"team_name,omitempty"`
+	MeanSecondsToResolve           int     `json:"mean_seconds_to_resolve,omitempty"`
+	MeanSecondsToFirstAck          int     `json:"mean_seconds_to_first_ack,omitempty"`
+	MeanSecondsToEngage            int     `json:"mean_seconds_to_engage,omitempty"`
+	MeanSecondsToMobilize          int     `json:"mean_seconds_to_mobilize,omitempty"`
+	MeanEngagedSeconds             int     `json:"mean_engaged_seconds,omitempty"`
+	MeanEngagedUserCount           int     `json:"mean_engaged_user_count,omitempty"`
+	TotalEscalationCount           int     `json:"total_escalation_count,omitempty"`
+	MeanAssignmentCount            int     `json:"mean_assignment_count,omitempty"`
+	TotalBusinessHourInterruptions int     `json:"total_business_hour_interruptions,omitempty"`
+	TotalSleepHourInterruptions    int     `json:"total_sleep_hour_interruptions,omitempty"`
+	TotalOffHourInterruptions      int     `json:"total_off_hour_interruptions,omitempty"`
+	TotalSnoozedSeconds            int     `json:"total_snoozed_seconds,omitempty"`
+	TotalEngagedSeconds            int     `json:"total_engaged_seconds,omitempty"`
+	TotalIncidentCount             int     `json:"total_incident_count,omitempty"`
+	UpTimePct                      float32 `json:"up_time_pct,omitempty"`
+	UserDefinedEffortSeconds       int     `json:"user_defined_effort_seconds,omitempty"`
+	RangeStart                     string  `json:"range_start,omitempty"`
 }
 
+// GetAggregatedIncidentData gets the aggregated incident analytics for the requested data.
 func (c *Client) GetAggregatedIncidentData(ctx context.Context, analytics AnalyticsRequest) (AnalyticsResponse, error) {
+	h := map[string]string{
+		"X-EARLY-ACCESS": "analytics-v2",
+	}
+
+	resp, err := c.post(ctx, "/analytics/metrics/incidents/all", analytics, h)
+	if err != nil {
+		return AnalyticsResponse{}, err
+	}
+
 	var analyticsResponse AnalyticsResponse
-	headers := make(map[string]string)
-	headers["X-EARLY-ACCESS"] = "analytics-v2"
+	if err = c.decodeJSON(resp, &analyticsResponse); err != nil {
+		return AnalyticsResponse{}, err
+	}
 
-	resp, err := c.post(ctx, "/analytics/metrics/incidents/all", analytics, headers)
+	return analyticsResponse, nil
+}
+
+// GetAggregatedServiceData gets the aggregated service analytics for the requested data.
+func (c *Client) GetAggregatedServiceData(ctx context.Context, analytics AnalyticsRequest) (AnalyticsResponse, error) {
+	h := map[string]string{
+		"X-EARLY-ACCESS": "analytics-v2",
+	}
+
+	resp, err := c.post(ctx, "/analytics/metrics/incidents/services", analytics, h)
 	if err != nil {
-		return analyticsResponse, err
+		return AnalyticsResponse{}, err
 	}
-	err = c.decodeJSON(resp, &analyticsResponse)
-	return analyticsResponse, err
+
+	var analyticsResponse AnalyticsResponse
+	if err = c.decodeJSON(resp, &analyticsResponse); err != nil {
+		return AnalyticsResponse{}, err
+	}
+
+	return analyticsResponse, nil
+}
+
+// GetAggregatedTeamData gets the aggregated team analytics for the requested data.
+func (c *Client) GetAggregatedTeamData(ctx context.Context, analytics AnalyticsRequest) (AnalyticsResponse, error) {
+	h := map[string]string{
+		"X-EARLY-ACCESS": "analytics-v2",
+	}
+
+	resp, err := c.post(ctx, "/analytics/metrics/incidents/teams", analytics, h)
+	if err != nil {
+		return AnalyticsResponse{}, err
+	}
+
+	var analyticsResponse AnalyticsResponse
+	if err = c.decodeJSON(resp, &analyticsResponse); err != nil {
+		return AnalyticsResponse{}, err
+	}
+
+	return analyticsResponse, nil
 }
diff --git a/command/analytics_show.go b/command/analytics_incident_show.go
similarity index 79%
rename from command/analytics_show.go
rename to command/analytics_incident_show.go
index 6170fea..4df116f 100644
--- a/command/analytics_show.go
+++ b/command/analytics_incident_show.go
@@ -4,24 +4,27 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"strings"
+	"time"
+
 	"github.com/PagerDuty/go-pagerduty"
 	"github.com/mitchellh/cli"
 	log "github.com/sirupsen/logrus"
-	"strings"
-	"time"
 )
 
 type AnalyticsShow struct {
 	Meta
 }
 
+// AnalyticsGetAggregatedIncidentDataCommand gets the aggregated incident analytics for the requested data.
 func AnalyticsGetAggregatedIncidentDataCommand() (cli.Command, error) {
 	return &AnalyticsShow{}, nil
 }
 
+// Help displays information on how to use the analytics incident cli command.
 func (c *AnalyticsShow) Help() string {
 	helpText := `
-	analytics show
+	analytics incident show
 
 	Options:
 
@@ -33,12 +36,14 @@ func (c *AnalyticsShow) Help() string {
 	return strings.TrimSpace(helpText)
 }
 
+// Synopsis returns a synopsis of the analytics incident cli command.
 func (c *AnalyticsShow) Synopsis() string {
-	return "Get analytics aggregated incident data"
+	return "Get aggregated incident data analytics"
 }
 
+//Run executes analytics cli command and displays incident analytics for the requested data.
 func (c *AnalyticsShow) Run(args []string) int {
-	flags := c.Meta.FlagSet("analytics show")
+	flags := c.Meta.FlagSet("analytics incident show")
 	flags.Usage = func() { fmt.Println(c.Help()) }
 	servID := flags.String("service_id", "", "Service ID")
 	now := time.Now()
@@ -48,7 +53,6 @@ func (c *AnalyticsShow) Run(args []string) int {
 	urgency := flags.String("urgency", "", "high|low")
 	teamID := flags.String("team_id", "", "team ID")
 
-	//log.SetLevel(log.DebugLevel)
 	if err := flags.Parse(args); err != nil {
 		log.Errorln(err)
 		return -1
@@ -84,9 +88,9 @@ func (c *AnalyticsShow) Run(args []string) int {
 	}
 
 	analytics := pagerduty.AnalyticsRequest{
-		AnalyticsFilter: &analyticsFilter,
-		AggregateUnit:   "day",
-		TimeZone:        "Etc/UTC",
+		Filters:       &analyticsFilter,
+		AggregateUnit: "day",
+		TimeZone:      "Etc/UTC",
 	}
 
 	aggregatedIncidentData, err := client.GetAggregatedIncidentData(context.Background(), analytics)
diff --git a/command/analytics_service_show.go b/command/analytics_service_show.go
new file mode 100644
index 0000000..8cf46a4
--- /dev/null
+++ b/command/analytics_service_show.go
@@ -0,0 +1,107 @@
+package main
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"strings"
+	"time"
+
+	"github.com/PagerDuty/go-pagerduty"
+	"github.com/mitchellh/cli"
+	log "github.com/sirupsen/logrus"
+)
+
+type AnalyticsServiceShow struct {
+	Meta
+}
+
+// AnalyticsGetAggregatedServiceDataCommand gets the aggregated service analytics for the requested data.
+func AnalyticsGetAggregatedServiceDataCommand() (cli.Command, error) {
+	return &AnalyticsServiceShow{}, nil
+}
+
+// Help displays information on how to use the analytics service cli command.
+func (c *AnalyticsServiceShow) Help() string {
+	helpText := `
+	analytics service show
+	Options:
+		 -(service_id|team_id) #MANDATORY provide service or team id to stats on.
+		 -start #Optional RFC3339 format default : 7 days ago
+		 -end #Optional RFC3339 format default : now
+		 -urgency #Optional (high|low)
+	` + c.Meta.Help()
+	return strings.TrimSpace(helpText)
+}
+
+// Synopsis returns a synopsis of the analytics service cli command.
+func (c *AnalyticsServiceShow) Synopsis() string {
+	return "Get aggregated service data analytics"
+}
+
+//Run executes analytics cli command and displays service analytics for the requested data.
+func (c *AnalyticsServiceShow) Run(args []string) int {
+	flags := c.Meta.FlagSet("analytics service show")
+	flags.Usage = func() { fmt.Println(c.Help()) }
+	servID := flags.String("service_id", "", "Service ID")
+	now := time.Now()
+	sevenDaysAgo := now.Add(time.Duration(-24*7) * time.Hour)
+	start := flags.String("start", sevenDaysAgo.Format(time.RFC3339), "start date")
+	end := flags.String("end", now.Format(time.RFC3339), "end date")
+	urgency := flags.String("urgency", "", "high|low")
+	teamID := flags.String("team_id", "", "team ID")
+
+	if err := flags.Parse(args); err != nil {
+		log.Errorln(err)
+		return -1
+	}
+
+	if err := c.Meta.Setup(); err != nil {
+		log.Error(err)
+		return -1
+	}
+
+	client := c.Meta.Client()
+
+	serviceIds := make([]string, 1)
+	if *servID == "" {
+		serviceIds = nil
+	} else {
+		serviceIds[0] = *servID
+	}
+
+	teamIds := make([]string, 1)
+	if *teamID == "" {
+		teamIds = nil
+	} else {
+		teamIds[0] = *teamID
+	}
+
+	analyticsFilter := pagerduty.AnalyticsFilter{
+		CreatedAtStart: *start,
+		CreatedAtEnd:   *end,
+		Urgency:        *urgency,
+		ServiceIDs:     serviceIds,
+		TeamIDs:        teamIds,
+	}
+
+	analytics := pagerduty.AnalyticsRequest{
+		Filters:       &analyticsFilter,
+		AggregateUnit: "day",
+		TimeZone:      "Etc/UTC",
+	}
+
+	aggregatedServiceData, err := client.GetAggregatedServiceData(context.Background(), analytics)
+	if err != nil {
+		log.Error(err)
+		return -1
+	}
+
+	aggregatedServiceDataBytes, err := json.Marshal(aggregatedServiceData)
+	if err != nil {
+		log.Error(err)
+		return -1
+	}
+	fmt.Println(string(aggregatedServiceDataBytes))
+	return 0
+}
diff --git a/command/analytics_team_show.go b/command/analytics_team_show.go
new file mode 100644
index 0000000..def6895
--- /dev/null
+++ b/command/analytics_team_show.go
@@ -0,0 +1,107 @@
+package main
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"strings"
+	"time"
+
+	"github.com/PagerDuty/go-pagerduty"
+	"github.com/mitchellh/cli"
+	log "github.com/sirupsen/logrus"
+)
+
+type AnalyticsTeamShow struct {
+	Meta
+}
+
+// AnalyticsGetAggregatedTeamDataCommand gets the aggregated team analytics for the requested data.
+func AnalyticsGetAggregatedTeamDataCommand() (cli.Command, error) {
+	return &AnalyticsServiceShow{}, nil
+}
+
+// Help displays information on how to use the analytics team cli command.
+func (c *AnalyticsTeamShow) Help() string {
+	helpText := `
+	analytics team show
+	Options:
+		 -(service_id|team_id) #MANDATORY provide service or team id to stats on.
+		 -start #Optional RFC3339 format default : 7 days ago
+		 -end #Optional RFC3339 format default : now
+		 -urgency #Optional (high|low)
+	` + c.Meta.Help()
+	return strings.TrimSpace(helpText)
+}
+
+// Synopsis returns a synopsis of the analytics team cli command.
+func (c *AnalyticsTeamShow) Synopsis() string {
+	return "Get aggregated team data analytics"
+}
+
+//Run executes analytics cli command and displays team analytics for the requested data.
+func (c *AnalyticsTeamShow) Run(args []string) int {
+	flags := c.Meta.FlagSet("analytics team show")
+	flags.Usage = func() { fmt.Println(c.Help()) }
+	servID := flags.String("service_id", "", "Service ID")
+	now := time.Now()
+	sevenDaysAgo := now.Add(time.Duration(-24*7) * time.Hour)
+	start := flags.String("start", sevenDaysAgo.Format(time.RFC3339), "start date")
+	end := flags.String("end", now.Format(time.RFC3339), "end date")
+	urgency := flags.String("urgency", "", "high|low")
+	teamID := flags.String("team_id", "", "team ID")
+
+	if err := flags.Parse(args); err != nil {
+		log.Errorln(err)
+		return -1
+	}
+
+	if err := c.Meta.Setup(); err != nil {
+		log.Error(err)
+		return -1
+	}
+
+	client := c.Meta.Client()
+
+	serviceIds := make([]string, 1)
+	if *servID == "" {
+		serviceIds = nil
+	} else {
+		serviceIds[0] = *servID
+	}
+
+	teamIds := make([]string, 1)
+	if *teamID == "" {
+		teamIds = nil
+	} else {
+		teamIds[0] = *teamID
+	}
+
+	analyticsFilter := pagerduty.AnalyticsFilter{
+		CreatedAtStart: *start,
+		CreatedAtEnd:   *end,
+		Urgency:        *urgency,
+		ServiceIDs:     serviceIds,
+		TeamIDs:        teamIds,
+	}
+
+	analytics := pagerduty.AnalyticsRequest{
+		Filters:       &analyticsFilter,
+		AggregateUnit: "day",
+		TimeZone:      "Etc/UTC",
+	}
+
+	aggregatedTeamData, err := client.GetAggregatedTeamData(context.Background(), analytics)
+	if err != nil {
+		log.Error(err)
+		return -1
+	}
+
+	aggregatedTeamDataBytes, err := json.Marshal(aggregatedTeamData)
+	if err != nil {
+		log.Error(err)
+		return -1
+	}
+	fmt.Println(string(aggregatedTeamDataBytes))
+	return 0
+}
diff --git a/command/main.go b/command/main.go
index 6d8c57f..27be30a 100644
--- a/command/main.go
+++ b/command/main.go
@@ -101,9 +101,11 @@ func loadCommands() map[string]cli.CommandFactory {
 		"user notification-rule show":   UserNotificationRuleShowCommand,
 		"user notification-rule update": UserNotificationRuleUpdateCommand,
 
-		"vendor list":                          VendorListCommand,
-		"vendor show":                          VendorShowCommand,
-		"analyticsAggregatedIncidentData show": AnalyticsGetAggregatedIncidentDataCommand,
+		"vendor list":             VendorListCommand,
+		"vendor show":             VendorShowCommand,
+		"analytics incident show": AnalyticsGetAggregatedIncidentDataCommand,
+		"analytics service show":  AnalyticsGetAggregatedServiceDataCommand,
+		"analytics team show":     AnalyticsGetAggregatedTeamDataCommand,
 	}
 }
 


Test patch:
diff --git a/analytics_test.go b/analytics_test.go
index 1816211..e19959d 100644
--- a/analytics_test.go
+++ b/analytics_test.go
@@ -12,7 +12,7 @@ func TestAnalytics_GetAggregatedIncidentData(t *testing.T) {
 	defer teardown()
 
 	analyticsRequest := AnalyticsRequest{
-		AnalyticsFilter: &AnalyticsFilter{
+		Filters: &AnalyticsFilter{
 			CreatedAtStart: "2021-01-01T15:00:32Z",
 			CreatedAtEnd:   "2021-01-08T15:00:32Z",
 			TeamIDs:        []string{"PCDYDX0"},
@@ -23,11 +23,12 @@ func TestAnalytics_GetAggregatedIncidentData(t *testing.T) {
 	analyticsDataWanted := AnalyticsData{MeanSecondsToResolve: 34550, MeanSecondsToFirstAck: 70, MeanEngagedSeconds: 502, MeanAssignmentCount: 1, TotalBusinessHourInterruptions: 1, TotalEngagedSeconds: 2514, TotalIncidentCount: 5, RangeStart: "2021-01-06T00:00:00.000000"}
 	analyticsFilterWanted := AnalyticsFilter{CreatedAtStart: "2021-01-06T09:21:41Z", CreatedAtEnd: "2021-01-13T09:21:41Z", TeamIDs: []string{"PCDYDX0"}}
 	analyticsResponse := AnalyticsResponse{
-		Data:            []AnalyticsData{analyticsDataWanted},
-		AnalyticsFilter: &analyticsFilterWanted,
-		AggregateUnit:   "day",
-		TimeZone:        "Etc/UTC",
+		Data:          []AnalyticsData{analyticsDataWanted},
+		Filters:       &analyticsFilterWanted,
+		AggregateUnit: "day",
+		TimeZone:      "Etc/UTC",
 	}
+
 	bytesAnalyticsResponse, err := json.Marshal(analyticsResponse)
 	mux.HandleFunc("/analytics/metrics/incidents/all", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "POST")
@@ -41,10 +42,100 @@ func TestAnalytics_GetAggregatedIncidentData(t *testing.T) {
 
 	res, err := client.GetAggregatedIncidentData(context.Background(), analyticsRequest)
 	want := AnalyticsResponse{
-		Data:            []AnalyticsData{analyticsDataWanted},
-		AnalyticsFilter: &analyticsFilterWanted,
-		AggregateUnit:   "day",
-		TimeZone:        "Etc/UTC",
+		Data:          []AnalyticsData{analyticsDataWanted},
+		Filters:       &analyticsFilterWanted,
+		AggregateUnit: "day",
+		TimeZone:      "Etc/UTC",
+	}
+	if err != nil {
+		t.Fatal(err)
+	}
+	testEqual(t, want, res)
+}
+
+func TestAnalytics_GetAggregatedServiceData(t *testing.T) {
+	setup()
+	defer teardown()
+
+	analyticsRequest := AnalyticsRequest{
+		Filters: &AnalyticsFilter{
+			CreatedAtStart: "2021-01-01T15:00:32Z",
+			CreatedAtEnd:   "2021-01-08T15:00:32Z",
+			TeamIDs:        []string{"PCDYDX0"},
+		},
+		AggregateUnit: "day",
+		TimeZone:      "Etc/UTC",
+	}
+	analyticsDataWanted := AnalyticsData{MeanAssignmentCount: 1, MeanEngagedSeconds: 502, MeanEngagedUserCount: 0, MeanSecondsToResolve: 34550, MeanSecondsToFirstAck: 70, TotalBusinessHourInterruptions: 1, TotalEngagedSeconds: 2514, TotalIncidentCount: 5, RangeStart: "2021-01-06T00:00:00.000000", ServiceID: "PSEJLIN", ServiceName: "FooAlerts", TeamID: "PCDYDX0", TeamName: "FooTeam", UpTimePct: 89.86111111111111}
+	analyticsFilterWanted := AnalyticsFilter{CreatedAtStart: "2021-01-06T09:21:41Z", CreatedAtEnd: "2021-01-13T09:21:41Z", TeamIDs: []string{"PCDYDX0"}}
+	analyticsResponse := AnalyticsResponse{
+		Data:          []AnalyticsData{analyticsDataWanted},
+		Filters:       &analyticsFilterWanted,
+		AggregateUnit: "day",
+		TimeZone:      "Etc/UTC",
+	}
+	bytesAnalyticsResponse, err := json.Marshal(analyticsResponse)
+	mux.HandleFunc("/analytics/metrics/incidents/services", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "POST")
+		w.Write(bytesAnalyticsResponse)
+	})
+
+	client := &Client{apiEndpoint: server.URL,
+		authToken:  "foo",
+		HTTPClient: defaultHTTPClient,
+	}
+
+	res, err := client.GetAggregatedServiceData(context.Background(), analyticsRequest)
+	want := AnalyticsResponse{
+		Data:          []AnalyticsData{analyticsDataWanted},
+		Filters:       &analyticsFilterWanted,
+		AggregateUnit: "day",
+		TimeZone:      "Etc/UTC",
+	}
+	if err != nil {
+		t.Fatal(err)
+	}
+	testEqual(t, want, res)
+}
+
+func TestAnalytics_GetAggregatedTeamData(t *testing.T) {
+	setup()
+	defer teardown()
+
+	analyticsRequest := AnalyticsRequest{
+		Filters: &AnalyticsFilter{
+			CreatedAtStart: "2021-01-01T15:00:32Z",
+			CreatedAtEnd:   "2021-01-08T15:00:32Z",
+			TeamIDs:        []string{"PCDYDX0"},
+		},
+		AggregateUnit: "day",
+		TimeZone:      "Etc/UTC",
+	}
+	analyticsDataWanted := AnalyticsData{MeanAssignmentCount: 1, MeanEngagedSeconds: 502, MeanEngagedUserCount: 0, MeanSecondsToResolve: 34550, MeanSecondsToFirstAck: 70, TotalBusinessHourInterruptions: 1, TotalEngagedSeconds: 2514, TotalIncidentCount: 5, RangeStart: "2021-01-06T00:00:00.000000", TeamID: "PCDYDX0", TeamName: "FooTeam", UpTimePct: 89.86111111111111}
+	analyticsFilterWanted := AnalyticsFilter{CreatedAtStart: "2021-01-06T09:21:41Z", CreatedAtEnd: "2021-01-13T09:21:41Z", TeamIDs: []string{"PCDYDX0"}}
+	analyticsResponse := AnalyticsResponse{
+		Data:          []AnalyticsData{analyticsDataWanted},
+		Filters:       &analyticsFilterWanted,
+		AggregateUnit: "day",
+		TimeZone:      "Etc/UTC",
+	}
+	bytesAnalyticsResponse, err := json.Marshal(analyticsResponse)
+	mux.HandleFunc("/analytics/metrics/incidents/teams", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "POST")
+		w.Write(bytesAnalyticsResponse)
+	})
+
+	client := &Client{apiEndpoint: server.URL,
+		authToken:  "foo",
+		HTTPClient: defaultHTTPClient,
+	}
+
+	res, err := client.GetAggregatedTeamData(context.Background(), analyticsRequest)
+	want := AnalyticsResponse{
+		Data:          []AnalyticsData{analyticsDataWanted},
+		Filters:       &analyticsFilterWanted,
+		AggregateUnit: "day",
+		TimeZone:      "Etc/UTC",
 	}
 	if err != nil {
 		t.Fatal(err)