func (sc *Client) GetSite(corpName, siteName string) (Site, error) {
	resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s", corpName, siteName), "")
	if err != nil {
		return Site{}, err
	}
	var site Site
	err = json.Unmarshal(resp, &site)
	if err != nil {
		return Site{}, err
	}
	return site, nil
}
GetSite gets a site by name.
package sigsci
import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)
const apiURL = "https://dashboard.signalsciences.net/api"
type Client struct {
	email string
	token string
}
func NewClient(email, password string) (Client, error) {
	sc := Client{}
	err := sc.authenticate(email, password)
	if err != nil {
		return Client{}, err
	}
	return sc, nil
}
func NewTokenClient(email, token string) Client {
	return Client{
		email: email,
		token: token,
	}
}
func (sc *Client) authenticate(email, password string) error {
	resp, err := http.PostForm(apiURL+"/v0/auth", url.Values{"email": {email}, "password": {password}})
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	var tr struct {
		Token string
	}
	err = json.NewDecoder(resp.Body).Decode(&tr)
	if err != nil {
		return err
	}
	sc.token = tr.Token
	return nil
}
func (sc *Client) doRequest(method, url, reqBody string) ([]byte, error) {
	client := &http.Client{}
	var b io.Reader
	if reqBody != "" {
		b = strings.NewReader(reqBody)
	}
	req, err := http.NewRequest(method, apiURL+url, b)
	if err != nil {
		return []byte{}, err
	}
	if sc.email != "" {
		req.Header.Set("X-API-User", sc.email)
		req.Header.Set("X-API-Token", sc.token)
	} else {
		req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", sc.token))
	}
	req.Header.Add("Content-Type", "application/json")
	req.Header.Set("User-Agent", "go-sigsci")
	resp, err := client.Do(req)
	if err != nil {
		return []byte{}, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return []byte{}, err
	}
	switch method {
	case "GET":
		if resp.StatusCode != http.StatusOK {
			return body, errMsg(body)
		}
	case "POST":
		switch resp.StatusCode {
		case http.StatusOK, http.StatusCreated, http.StatusNoContent:
		default:
			return body, errMsg(body)
		}
	case "DELETE":
		if resp.StatusCode != http.StatusNoContent {
			return body, errMsg(body)
		}
	case "PATCH":
		if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
			return body, errMsg(body)
		}
	}
	return body, nil
}
func errMsg(b []byte) error {
	var errResp struct {
		Message string
	}
	err := json.Unmarshal(b, &errResp)
	if err != nil {
		return err
	}
	return errors.New(errResp.Message)
}
type Corp struct {
	Name                   string
	DisplayName            string
	SmallIconURI           string
	Created                time.Time
	SiteLimit              int
	Sites                  map[string]string
	AuthType               string
	MFAEnforced            bool
	SessionMaxAgeDashboard int
}
type corpsResponse struct {
	Data []Corp
}
func (sc *Client) ListCorps() ([]Corp, error) {
	resp, err := sc.doRequest("GET", "/v0/corps", "")
	if err != nil {
		return []Corp{}, err
	}
	var cr corpsResponse
	err = json.Unmarshal(resp, &cr)
	if err != nil {
		return []Corp{}, err
	}
	return cr.Data, nil
}
func (sc *Client) GetCorp(corpName string) (Corp, error) {
	resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s", corpName), "")
	if err != nil {
		return Corp{}, err
	}
	var corp Corp
	err = json.Unmarshal(resp, &corp)
	if err != nil {
		return Corp{}, err
	}
	return corp, nil
}
type UpdateCorpBody struct {
	DisplayName            string `json:"displayName,omitempty"`
	SmallIconURI           string `json:"smallIconURI,omitempty"`
	SessionMaxAgeDashboard int    `json:"sessionMaxAgeDashboard,omitempty"`
}
func (sc *Client) UpdateCorp(corpName string, body UpdateCorpBody) (Corp, error) {
	b, err := json.Marshal(body)
	if err != nil {
		return Corp{}, err
	}
	resp, err := sc.doRequest("PATCH", fmt.Sprintf("/v0/corps/%s", corpName), string(b))
	if err != nil {
		return Corp{}, err
	}
	var corp Corp
	err = json.Unmarshal(resp, &corp)
	if err != nil {
		return Corp{}, err
	}
	return corp, nil
}
type Role string
const (
	RoleNoAccess = Role("none")
	RoleUnknown  = Role("unknown")
	RoleOwner    = Role("owner")
	RoleAdmin    = Role("admin")
	RoleUser     = Role("user")
	RoleObserver = Role("observer")
	RoleSiteNoAccess = Role("none")
	RoleSiteUnknown  = Role("unknown")
	RoleSiteOwner    = Role("owner")
	RoleSiteAdmin    = Role("admin")
	RoleSiteUser     = Role("user")
	RoleSiteObserver = Role("observer")
	RoleCorpOwner    = Role("corpOwner")
	RoleCorpUser     = Role("corpUser")
)
type CorpUser struct {
	Name        string
	Email       string
	Memberships map[string]string
	Role        string
	Status      string
	MFAEnabled  bool
	AuthStatus  string
	Created     time.Time
}
type corpUsersResponse struct {
	Data []CorpUser
}
func (sc *Client) ListCorpUsers(corpName string) ([]CorpUser, error) {
	resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/users", corpName), "")
	if err != nil {
		return []CorpUser{}, err
	}
	var cur corpUsersResponse
	err = json.Unmarshal(resp, &cur)
	if err != nil {
		return []CorpUser{}, err
	}
	return cur.Data, nil
}
func (sc *Client) GetCorpUser(corpName, email string) (CorpUser, error) {
	resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/users/%s", corpName, email), "")
	if err != nil {
		return CorpUser{}, err
	}
	var cu CorpUser
	err = json.Unmarshal(resp, &cu)
	if err != nil {
		return CorpUser{}, err
	}
	return cu, nil
}
func (sc *Client) DeleteCorpUser(corpName, email string) error {
	_, err := sc.doRequest("DELETE", fmt.Sprintf("/v0/corps/%s/users/%s", corpName, email), "")
	return err
}
type site struct {
	Name string `json:"name"`
}
type SiteMembership struct {
	Site site `json:"site"`
	Role Role `json:"role"`
}
func NewSiteMembership(name string, role Role) SiteMembership {
	return SiteMembership{
		Site: site{Name: name},
		Role: role,
	}
}
type inviteMemberships struct {
	Data []SiteMembership `json:"data"`
}
type CorpUserInvite struct {
	Role        Role              `json:"role"`
	Memberships inviteMemberships `json:"memberships"`
}
func NewCorpUserInvite(corpRole Role, memberships []SiteMembership) CorpUserInvite {
	return CorpUserInvite{
		Role: corpRole,
		Memberships: inviteMemberships{
			Data: memberships,
		},
	}
}
func (sc *Client) InviteUser(corpName, email string, invite CorpUserInvite) (CorpUser, error) {
	body, err := json.Marshal(invite)
	if err != nil {
		return CorpUser{}, err
	}
	resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/users/%s/invite", corpName, email), string(body))
	if err != nil {
		return CorpUser{}, err
	}
	var cu CorpUser
	err = json.Unmarshal(resp, &cu)
	if err != nil {
		return CorpUser{}, err
	}
	return cu, nil
}
type topAttackType struct {
	TagName    string
	TagCount   int
	TotalCount int
}
type topAttackSource struct {
	CountryCode  string
	CountryName  string
	RequestCount int
	TotalCount   int
}
type OverviewSite struct {
	Name             string
	DisplayName      string
	TotalCount       int
	BlockedCount     int
	FlaggedCount     int
	AttackCount      int
	FlaggedIPCount   int
	TopAttackTypes   []topAttackType
	TopAttackSources []topAttackSource
}
type overviewResponse struct {
	Data []OverviewSite
}
func (sc *Client) GetOverviewReport(corpName string, query url.Values) ([]OverviewSite, error) {
	url := fmt.Sprintf("/v0/corps/%s/reports/attacks", corpName)
	if query.Encode() != "" {
		url += "?" + query.Encode()
	}
	resp, err := sc.doRequest("GET", url, "")
	if err != nil {
		return []OverviewSite{}, err
	}
	var or overviewResponse
	err = json.Unmarshal(resp, &or)
	if err != nil {
		return []OverviewSite{}, err
	}
	return or.Data, nil
}
type ActivityEvent struct {
	ID          string
	EventType   string
	MsgData     map[string]string
	Message     string
	Attachments []struct{}
	Created     time.Time
}
type activityResponse struct {
	TotalCount int
	Next       map[string]string
	Data       []ActivityEvent
}
func (sc *Client) ListCorpActivity(corpName string, limit, page int) ([]ActivityEvent, error) {
	resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/activity?limit=%d&page=%d", corpName, limit, page), "")
	if err != nil {
		return []ActivityEvent{}, err
	}
	var ar activityResponse
	err = json.Unmarshal(resp, &ar)
	if err != nil {
		return []ActivityEvent{}, err
	}
	return ar.Data, nil
}
type Site struct {
	Name                 string
	DisplayName          string
	AgentLevel           string
	BlockHTTPCode        int
	BlockDurationSeconds int
	Created              time.Time
	Whitelist            map[string]string
	Blacklist            map[string]string
	Events               map[string]string
	Requests             map[string]string
	Redactions           map[string]string
	SuspiciousIPs        map[string]string
	Monitors             map[string]string
	Pathwhitelist        map[string]string
	Paramwhitelist       map[string]string
	Integrations         map[string]string
	HeaderLinks          map[string]string
	Agents               map[string]string
	Alerts               map[string]string
	AnalyticsEvents      map[string]string
	TopAttacks           map[string]string
	Members              map[string]string
	AgentAnonMode        string
}
type sitesResponse struct {
	Data []Site
}
func (sc *Client) ListSites(corpName string) ([]Site, error) {
	resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites", corpName), "")
	if err != nil {
		return []Site{}, err
	}
	var sr sitesResponse
	err = json.Unmarshal(resp, &sr)
	if err != nil {
		return []Site{}, err
	}
	return sr.Data, nil
}