Repository: mailgun/mailgun-go
Pull request #376 (2024-12-25 13:05:55)

DE-1384 Domain agnostic API


Patch:
diff --git a/README.md b/README.md
index 617d57f..beb7485 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ var privateAPIKey = "your-private-key"
 
 func main() {
 	// Create an instance of the Mailgun Client
-	mg := mailgun.NewMailgun(yourDomain, privateAPIKey)
+	mg := mailgun.NewMailgun(privateAPIKey)
 	
 	//When you have an EU-domain, you must specify the endpoint:
 	//mg.SetAPIBase("https://api.eu.mailgun.net/v3")
@@ -79,9 +79,9 @@ import (
 func main() {
 	// You can find the Private API Key in your Account Menu, under "Settings":
 	// (https://app.mailgun.com/settings/api_security)
-	mg := mailgun.NewMailgun("your-domain.com", "your-private-key")
+	mg := mailgun.NewMailgun("your-private-key")
 
-	it := mg.ListEvents(&mailgun.ListEventOptions{Limit: 100})
+	it := mg.ListEvents("your-domain.com", &mailgun.ListEventOptions{Limit: 100})
 
 	var page []mailgun.Event
 
@@ -135,12 +135,12 @@ import (
 func main() {
 	// You can find the Private API Key in your Account Menu, under "Settings":
 	// (https://app.mailgun.com/settings/api_security)
-	mg := mailgun.NewMailgun("your-domain.com", "your-private-key")
+	mg := mailgun.NewMailgun("your-private-key")
 
 	begin := time.Now().Add(time.Second * -3)
 
 	// Very short poll interval
-	it := mg.PollEvents(&mailgun.ListEventOptions{
+	it := mg.PollEvents("your-domain.com", &mailgun.ListEventOptions{
 		// Only events with a timestamp after this date/time will be returned
 		Begin: begin,
 		// How often we poll the api for new events
@@ -210,11 +210,10 @@ import (
 func main() {
 	// You can find the Private API Key in your Account Menu, under "Settings":
 	// (https://app.mailgun.com/settings/api_security)
-	mg := mailgun.NewMailgun("your-domain.com", "private-api-key")
+	mg := mailgun.NewMailgun("private-api-key")
 	mg.SetWebhookSigningKey("webhook-signing-key")
 
 	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
-
 		var payload mailgun.WebhookPayload
 		if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
 			fmt.Printf("decode JSON error: %s", err)
@@ -284,7 +283,7 @@ var privateAPIKey = "your-private-key"
 
 func main() {
 	// Create an instance of the Mailgun Client
-	mg := mailgun.NewMailgun(yourDomain, privateAPIKey)
+	mg := mailgun.NewMailgun(privateAPIKey)
 
 	sender := "sender@example.com"
 	subject := "HTML email!"
@@ -306,7 +305,7 @@ func main() {
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
 	defer cancel()
 
-	// Send the message with a 10 second timeout
+	// Send the message with a 10-second timeout
 	resp, id, err := mg.Send(ctx, message)
 
 	if err != nil {
@@ -343,7 +342,7 @@ var privateAPIKey = "your-private-key"
 
 func main() {
 	// Create an instance of the Mailgun Client
-	mg := mailgun.NewMailgun(yourDomain, privateAPIKey)
+	mg := mailgun.NewMailgun(privateAPIKey)
 
 	sender := "sender@example.com"
 	subject := "Fancy subject!"
@@ -379,7 +378,7 @@ and click on the "Go" button at the top of the page.
 European customers will need to change the default API Base to access your domains
 
 ```go
-mg := mailgun.NewMailgun("your-domain.com", "private-api-key")
+mg := mailgun.NewMailgun("private-api-key")
 mg.SetAPIBase(mailgun.APIBaseEU)
 ```
 
@@ -390,7 +389,6 @@ mg.SetAPIBase(mailgun.APIBaseEU)
 To run the tests various environment variables must be set. These are:
 
 * `MG_DOMAIN` is the domain name - this is a value registered in the Mailgun admin interface.
-* `MG_PUBLIC_API_KEY` is the Public Validation API key - you can get this value from the Mailgun [security page](https://app.mailgun.com/settings/api_security)
 * `MG_API_KEY` is the Private API key - you can get this value from the Mailgun [security page](https://app.mailgun.com/settings/api_security)
 * `MG_EMAIL_TO` is the email address used in various sending tests.
 
diff --git a/analytics.go b/analytics.go
index 3163da9..7a421cf 100644
--- a/analytics.go
+++ b/analytics.go
@@ -22,6 +22,14 @@ type MetricsPagination struct {
 
 // ListMetrics returns domain/account metrics.
 //
+// To filter by domain:
+//
+//	opts.Filter.BoolGroupAnd = []mailgun.MetricsFilterPredicate{{
+//		Attribute:     "domain",
+//		Comparator:    "=",
+//		LabeledValues: []mailgun.MetricsLabeledValue{{Label: "example.com", Value: "example.com"}},
+//	}}
+//
 // NOTE: Only for v1 API. To use the /v1 version define MG_URL in the environment variable
 // as `https://api.mailgun.net/v1` or set `mg.SetAPIBase("https://api.mailgun.net/v1")`
 //
@@ -31,23 +39,12 @@ func (mg *MailgunImpl) ListMetrics(opts MetricsOptions) (*MetricsIterator, error
 		return nil, errors.New("only v1 API is supported")
 	}
 
-	domain := mg.Domain()
-	if domain != "" {
-		domainFilter := MetricsFilterPredicate{
-			Attribute:     "domain",
-			Comparator:    "=",
-			LabeledValues: []MetricsLabeledValue{{Label: domain, Value: domain}},
-		}
-
-		opts.Filter.BoolGroupAnd = append(opts.Filter.BoolGroupAnd, domainFilter)
-	}
-
 	if opts.Pagination.Limit == 0 {
 		opts.Pagination.Limit = 10
 	}
 
-	req := newHTTPRequest(generatePublicApiUrl(mg, metricsEndpoint))
-	req.setClient(mg.Client())
+	req := newHTTPRequest(generateApiUrl(mg, metricsEndpoint))
+	req.setClient(mg.HTTPClient())
 	req.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	return &MetricsIterator{
diff --git a/bounces.go b/bounces.go
index d27948a..405d861 100644
--- a/bounces.go
+++ b/bounces.go
@@ -34,9 +34,9 @@ type bouncesListResponse struct {
 // The results include the total number of bounces (regardless of skip or limit settings),
 // and the slice of bounces specified, if successful.
 // Note that the length of the slice may be smaller than the total number of bounces.
-func (mg *MailgunImpl) ListBounces(opts *ListOptions) *BouncesIterator {
-	r := newHTTPRequest(generateApiUrl(mg, bouncesEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) ListBounces(domain string, opts *ListOptions) *BouncesIterator {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, bouncesEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	if opts != nil {
 		if opts.Limit != 0 {
@@ -139,16 +139,16 @@ func (ci *BouncesIterator) Previous(ctx context.Context, items *[]Bounce) bool {
 func (ci *BouncesIterator) fetch(ctx context.Context, url string) error {
 	ci.Items = nil
 	r := newHTTPRequest(url)
-	r.setClient(ci.mg.Client())
+	r.setClient(ci.mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, ci.mg.APIKey())
 
 	return getResponseFromJSON(ctx, r, &ci.bouncesListResponse)
 }
 
 // GetBounce retrieves a single bounce record, if any exist, for the given recipient address.
-func (mg *MailgunImpl) GetBounce(ctx context.Context, address string) (Bounce, error) {
-	r := newHTTPRequest(generateApiUrl(mg, bouncesEndpoint) + "/" + address)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) GetBounce(ctx context.Context, domain, address string) (Bounce, error) {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, bouncesEndpoint, domain) + "/" + address)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	var response Bounce
@@ -172,9 +172,9 @@ func (mg *MailgunImpl) GetBounce(ctx context.Context, address string) (Bounce, e
 //
 // Note that both code and error exist as strings, even though
 // code will report as a number.
-func (mg *MailgunImpl) AddBounce(ctx context.Context, address, code, bounceError string) error {
-	r := newHTTPRequest(generateApiUrl(mg, bouncesEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) AddBounce(ctx context.Context, domain, address, code, bounceError string) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, bouncesEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -190,9 +190,9 @@ func (mg *MailgunImpl) AddBounce(ctx context.Context, address, code, bounceError
 }
 
 // Add Bounces adds a list of bounces to the bounce list
-func (mg *MailgunImpl) AddBounces(ctx context.Context, bounces []Bounce) error {
-	r := newHTTPRequest(generateApiUrl(mg, bouncesEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) AddBounces(ctx context.Context, domain string, bounces []Bounce) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, bouncesEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newJSONEncodedPayload(bounces)
@@ -202,18 +202,18 @@ func (mg *MailgunImpl) AddBounces(ctx context.Context, bounces []Bounce) error {
 }
 
 // DeleteBounce removes all bounces associted with the provided e-mail address.
-func (mg *MailgunImpl) DeleteBounce(ctx context.Context, address string) error {
-	r := newHTTPRequest(generateApiUrl(mg, bouncesEndpoint) + "/" + address)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) DeleteBounce(ctx context.Context, domain, address string) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, bouncesEndpoint, domain) + "/" + address)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
 }
 
 // DeleteBounceList removes all bounces in the bounce list
-func (mg *MailgunImpl) DeleteBounceList(ctx context.Context) error {
-	r := newHTTPRequest(generateApiUrl(mg, bouncesEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) DeleteBounceList(ctx context.Context, domain string) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, bouncesEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
diff --git a/credentials.go b/credentials.go
index 05873a5..945a9c7 100644
--- a/credentials.go
+++ b/credentials.go
@@ -23,7 +23,7 @@ type credentialsListResponse struct {
 var ErrEmptyParam = fmt.Errorf("empty or illegal parameter")
 
 // ListCredentials returns the (possibly zero-length) list of credentials associated with your domain.
-func (mg *MailgunImpl) ListCredentials(opts *ListOptions) *CredentialsIterator {
+func (mg *MailgunImpl) ListCredentials(domain string, opts *ListOptions) *CredentialsIterator {
 	var limit int
 	if opts != nil {
 		limit = opts.Limit
@@ -34,7 +34,7 @@ func (mg *MailgunImpl) ListCredentials(opts *ListOptions) *CredentialsIterator {
 	}
 	return &CredentialsIterator{
 		mg:                      mg,
-		url:                     generateCredentialsUrl(mg, ""),
+		url:                     generateCredentialsUrl(mg, domain, ""),
 		credentialsListResponse: credentialsListResponse{TotalCount: -1},
 		limit:                   limit,
 	}
@@ -161,7 +161,7 @@ func (ri *CredentialsIterator) fetch(ctx context.Context, skip, limit int) error
 	ri.Items = nil
 	r := newHTTPRequest(ri.url)
 	r.setBasicAuth(basicAuthUser, ri.mg.APIKey())
-	r.setClient(ri.mg.Client())
+	r.setClient(ri.mg.HTTPClient())
 
 	if skip != 0 {
 		r.addParameter("skip", strconv.Itoa(skip))
@@ -174,12 +174,12 @@ func (ri *CredentialsIterator) fetch(ctx context.Context, skip, limit int) error
 }
 
 // CreateCredential attempts to create associate a new principle with your domain.
-func (mg *MailgunImpl) CreateCredential(ctx context.Context, login, password string) error {
+func (mg *MailgunImpl) CreateCredential(ctx context.Context, domain, login, password string) error {
 	if (login == "") || (password == "") {
 		return ErrEmptyParam
 	}
-	r := newHTTPRequest(generateCredentialsUrl(mg, ""))
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateCredentialsUrl(mg, domain, ""))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := newUrlEncodedPayload()
 	p.addValue("login", login)
@@ -189,12 +189,12 @@ func (mg *MailgunImpl) CreateCredential(ctx context.Context, login, password str
 }
 
 // ChangeCredentialPassword attempts to alter the indicated credential's password.
-func (mg *MailgunImpl) ChangeCredentialPassword(ctx context.Context, login, password string) error {
+func (mg *MailgunImpl) ChangeCredentialPassword(ctx context.Context, domain, login, password string) error {
 	if (login == "") || (password == "") {
 		return ErrEmptyParam
 	}
-	r := newHTTPRequest(generateCredentialsUrl(mg, login))
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateCredentialsUrl(mg, domain, login))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := newUrlEncodedPayload()
 	p.addValue("password", password)
@@ -203,12 +203,12 @@ func (mg *MailgunImpl) ChangeCredentialPassword(ctx context.Context, login, pass
 }
 
 // DeleteCredential attempts to remove the indicated principle from the domain.
-func (mg *MailgunImpl) DeleteCredential(ctx context.Context, login string) error {
+func (mg *MailgunImpl) DeleteCredential(ctx context.Context, domain, login string) error {
 	if login == "" {
 		return ErrEmptyParam
 	}
-	r := newHTTPRequest(generateCredentialsUrl(mg, login))
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateCredentialsUrl(mg, domain, login))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
diff --git a/domains.go b/domains.go
index 8fcb81f..cb01562 100644
--- a/domains.go
+++ b/domains.go
@@ -92,7 +92,7 @@ func (mg *MailgunImpl) ListDomains(opts *ListOptions) *DomainsIterator {
 	}
 	return &DomainsIterator{
 		mg:                  mg,
-		url:                 generatePublicApiUrl(mg, domainsEndpoint),
+		url:                 generateApiUrl(mg, domainsEndpoint),
 		domainsListResponse: domainsListResponse{TotalCount: -1},
 		limit:               limit,
 	}
@@ -219,7 +219,7 @@ func (ri *DomainsIterator) fetch(ctx context.Context, skip, limit int) error {
 	ri.Items = nil
 	r := newHTTPRequest(ri.url)
 	r.setBasicAuth(basicAuthUser, ri.mg.APIKey())
-	r.setClient(ri.mg.Client())
+	r.setClient(ri.mg.HTTPClient())
 
 	if skip != 0 {
 		r.addParameter("skip", strconv.Itoa(skip))
@@ -233,8 +233,8 @@ func (ri *DomainsIterator) fetch(ctx context.Context, skip, limit int) error {
 
 // GetDomain retrieves detailed information about the named domain.
 func (mg *MailgunImpl) GetDomain(ctx context.Context, domain string) (DomainResponse, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain)
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	var resp DomainResponse
 	err := getResponseFromJSON(ctx, r, &resp)
@@ -242,8 +242,8 @@ func (mg *MailgunImpl) GetDomain(ctx context.Context, domain string) (DomainResp
 }
 
 func (mg *MailgunImpl) VerifyDomain(ctx context.Context, domain string) (string, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/verify")
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/verify")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -254,8 +254,8 @@ func (mg *MailgunImpl) VerifyDomain(ctx context.Context, domain string) (string,
 
 // VerifyAndReturnDomain verifies & retrieves detailed information about the named domain.
 func (mg *MailgunImpl) VerifyAndReturnDomain(ctx context.Context, domain string) (DomainResponse, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/verify")
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/verify")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -282,8 +282,8 @@ type CreateDomainOptions struct {
 // The wildcard parameter instructs Mailgun to treat all subdomains of this domain uniformly if true,
 // and as different domains if false.
 func (mg *MailgunImpl) CreateDomain(ctx context.Context, name string, opts *CreateDomainOptions) (DomainResponse, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint))
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -319,8 +319,8 @@ func (mg *MailgunImpl) CreateDomain(ctx context.Context, name string, opts *Crea
 
 // GetDomainConnection returns delivery connection settings for the defined domain
 func (mg *MailgunImpl) GetDomainConnection(ctx context.Context, domain string) (DomainConnection, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/connection")
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/connection")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	var resp domainConnectionResponse
 	err := getResponseFromJSON(ctx, r, &resp)
@@ -329,8 +329,8 @@ func (mg *MailgunImpl) GetDomainConnection(ctx context.Context, domain string) (
 
 // Updates the specified delivery connection settings for the defined domain
 func (mg *MailgunImpl) UpdateDomainConnection(ctx context.Context, domain string, settings DomainConnection) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/connection")
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/connection")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -342,8 +342,8 @@ func (mg *MailgunImpl) UpdateDomainConnection(ctx context.Context, domain string
 
 // DeleteDomain instructs Mailgun to dispose of the named domain name
 func (mg *MailgunImpl) DeleteDomain(ctx context.Context, name string) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + name)
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + name)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
@@ -351,8 +351,8 @@ func (mg *MailgunImpl) DeleteDomain(ctx context.Context, name string) error {
 
 // GetDomainTracking returns tracking settings for a domain
 func (mg *MailgunImpl) GetDomainTracking(ctx context.Context, domain string) (DomainTracking, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/tracking")
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/tracking")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	var resp domainTrackingResponse
 	err := getResponseFromJSON(ctx, r, &resp)
@@ -360,8 +360,8 @@ func (mg *MailgunImpl) GetDomainTracking(ctx context.Context, domain string) (Do
 }
 
 func (mg *MailgunImpl) UpdateClickTracking(ctx context.Context, domain, active string) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/tracking/click")
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/tracking/click")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -371,8 +371,8 @@ func (mg *MailgunImpl) UpdateClickTracking(ctx context.Context, domain, active s
 }
 
 func (mg *MailgunImpl) UpdateUnsubscribeTracking(ctx context.Context, domain, active, htmlFooter, textFooter string) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/tracking/unsubscribe")
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/tracking/unsubscribe")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -384,8 +384,8 @@ func (mg *MailgunImpl) UpdateUnsubscribeTracking(ctx context.Context, domain, ac
 }
 
 func (mg *MailgunImpl) UpdateOpenTracking(ctx context.Context, domain, active string) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/tracking/open")
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/tracking/open")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -396,8 +396,8 @@ func (mg *MailgunImpl) UpdateOpenTracking(ctx context.Context, domain, active st
 
 // Update the DKIM selector for a domain
 func (mg *MailgunImpl) UpdateDomainDkimSelector(ctx context.Context, domain, dkimSelector string) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/dkim_selector")
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/dkim_selector")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -408,8 +408,8 @@ func (mg *MailgunImpl) UpdateDomainDkimSelector(ctx context.Context, domain, dki
 
 // Update the CNAME used for tracking opens and clicks
 func (mg *MailgunImpl) UpdateDomainTrackingWebPrefix(ctx context.Context, domain, webPrefix string) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/web_prefix")
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/web_prefix")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -426,8 +426,8 @@ type UpdateDomainOptions struct {
 // UpdateDomain updates a domain's attributes.
 // Currently only the web_scheme update is supported, spam_action and wildcard are to be added.
 func (mg *MailgunImpl) UpdateDomain(ctx context.Context, name string, opts *UpdateDomainOptions) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + name)
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + name)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
diff --git a/email_validation.go b/email_validation.go
index c294fc8..d9b484a 100644
--- a/email_validation.go
+++ b/email_validation.go
@@ -83,6 +83,7 @@ type EmailValidator interface {
 	ParseAddresses(ctx context.Context, addresses ...string) ([]string, []string, error)
 }
 
+// TODO(v5): switch to MailgunImpl
 type EmailValidatorImpl struct {
 	client  *http.Client
 	apiBase string
@@ -145,7 +146,7 @@ func (m *EmailValidatorImpl) APIKey() string {
 
 // ValidateEmail performs various checks on the email address provided to ensure it's correctly formatted.
 // It may also be used to break an email address into its sub-components. If user has set the
-// TODO(DE-1384): move to *MailgunImpl?
+// TODO(v5): move to *MailgunImpl?
 func (m *EmailValidatorImpl) ValidateEmail(ctx context.Context, email string, mailBoxVerify bool) (EmailVerification, error) {
 	// TODO(DE-1383): remove check:
 	if strings.HasSuffix(m.APIBase(), "/v4") {
diff --git a/events.go b/events.go
index a8c2f3e..d17e63a 100644
--- a/events.go
+++ b/events.go
@@ -36,18 +36,12 @@ type EventIterator struct {
 	err error
 }
 
-// Create an new iterator to fetch a page of events from the events api with a specific domain
-func (mg *MailgunImpl) ListEventsWithDomain(opts *ListEventOptions, domain string) *EventIterator {
+// ListEvents creates a new iterator to fetch a page of events from the events api
+func (mg *MailgunImpl) ListEvents(domain string, opts *ListEventOptions) *EventIterator {
 	url := generateApiUrlWithDomain(mg, eventsEndpoint, domain)
 	return mg.listEvents(url, opts)
 }
 
-// Create an new iterator to fetch a page of events from the events api
-func (mg *MailgunImpl) ListEvents(opts *ListEventOptions) *EventIterator {
-	url := generateApiUrl(mg, eventsEndpoint)
-	return mg.listEvents(url, opts)
-}
-
 func (mg *MailgunImpl) listEvents(url string, opts *ListEventOptions) *EventIterator {
 	req := newHTTPRequest(url)
 	if opts != nil {
@@ -161,7 +155,7 @@ func (ei *EventIterator) Previous(ctx context.Context, ee *[]Event) bool {
 func (ei *EventIterator) fetch(ctx context.Context, url string) error {
 	ei.Items = nil
 	r := newHTTPRequest(url)
-	r.setClient(ei.mg.Client())
+	r.setClient(ei.mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, ei.mg.APIKey())
 
 	resp, err := makeRequest(ctx, r, http.MethodGet, nil)
@@ -188,7 +182,7 @@ type EventPoller struct {
 
 // PollEvents polls the events api and return new events as they occur
 //
-//	it = mg.PollEvents(&ListEventOptions{
+//	it = mg.PollEvents("example.com", &ListEventOptions{
 //		// Only events with a timestamp after this date/time will be returned
 //		Begin:        time.Now().Add(time.Second * -3),
 //		// How often we poll the api for new events
@@ -207,7 +201,7 @@ type EventPoller struct {
 //	if it.Err() != nil {
 //		log.Fatal(it.Err())
 //	}
-func (mg *MailgunImpl) PollEvents(opts *ListEventOptions) *EventPoller {
+func (mg *MailgunImpl) PollEvents(domain string, opts *ListEventOptions) *EventPoller {
 	now := time.Now()
 	// ForceAscending must be set
 	opts.ForceAscending = true
@@ -223,7 +217,7 @@ func (mg *MailgunImpl) PollEvents(opts *ListEventOptions) *EventPoller {
 	}
 
 	return &EventPoller{
-		it:   mg.ListEvents(opts),
+		it:   mg.ListEvents(domain, opts),
 		opts: *opts,
 		mg:   mg,
 	}
diff --git a/examples/examples.go b/examples/examples.go
index d36316d..da2b4b5 100644
--- a/examples/examples.go
+++ b/examples/examples.go
@@ -11,30 +11,30 @@ import (
 )
 
 func AddBounce(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.AddBounce(ctx, "bob@example.com", "550", "Undeliverable message error")
+	return mg.AddBounce(ctx, domain, "bob@example.com", "550", "Undeliverable message error")
 }
 
 func CreateComplaint(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.CreateComplaint(ctx, "bob@example.com")
+	return mg.CreateComplaint(ctx, domain, "bob@example.com")
 }
 
 func AddDomain(domain, apiKey string) (mailgun.DomainResponse, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.CreateDomain(ctx, "example.com", &mailgun.CreateDomainOptions{
+	return mg.CreateDomain(ctx, domain, &mailgun.CreateDomainOptions{
 		Password:   "super_secret",
 		SpamAction: mailgun.SpamActionTag,
 		Wildcard:   false,
@@ -42,16 +42,16 @@ func AddDomain(domain, apiKey string) (mailgun.DomainResponse, error) {
 }
 
 func AddDomainIPS(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.AddDomainIP(ctx, "127.0.0.1")
+	return mg.AddDomainIP(ctx, domain, "127.0.0.1")
 }
 
-func AddListMember(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+func AddListMember(apiKey string) error {
+	mg := mailgun.NewMailgun(apiKey)
 
 	memberJoe := mailgun.Member{
 		Address:    "joe@example.com",
@@ -65,8 +65,8 @@ func AddListMember(domain, apiKey string) error {
 	return mg.CreateMember(ctx, true, "mailingList@example.com", memberJoe)
 }
 
-func AddListMembers(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+func AddListMembers(apiKey string) error {
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -94,16 +94,16 @@ func AddListMembers(domain, apiKey string) error {
 }
 
 func CreateUnsubscribe(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.CreateUnsubscribe(ctx, "bob@example.com", "*")
+	return mg.CreateUnsubscribe(ctx, domain, "bob@example.com", "*")
 }
 
 func CreateUnsubscribes(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -113,60 +113,60 @@ func CreateUnsubscribes(domain, apiKey string) error {
 		{Address: "bob@example.com", Tags: []string{"tag1"}},
 	}
 
-	return mg.CreateUnsubscribes(ctx, unsubscribes)
+	return mg.CreateUnsubscribes(ctx, domain, unsubscribes)
 }
 
 func CreateUnsubscribeWithTag(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.CreateUnsubscribe(ctx, "bob@example.com", "tag1")
+	return mg.CreateUnsubscribe(ctx, domain, "bob@example.com", "tag1")
 }
 
 func CreateWebhook(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.CreateWebhook(ctx, "clicked", []string{"https://your_domain.com/v1/clicked"})
+	return mg.CreateWebhook(ctx, domain, "clicked", []string{"https://your_domain.com/v1/clicked"})
 }
 
 func ChangePassword(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.ChangeCredentialPassword(ctx, "alice", "super_secret")
+	return mg.ChangeCredentialPassword(ctx, domain, "alice", "super_secret")
 }
 
 func CreateCredential(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.CreateCredential(ctx, "alice@example.com", "secret")
+	return mg.CreateCredential(ctx, domain, "alice@example.com", "secret")
 }
 
 func CreateDomain(domain, apiKey string) (mailgun.DomainResponse, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.CreateDomain(ctx, "example.com", &mailgun.CreateDomainOptions{
+	return mg.CreateDomain(ctx, domain, &mailgun.CreateDomainOptions{
 		Password:   "super_secret",
 		SpamAction: mailgun.SpamActionTag,
 		Wildcard:   false,
 	})
 }
 
-func CreateExport(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+func CreateExport(apiKey string) error {
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -174,8 +174,8 @@ func CreateExport(domain, apiKey string) error {
 	return mg.CreateExport(ctx, "/v3/domains")
 }
 
-func CreateMailingList(domain, apiKey string) (mailgun.MailingList, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+func CreateMailingList(apiKey string) (mailgun.MailingList, error) {
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -189,7 +189,7 @@ func CreateMailingList(domain, apiKey string) (mailgun.MailingList, error) {
 }
 
 func CreateRoute(domain, apiKey string) (mailgun.Route, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -206,46 +206,46 @@ func CreateRoute(domain, apiKey string) (mailgun.Route, error) {
 }
 
 func DeleteCredential(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.DeleteCredential(ctx, "alice")
+	return mg.DeleteCredential(ctx, domain, "alice")
 }
 
 func DeleteDomain(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.DeleteDomain(ctx, "example.com")
+	return mg.DeleteDomain(ctx, domain)
 }
 
 func DeleteTag(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.DeleteTag(ctx, "newsletter")
+	return mg.DeleteTag(ctx, domain, "newsletter")
 }
 
 func DeleteWebhook(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.DeleteWebhook(ctx, "clicked")
+	return mg.DeleteWebhook(ctx, domain, "clicked")
 }
 
 func PrintEventLog(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	// Create an iterator
-	it := mg.ListEvents(&mailgun.ListEventOptions{
+	it := mg.ListEvents(domain, &mailgun.ListEventOptions{
 		Begin: time.Now().Add(-50 * time.Minute),
 		Limit: 100,
 		Filter: map[string]string{
@@ -273,10 +273,10 @@ func PrintEventLog(domain, apiKey string) error {
 }
 
 func PrintFailedEvents(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	// Create an iterator
-	it := mg.ListEvents(&mailgun.ListEventOptions{
+	it := mg.ListEvents(domain, &mailgun.ListEventOptions{
 		Filter: map[string]string{
 			"event": "rejected OR failed",
 		},
@@ -306,10 +306,10 @@ func PrintFailedEvents(domain, apiKey string) error {
 }
 
 func PrintEvents(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	// Create an iterator
-	it := mg.ListEvents(nil)
+	it := mg.ListEvents(domain, nil)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -337,17 +337,17 @@ func PrintEvents(domain, apiKey string) error {
 }
 
 func GetBounce(domain, apiKey string) (mailgun.Bounce, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.GetBounce(ctx, "foo@bar.com")
+	return mg.GetBounce(ctx, domain, "foo@bar.com")
 }
 
 func ListBounces(domain, apiKey string) ([]mailgun.Bounce, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
-	it := mg.ListBounces(nil)
+	mg := mailgun.NewMailgun(apiKey)
+	it := mg.ListBounces(domain, nil)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -364,17 +364,17 @@ func ListBounces(domain, apiKey string) ([]mailgun.Bounce, error) {
 }
 
 func GetComplaints(domain, apiKey string) (mailgun.Complaint, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.GetComplaint(ctx, "baz@example.com")
+	return mg.GetComplaint(ctx, domain, "baz@example.com")
 }
 
 func ListComplaints(domain, apiKey string) ([]mailgun.Complaint, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
-	it := mg.ListComplaints(nil)
+	mg := mailgun.NewMailgun(apiKey)
+	it := mg.ListComplaints(domain, nil)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -391,7 +391,7 @@ func ListComplaints(domain, apiKey string) ([]mailgun.Complaint, error) {
 }
 
 func GetDomainConnection(domain, apiKey string) (mailgun.DomainConnection, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -400,8 +400,8 @@ func GetDomainConnection(domain, apiKey string) (mailgun.DomainConnection, error
 }
 
 func ListCredentials(domain, apiKey string) ([]mailgun.Credential, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
-	it := mg.ListCredentials(nil)
+	mg := mailgun.NewMailgun(apiKey)
+	it := mg.ListCredentials(domain, nil)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -418,7 +418,7 @@ func ListCredentials(domain, apiKey string) ([]mailgun.Credential, error) {
 }
 
 func GetDomain(domain, apiKey string) (mailgun.DomainResponse, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -427,16 +427,16 @@ func GetDomain(domain, apiKey string) (mailgun.DomainResponse, error) {
 }
 
 func ListDomainIPS(domain, apiKey string) ([]mailgun.IPAddress, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.ListDomainIPS(ctx)
+	return mg.ListDomainIPS(ctx, domain)
 }
 
 func GetDomainTracking(domain, apiKey string) (mailgun.DomainTracking, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -445,7 +445,7 @@ func GetDomainTracking(domain, apiKey string) (mailgun.DomainTracking, error) {
 }
 
 func ListDomains(domain, apiKey string) ([]mailgun.Domain, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 	it := mg.ListDomains(nil)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
@@ -463,7 +463,7 @@ func ListDomains(domain, apiKey string) ([]mailgun.Domain, error) {
 }
 
 func GetExport(domain, apiKey string) (mailgun.Export, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -472,7 +472,7 @@ func GetExport(domain, apiKey string) (mailgun.Export, error) {
 }
 
 func GetIP(domain, apiKey string) (mailgun.IPAddress, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -481,7 +481,7 @@ func GetIP(domain, apiKey string) (mailgun.IPAddress, error) {
 }
 
 func ListIPS(domain, apiKey string) ([]mailgun.IPAddress, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -491,7 +491,7 @@ func ListIPS(domain, apiKey string) ([]mailgun.IPAddress, error) {
 }
 
 func GetTagLimits(domain, apiKey string) (mailgun.TagLimits, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -499,8 +499,8 @@ func GetTagLimits(domain, apiKey string) (mailgun.TagLimits, error) {
 	return mg.GetTagLimits(ctx, domain)
 }
 
-func ListExports(domain, apiKey string) ([]mailgun.Export, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+func ListExports(apiKey string) ([]mailgun.Export, error) {
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -509,8 +509,8 @@ func ListExports(domain, apiKey string) ([]mailgun.Export, error) {
 	return mg.ListExports(ctx, "")
 }
 
-func GetMembers(domain, apiKey string) ([]mailgun.Member, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+func GetMembers(apiKey string) ([]mailgun.Member, error) {
+	mg := mailgun.NewMailgun(apiKey)
 	it := mg.ListMembers("list@example.com", nil)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
@@ -527,8 +527,8 @@ func GetMembers(domain, apiKey string) ([]mailgun.Member, error) {
 	return result, nil
 }
 
-func ListMailingLists(domain, apiKey string) ([]mailgun.MailingList, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+func ListMailingLists(apiKey string) ([]mailgun.MailingList, error) {
+	mg := mailgun.NewMailgun(apiKey)
 	it := mg.ListMailingLists(nil)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
@@ -546,7 +546,7 @@ func ListMailingLists(domain, apiKey string) ([]mailgun.MailingList, error) {
 }
 
 func GetRoute(domain, apiKey string) (mailgun.Route, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -555,7 +555,7 @@ func GetRoute(domain, apiKey string) (mailgun.Route, error) {
 }
 
 func ListRoutes(domain, apiKey string) ([]mailgun.Route, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 	it := mg.ListRoutes(nil)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
@@ -573,8 +573,8 @@ func ListRoutes(domain, apiKey string) ([]mailgun.Route, error) {
 }
 
 func ListTags(domain, apiKey string) ([]mailgun.Tag, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
-	it := mg.ListTags(nil)
+	mg := mailgun.NewMailgun(apiKey)
+	it := mg.ListTags(domain, nil)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -591,8 +591,8 @@ func ListTags(domain, apiKey string) ([]mailgun.Tag, error) {
 }
 
 func ListUnsubscribes(domain, apiKey string) ([]mailgun.Unsubscribe, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
-	it := mg.ListUnsubscribes(nil)
+	mg := mailgun.NewMailgun(apiKey)
+	it := mg.ListUnsubscribes(domain, nil)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -618,34 +618,34 @@ func ValidateEmail(apiKey string) (mailgun.EmailVerification, error) {
 }
 
 func GetWebhook(domain, apiKey string) ([]string, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.GetWebhook(ctx, "clicked")
+	return mg.GetWebhook(ctx, domain, "clicked")
 }
 
 func ListWebhooks(domain, apiKey string) (map[string][]string, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.ListWebhooks(ctx)
+	return mg.ListWebhooks(ctx, domain)
 }
 
 func DeleteDomainIP(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.DeleteDomainIP(ctx, "127.0.0.1")
+	return mg.DeleteDomainIP(ctx, domain, "127.0.0.1")
 }
 
-func DeleteListMember(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+func DeleteListMember(apiKey string) error {
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -653,8 +653,8 @@ func DeleteListMember(domain, apiKey string) error {
 	return mg.DeleteMember(ctx, "joe@example.com", "list@example.com")
 }
 
-func DeleteMailingList(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+func DeleteMailingList(apiKey string) error {
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -663,7 +663,7 @@ func DeleteMailingList(domain, apiKey string) error {
 }
 
 func ResendMessage(domain, apiKey string) (string, string, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -672,8 +672,9 @@ func ResendMessage(domain, apiKey string) (string, string, error) {
 }
 
 func SendComplexMessage(domain, apiKey string) (string, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 	m := mailgun.NewMessage(
+		domain,
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -693,8 +694,9 @@ func SendComplexMessage(domain, apiKey string) (string, error) {
 }
 
 func SendWithConnectionOptions(domain, apiKey string) (string, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 	m := mailgun.NewMessage(
+		domain,
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -712,8 +714,9 @@ func SendWithConnectionOptions(domain, apiKey string) (string, error) {
 }
 
 func SendInlineImage(domain, apiKey string) (string, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 	m := mailgun.NewMessage(
+		domain,
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -732,8 +735,9 @@ func SendInlineImage(domain, apiKey string) (string, error) {
 }
 
 func SendMessageNoTracking(domain, apiKey string) (string, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 	m := mailgun.NewMessage(
+		domain,
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -749,7 +753,7 @@ func SendMessageNoTracking(domain, apiKey string) (string, error) {
 }
 
 func SendMimeMessage(domain, apiKey string) (string, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 	mimeMsgReader, err := os.Open("files/message.mime")
 	if err != nil {
 		return "", err
@@ -765,8 +769,9 @@ func SendMimeMessage(domain, apiKey string) (string, error) {
 }
 
 func SendScheduledMessage(domain, apiKey string) (string, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 	m := mailgun.NewMessage(
+		domain,
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -782,8 +787,9 @@ func SendScheduledMessage(domain, apiKey string) (string, error) {
 }
 
 func SendSimpleMessage(domain, apiKey string) (string, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 	m := mailgun.NewMessage(
+		domain,
 		"Excited User <mailgun@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -798,7 +804,7 @@ func SendSimpleMessage(domain, apiKey string) (string, error) {
 }
 
 func SendTaggedMessage(domain, apiKey string) (string, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 	m := mailgun.NewMessage(
 		domain,
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
@@ -820,7 +826,7 @@ func SendTaggedMessage(domain, apiKey string) (string, error) {
 }
 
 func SendTemplateMessage(domain, apiKey string) (string, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 	m := mailgun.NewMessage(
 		domain,
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
@@ -849,7 +855,7 @@ func SendTemplateMessage(domain, apiKey string) (string, error) {
 }
 
 func UpdateDomainConnection(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -860,8 +866,8 @@ func UpdateDomainConnection(domain, apiKey string) error {
 	})
 }
 
-func UpdateMember(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+func UpdateMember(apiKey string) error {
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -874,16 +880,16 @@ func UpdateMember(domain, apiKey string) error {
 }
 
 func UpdateWebhook(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.UpdateWebhook(ctx, "clicked", []string{"https://your_domain.com/clicked"})
+	return mg.UpdateWebhook(ctx, domain, "clicked", []string{"https://your_domain.com/clicked"})
 }
 
-func VerifyWebhookSignature(domain, apiKey, webhookSigningKey, timestamp, token, signature string) (bool, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+func VerifyWebhookSignature(apiKey, webhookSigningKey, timestamp, token, signature string) (bool, error) {
+	mg := mailgun.NewMailgun(apiKey)
 	mg.SetWebhookSigningKey(webhookSigningKey)
 
 	return mg.VerifyWebhookSignature(mailgun.Signature{
@@ -894,14 +900,14 @@ func VerifyWebhookSignature(domain, apiKey, webhookSigningKey, timestamp, token,
 }
 
 func SendMessageWithTemplate(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 	var err error
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
 	// Create a new template
-	err = mg.CreateTemplate(ctx, &mailgun.Template{
+	err = mg.CreateTemplate(ctx, domain, &mailgun.Template{
 		Name: "my-template",
 		Version: mailgun.TemplateVersion{
 			Template: `'<div class="entry"> <h1>{{.title}}</h1> <div class="body"> {{.body}} </div> </div>'`,
@@ -934,12 +940,12 @@ func SendMessageWithTemplate(domain, apiKey string) error {
 }
 
 func CreateTemplate(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.CreateTemplate(ctx, &mailgun.Template{
+	return mg.CreateTemplate(ctx, domain, &mailgun.Template{
 		Name: "my-template",
 		Version: mailgun.TemplateVersion{
 			Template: `'<div class="entry"> <h1>{{.title}}</h1> <div class="body"> {{.body}} </div> </div>'`,
@@ -950,38 +956,38 @@ func CreateTemplate(domain, apiKey string) error {
 }
 
 func DeleteTemplate(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.DeleteTemplate(ctx, "my-template")
+	return mg.DeleteTemplate(ctx, domain, "my-template")
 }
 
 func UpdateTemplate(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.UpdateTemplate(ctx, &mailgun.Template{
+	return mg.UpdateTemplate(ctx, domain, &mailgun.Template{
 		Name:        "my-template",
 		Description: "Add a description to the template",
 	})
 }
 
 func GetTemplate(domain, apiKey string) (mailgun.Template, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.GetTemplate(ctx, "my-template")
+	return mg.GetTemplate(ctx, domain, "my-template")
 }
 
 func ListActiveTemplates(domain, apiKey string) ([]mailgun.Template, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
-	it := mg.ListTemplates(&mailgun.ListTemplateOptions{Active: true})
+	mg := mailgun.NewMailgun(apiKey)
+	it := mg.ListTemplates(domain, &mailgun.ListTemplateOptions{Active: true})
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -998,8 +1004,8 @@ func ListActiveTemplates(domain, apiKey string) ([]mailgun.Template, error) {
 }
 
 func ListTemplates(domain, apiKey string) ([]mailgun.Template, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
-	it := mg.ListTemplates(nil)
+	mg := mailgun.NewMailgun(apiKey)
+	it := mg.ListTemplates(domain, nil)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -1016,12 +1022,12 @@ func ListTemplates(domain, apiKey string) ([]mailgun.Template, error) {
 }
 
 func AddTemplateVersion(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.AddTemplateVersion(ctx, "my-template", &mailgun.TemplateVersion{
+	return mg.AddTemplateVersion(ctx, domain, "my-template", &mailgun.TemplateVersion{
 		Template: `'<div class="entry"> <h1>{{.title}}</h1> <div class="body"> {{.body}} </div> </div>'`,
 		Engine:   mailgun.TemplateEngineGo,
 		Tag:      "v2",
@@ -1030,32 +1036,32 @@ func AddTemplateVersion(domain, apiKey string) error {
 }
 
 func DeleteTemplateVersion(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
 	// Delete the template version tagged as 'v2'
-	return mg.DeleteTemplateVersion(ctx, "my-template", "v2")
+	return mg.DeleteTemplateVersion(ctx, domain, "my-template", "v2")
 }
 
 func GetTemplateVersion(domain, apiKey string) (mailgun.TemplateVersion, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
 	// Get the template version tagged as 'v2'
-	return mg.GetTemplateVersion(ctx, "my-template", "v2")
+	return mg.GetTemplateVersion(ctx, domain, "my-template", "v2")
 }
 
 func UpdateTemplateVersion(domain, apiKey string) error {
-	mg := mailgun.NewMailgun(domain, apiKey)
+	mg := mailgun.NewMailgun(apiKey)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
 
-	return mg.UpdateTemplateVersion(ctx, "my-template", &mailgun.TemplateVersion{
+	return mg.UpdateTemplateVersion(ctx, domain, "my-template", &mailgun.TemplateVersion{
 		Comment: "Add a comment to the template and make it 'active'",
 		Tag:     "v2",
 		Active:  true,
@@ -1063,8 +1069,8 @@ func UpdateTemplateVersion(domain, apiKey string) error {
 }
 
 func ListTemplateVersions(domain, apiKey string) ([]mailgun.TemplateVersion, error) {
-	mg := mailgun.NewMailgun(domain, apiKey)
-	it := mg.ListTemplateVersions("my-template", nil)
+	mg := mailgun.NewMailgun(apiKey)
+	it := mg.ListTemplateVersions(domain, "my-template", nil)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
diff --git a/exports.go b/exports.go
index f46cdb8..dc0a4db 100644
--- a/exports.go
+++ b/exports.go
@@ -19,8 +19,8 @@ type Export struct {
 
 // Create an export based on the URL given
 func (mg *MailgunImpl) CreateExport(ctx context.Context, url string) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, exportsEndpoint))
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, exportsEndpoint))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -31,8 +31,8 @@ func (mg *MailgunImpl) CreateExport(ctx context.Context, url string) error {
 
 // List all exports created within the past 24 hours
 func (mg *MailgunImpl) ListExports(ctx context.Context, url string) ([]Export, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, exportsEndpoint))
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, exportsEndpoint))
+	r.setClient(mg.HTTPClient())
 	if url != "" {
 		r.addParameter("url", url)
 	}
@@ -52,8 +52,8 @@ func (mg *MailgunImpl) ListExports(ctx context.Context, url string) ([]Export, e
 
 // GetExport gets an export by id
 func (mg *MailgunImpl) GetExport(ctx context.Context, id string) (Export, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, exportsEndpoint) + "/" + id)
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, exportsEndpoint) + "/" + id)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	var resp Export
 	err := getResponseFromJSON(ctx, r, &resp)
@@ -63,15 +63,15 @@ func (mg *MailgunImpl) GetExport(ctx context.Context, id string) (Export, error)
 // Download an export by ID. This will respond with a '302 Moved'
 // with the Location header of temporary S3 URL if it is available.
 func (mg *MailgunImpl) GetExportLink(ctx context.Context, id string) (string, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, exportsEndpoint) + "/" + id + "/download_url")
-	c := mg.Client()
+	r := newHTTPRequest(generateApiUrl(mg, exportsEndpoint) + "/" + id + "/download_url")
+	c := mg.HTTPClient()
 
 	// Ensure the client doesn't attempt to retry
 	c.CheckRedirect = func(_ *http.Request, _ []*http.Request) error {
 		return errors.New("redirect")
 	}
 
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	r.addHeader("User-Agent", MailgunGoUserAgent)
diff --git a/ips.go b/ips.go
index a899168..6cb37fb 100644
--- a/ips.go
+++ b/ips.go
@@ -20,8 +20,8 @@ type okResp struct {
 
 // ListIPS returns a list of IPs assigned to your account
 func (mg *MailgunImpl) ListIPS(ctx context.Context, dedicated bool) ([]IPAddress, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, ipsEndpoint))
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, ipsEndpoint))
+	r.setClient(mg.HTTPClient())
 	if dedicated {
 		r.addParameter("dedicated", "true")
 	}
@@ -40,8 +40,8 @@ func (mg *MailgunImpl) ListIPS(ctx context.Context, dedicated bool) ([]IPAddress
 
 // GetIP returns information about the specified IP
 func (mg *MailgunImpl) GetIP(ctx context.Context, ip string) (IPAddress, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, ipsEndpoint) + "/" + ip)
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, ipsEndpoint) + "/" + ip)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	var resp IPAddress
 	err := getResponseFromJSON(ctx, r, &resp)
@@ -49,9 +49,9 @@ func (mg *MailgunImpl) GetIP(ctx context.Context, ip string) (IPAddress, error)
 }
 
 // ListDomainIPS returns a list of IPs currently assigned to the specified domain.
-func (mg *MailgunImpl) ListDomainIPS(ctx context.Context) ([]IPAddress, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + mg.domain + "/ips")
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) ListDomainIPS(ctx context.Context, domain string) ([]IPAddress, error) {
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/ips")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	var resp ipAddressListResponse
@@ -66,9 +66,9 @@ func (mg *MailgunImpl) ListDomainIPS(ctx context.Context) ([]IPAddress, error) {
 }
 
 // Assign a dedicated IP to the domain specified.
-func (mg *MailgunImpl) AddDomainIP(ctx context.Context, ip string) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + mg.domain + "/ips")
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) AddDomainIP(ctx context.Context, domain, ip string) error {
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/ips")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -78,9 +78,9 @@ func (mg *MailgunImpl) AddDomainIP(ctx context.Context, ip string) error {
 }
 
 // Unassign an IP from the domain specified.
-func (mg *MailgunImpl) DeleteDomainIP(ctx context.Context, ip string) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + mg.domain + "/ips/" + ip)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) DeleteDomainIP(ctx context.Context, domain, ip string) error {
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/ips/" + ip)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
diff --git a/limits.go b/limits.go
index 5ce1f38..4bff2e2 100644
--- a/limits.go
+++ b/limits.go
@@ -9,8 +9,8 @@ type TagLimits struct {
 
 // GetTagLimits returns tracking settings for a domain
 func (mg *MailgunImpl) GetTagLimits(ctx context.Context, domain string) (TagLimits, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/limits/tag")
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, domainsEndpoint) + "/" + domain + "/limits/tag")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	var resp TagLimits
 	err := getResponseFromJSON(ctx, r, &resp)
diff --git a/mailgun.go b/mailgun.go
index 421a6e0..6e8ddfd 100644
--- a/mailgun.go
+++ b/mailgun.go
@@ -121,10 +121,9 @@ const (
 // determine the currently supported feature set.
 type Mailgun interface {
 	APIBase() string
-	Domain() string
 	APIKey() string
-	Client() *http.Client
-	SetClient(client *http.Client)
+	HTTPClient() *http.Client
+	SetHTTPClient(client *http.Client)
 	SetAPIBase(url string)
 	AddOverrideHeader(k string, v string)
 
@@ -132,17 +131,17 @@ type Mailgun interface {
 	Send(ctx context.Context, m SendableMessage) (mes string, id string, err error)
 	ReSend(ctx context.Context, id string, recipients ...string) (string, string, error)
 
-	ListBounces(opts *ListOptions) *BouncesIterator
-	GetBounce(ctx context.Context, address string) (Bounce, error)
-	AddBounce(ctx context.Context, address, code, err string) error
-	DeleteBounce(ctx context.Context, address string) error
-	DeleteBounceList(ctx context.Context) error
+	ListBounces(domain string, opts *ListOptions) *BouncesIterator
+	GetBounce(ctx context.Context, domain, address string) (Bounce, error)
+	AddBounce(ctx context.Context, domain, address, code, err string) error
+	DeleteBounce(ctx context.Context, domain, address string) error
+	DeleteBounceList(ctx context.Context, domain string) error
 
 	ListMetrics(opts MetricsOptions) (*MetricsIterator, error)
 
-	GetTag(ctx context.Context, tag string) (Tag, error)
-	DeleteTag(ctx context.Context, tag string) error
-	ListTags(*ListTagOptions) *TagIterator
+	GetTag(ctx context.Context, domain, tag string) (Tag, error)
+	DeleteTag(ctx context.Context, domain, tag string) error
+	ListTags(domain string, opts *ListTagOptions) *TagIterator
 
 	ListDomains(opts *ListOptions) *DomainsIterator
 	GetDomain(ctx context.Context, domain string) (DomainResponse, error)
@@ -161,22 +160,23 @@ type Mailgun interface {
 	GetStoredMessageRaw(ctx context.Context, id string) (StoredMessageRaw, error)
 	GetStoredAttachment(ctx context.Context, url string) ([]byte, error)
 
-	ListCredentials(opts *ListOptions) *CredentialsIterator
-	CreateCredential(ctx context.Context, login, password string) error
-	ChangeCredentialPassword(ctx context.Context, login, password string) error
-	DeleteCredential(ctx context.Context, login string) error
+	ListCredentials(domain string, opts *ListOptions) *CredentialsIterator
+	CreateCredential(ctx context.Context, domain, login, password string) error
+	ChangeCredentialPassword(ctx context.Context, domain, login, password string) error
+	DeleteCredential(ctx context.Context, domain, login string) error
 
-	ListUnsubscribes(opts *ListOptions) *UnsubscribesIterator
-	GetUnsubscribe(ctx context.Context, address string) (Unsubscribe, error)
-	CreateUnsubscribe(ctx context.Context, address, tag string) error
-	CreateUnsubscribes(ctx context.Context, unsubscribes []Unsubscribe) error
-	DeleteUnsubscribe(ctx context.Context, address string) error
-	DeleteUnsubscribeWithTag(ctx context.Context, a, t string) error
+	ListUnsubscribes(domain string, opts *ListOptions) *UnsubscribesIterator
+	GetUnsubscribe(ctx context.Context, domain, address string) (Unsubscribe, error)
+	CreateUnsubscribe(ctx context.Context, domain, address, tag string) error
+	CreateUnsubscribes(ctx context.Context, domain string, unsubscribes []Unsubscribe) error
+	DeleteUnsubscribe(ctx context.Context, domain, address string) error
+	DeleteUnsubscribeWithTag(ctx context.Context, domain, a, t string) error
 
-	ListComplaints(opts *ListOptions) *ComplaintsIterator
-	GetComplaint(ctx context.Context, address string) (Complaint, error)
-	CreateComplaint(ctx context.Context, address string) error
-	DeleteComplaint(ctx context.Context, address string) error
+	ListComplaints(domain string, opts *ListOptions) *ComplaintsIterator
+	GetComplaint(ctx context.Context, domain, address string) (Complaint, error)
+	CreateComplaint(ctx context.Context, domain, address string) error
+	CreateComplaints(ctx context.Context, domain string, addresses []string) error
+	DeleteComplaint(ctx context.Context, domain, address string) error
 
 	ListRoutes(opts *ListOptions) *RoutesIterator
 	GetRoute(ctx context.Context, address string) (Route, error)
@@ -184,11 +184,11 @@ type Mailgun interface {
 	DeleteRoute(ctx context.Context, address string) error
 	UpdateRoute(ctx context.Context, address string, r Route) (Route, error)
 
-	ListWebhooks(ctx context.Context) (map[string][]string, error)
-	CreateWebhook(ctx context.Context, kind string, url []string) error
-	DeleteWebhook(ctx context.Context, kind string) error
-	GetWebhook(ctx context.Context, kind string) ([]string, error)
-	UpdateWebhook(ctx context.Context, kind string, url []string) error
+	ListWebhooks(ctx context.Context, domain string) (map[string][]string, error)
+	CreateWebhook(ctx context.Context, domain, kind string, url []string) error
+	DeleteWebhook(ctx context.Context, domain, kind string) error
+	GetWebhook(ctx context.Context, domain, kind string) ([]string, error)
+	UpdateWebhook(ctx context.Context, domain, kind string, url []string) error
 	VerifyWebhookSignature(sig Signature) (verified bool, err error)
 
 	ListMailingLists(opts *ListOptions) *ListsIterator
@@ -204,15 +204,14 @@ type Mailgun interface {
 	UpdateMember(ctx context.Context, Member, list string, prototype Member) (Member, error)
 	DeleteMember(ctx context.Context, Member, list string) error
 
-	ListEventsWithDomain(opts *ListEventOptions, domain string) *EventIterator
-	ListEvents(*ListEventOptions) *EventIterator
-	PollEvents(*ListEventOptions) *EventPoller
+	ListEvents(domain string, opts *ListEventOptions) *EventIterator
+	PollEvents(domain string, opts *ListEventOptions) *EventPoller
 
 	ListIPS(ctx context.Context, dedicated bool) ([]IPAddress, error)
 	GetIP(ctx context.Context, ip string) (IPAddress, error)
-	ListDomainIPS(ctx context.Context) ([]IPAddress, error)
-	AddDomainIP(ctx context.Context, ip string) error
-	DeleteDomainIP(ctx context.Context, ip string) error
+	ListDomainIPS(ctx context.Context, domain string) ([]IPAddress, error)
+	AddDomainIP(ctx context.Context, domain, ip string) error
+	DeleteDomainIP(ctx context.Context, domain, ip string) error
 
 	ListExports(ctx context.Context, url string) ([]Export, error)
 	GetExport(ctx context.Context, id string) (Export, error)
@@ -221,17 +220,17 @@ type Mailgun interface {
 
 	GetTagLimits(ctx context.Context, domain string) (TagLimits, error)
 
-	CreateTemplate(ctx context.Context, template *Template) error
-	GetTemplate(ctx context.Context, name string) (Template, error)
-	UpdateTemplate(ctx context.Context, template *Template) error
-	DeleteTemplate(ctx context.Context, name string) error
-	ListTemplates(opts *ListTemplateOptions) *TemplatesIterator
+	CreateTemplate(ctx context.Context, domain string, template *Template) error
+	GetTemplate(ctx context.Context, domain, name string) (Template, error)
+	UpdateTemplate(ctx context.Context, domain string, template *Template) error
+	DeleteTemplate(ctx context.Context, domain, name string) error
+	ListTemplates(domain string, opts *ListTemplateOptions) *TemplatesIterator
 
-	AddTemplateVersion(ctx context.Context, templateName string, version *TemplateVersion) error
-	GetTemplateVersion(ctx context.Context, templateName, tag string) (TemplateVersion, error)
-	UpdateTemplateVersion(ctx context.Context, templateName string, version *TemplateVersion) error
-	DeleteTemplateVersion(ctx context.Context, templateName, tag string) error
-	ListTemplateVersions(templateName string, opts *ListOptions) *TemplateVersionsIterator
+	AddTemplateVersion(ctx context.Context, domain, templateName string, version *TemplateVersion) error
+	GetTemplateVersion(ctx context.Context, domain, templateName, tag string) (TemplateVersion, error)
+	UpdateTemplateVersion(ctx context.Context, domain, templateName string, version *TemplateVersion) error
+	DeleteTemplateVersion(ctx context.Context, domain, templateName, tag string) error
+	ListTemplateVersions(domain, templateName string, opts *ListOptions) *TemplateVersionsIterator
 
 	ListSubaccounts(opts *ListSubaccountsOptions) *SubaccountsIterator
 	CreateSubaccount(ctx context.Context, subaccountName string) (SubaccountResponse, error)
@@ -247,7 +246,6 @@ type Mailgun interface {
 // Colloquially, we refer to instances of this structure as "clients."
 type MailgunImpl struct {
 	apiBase           string
-	domain            string
 	apiKey            string
 	webhookSigningKey string
 	client            *http.Client
@@ -255,29 +253,24 @@ type MailgunImpl struct {
 	overrideHeaders   map[string]string
 }
 
-// NewMailGun creates a new client instance.
-func NewMailgun(domain, apiKey string) *MailgunImpl {
+// NewMailgun creates a new client instance.
+func NewMailgun(apiKey string) *MailgunImpl {
 	return &MailgunImpl{
 		apiBase: APIBase,
-		domain:  domain,
 		apiKey:  apiKey,
 		client:  http.DefaultClient,
 	}
 }
 
 // NewMailgunFromEnv returns a new Mailgun client using the environment variables
-// MG_API_KEY, MG_DOMAIN, MG_URL, and MG_WEBHOOK_SIGNING_KEY
+// MG_API_KEY, MG_URL, and MG_WEBHOOK_SIGNING_KEY
 func NewMailgunFromEnv() (*MailgunImpl, error) {
 	apiKey := os.Getenv("MG_API_KEY")
 	if apiKey == "" {
 		return nil, errors.New("required environment variable MG_API_KEY not defined")
 	}
-	domain := os.Getenv("MG_DOMAIN")
-	if domain == "" {
-		return nil, errors.New("required environment variable MG_DOMAIN not defined")
-	}
 
-	mg := NewMailgun(domain, apiKey)
+	mg := NewMailgun(apiKey)
 
 	url := os.Getenv("MG_URL")
 	if url != "" {
@@ -297,23 +290,18 @@ func (mg *MailgunImpl) APIBase() string {
 	return mg.apiBase
 }
 
-// Domain returns the domain configured for this client.
-func (mg *MailgunImpl) Domain() string {
-	return mg.domain
-}
-
-// ApiKey returns the API key configured for this client.
+// APIKey returns the API key configured for this client.
 func (mg *MailgunImpl) APIKey() string {
 	return mg.apiKey
 }
 
-// Client returns the HTTP client configured for this client.
-func (mg *MailgunImpl) Client() *http.Client {
+// HTTPClient returns the HTTP client configured for this client.
+func (mg *MailgunImpl) HTTPClient() *http.Client {
 	return mg.client
 }
 
-// SetClient updates the HTTP client for this client.
-func (mg *MailgunImpl) SetClient(c *http.Client) {
+// SetHTTPClient updates the HTTP client for this client.
+func (mg *MailgunImpl) SetHTTPClient(c *http.Client) {
 	mg.client = c
 }
 
@@ -365,12 +353,12 @@ func (mg *MailgunImpl) AddOverrideHeader(k, v string) {
 	mg.overrideHeaders[k] = v
 }
 
-// generateApiUrl renders a URL for an API endpoint using the domain and endpoint name.
-func generateApiUrl(m Mailgun, endpoint string) string {
-	return fmt.Sprintf("%s/%s/%s", m.APIBase(), m.Domain(), endpoint)
+// ListOptions used by List methods to specify what list parameters to send to the mailgun API
+type ListOptions struct {
+	Limit int
 }
 
-// generateApiUrlWithDomain renders a URL for an API endpoint using a separate domain and endpoint name.
+// generateApiUrlWithDomain renders a URL for an API endpoint using the domain and endpoint name.
 func generateApiUrlWithDomain(m Mailgun, endpoint, domain string) string {
 	return fmt.Sprintf("%s/%s/%s", m.APIBase(), domain, endpoint)
 }
@@ -381,36 +369,36 @@ func generateMemberApiUrl(m Mailgun, endpoint, address string) string {
 	return fmt.Sprintf("%s/%s/%s/members", m.APIBase(), endpoint, address)
 }
 
-// generateApiUrlWithTarget works as generateApiUrl,
+// generateApiUrlWithTarget works as generateApiUrl
 // but consumes an additional resource parameter called 'target'.
-func generateApiUrlWithTarget(m Mailgun, endpoint, target string) string {
+func generateApiUrlWithTarget(m Mailgun, endpoint, domain, target string) string {
 	tail := ""
 	if target != "" {
 		tail = fmt.Sprintf("/%s", target)
 	}
-	return fmt.Sprintf("%s%s", generateApiUrl(m, endpoint), tail)
+	return fmt.Sprintf("%s%s", generateApiUrlWithDomain(m, endpoint, domain), tail)
 }
 
-// generateDomainApiUrl renders a URL as generateApiUrl, but
+// generateDomainsApiUrl renders a URL as generateApiUrlWithDomain, but
 // addresses a family of functions which have a non-standard URL structure.
 // Most URLs consume a domain in the 2nd position, but some endpoints
 // require the word "domains" to be there instead.
-func generateDomainApiUrl(m Mailgun, endpoint string) string {
-	return fmt.Sprintf("%s/domains/%s/%s", m.APIBase(), m.Domain(), endpoint)
+func generateDomainsApiUrl(m Mailgun, endpoint, domain string) string {
+	return fmt.Sprintf("%s/domains/%s/%s", m.APIBase(), domain, endpoint)
 }
 
-// generateCredentialsUrl renders a URL as generateDomainApiUrl,
+// generateCredentialsUrl renders a URL as generateDomainsApiUrl,
 // but focuses on the SMTP credentials family of API functions.
-func generateCredentialsUrl(m Mailgun, login string) string {
+func generateCredentialsUrl(m Mailgun, domain, login string) string {
 	tail := ""
 	if login != "" {
 		tail = fmt.Sprintf("/%s", login)
 	}
-	return generateDomainApiUrl(m, fmt.Sprintf("credentials%s", tail))
+	return generateDomainsApiUrl(m, fmt.Sprintf("credentials%s", tail), domain)
 }
 
-// generatePublicApiUrl works as generateApiUrl, except that generatePublicApiUrl has no need for the domain.
-func generatePublicApiUrl(m Mailgun, endpoint string) string {
+// generateApiUrl returns domain agnostic URL.
+func generateApiUrl(m Mailgun, endpoint string) string {
 	return fmt.Sprintf("%s/%s", m.APIBase(), endpoint)
 }
 
diff --git a/mailing_lists.go b/mailing_lists.go
index fbab6c9..ccaa0c3 100644
--- a/mailing_lists.go
+++ b/mailing_lists.go
@@ -63,8 +63,8 @@ type ListsIterator struct {
 
 // ListMailingLists returns the specified set of mailing lists administered by your account.
 func (mg *MailgunImpl) ListMailingLists(opts *ListOptions) *ListsIterator {
-	r := newHTTPRequest(generatePublicApiUrl(mg, listsEndpoint) + "/pages")
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, listsEndpoint) + "/pages")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	if opts != nil {
 		if opts.Limit != 0 {
@@ -161,7 +161,7 @@ func (li *ListsIterator) Previous(ctx context.Context, items *[]MailingList) boo
 func (li *ListsIterator) fetch(ctx context.Context, url string) error {
 	li.Items = nil
 	r := newHTTPRequest(url)
-	r.setClient(li.mg.Client())
+	r.setClient(li.mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, li.mg.APIKey())
 
 	return getResponseFromJSON(ctx, r, &li.listsResponse)
@@ -174,8 +174,8 @@ func (li *ListsIterator) fetch(ctx context.Context, url string) error {
 // while AccessLevel defaults to Everyone
 // and ReplyPreference defaults to List.
 func (mg *MailgunImpl) CreateMailingList(ctx context.Context, prototype MailingList) (MailingList, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, listsEndpoint))
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, listsEndpoint))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := newUrlEncodedPayload()
 	if prototype.Address != "" {
@@ -205,8 +205,8 @@ func (mg *MailgunImpl) CreateMailingList(ctx context.Context, prototype MailingL
 // DeleteMailingList removes all current members of the list, then removes the list itself.
 // Attempts to send e-mail to the list will fail subsequent to this call.
 func (mg *MailgunImpl) DeleteMailingList(ctx context.Context, addr string) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, listsEndpoint) + "/" + addr)
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, listsEndpoint) + "/" + addr)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
@@ -215,8 +215,8 @@ func (mg *MailgunImpl) DeleteMailingList(ctx context.Context, addr string) error
 // GetMailingList allows your application to recover the complete List structure
 // representing a mailing list, so long as you have its e-mail address.
 func (mg *MailgunImpl) GetMailingList(ctx context.Context, addr string) (MailingList, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, listsEndpoint) + "/" + addr)
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, listsEndpoint) + "/" + addr)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	response, err := makeGetRequest(ctx, r)
 	if err != nil {
@@ -236,8 +236,8 @@ func (mg *MailgunImpl) GetMailingList(ctx context.Context, addr string) (Mailing
 // e-mail sent to the old address will not succeed.
 // Make sure you account for the change accordingly.
 func (mg *MailgunImpl) UpdateMailingList(ctx context.Context, addr string, prototype MailingList) (MailingList, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, listsEndpoint) + "/" + addr)
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, listsEndpoint) + "/" + addr)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := newUrlEncodedPayload()
 	if prototype.Address != "" {
diff --git a/members.go b/members.go
index 0bd0771..2b48354 100644
--- a/members.go
+++ b/members.go
@@ -50,14 +50,9 @@ type MemberListIterator struct {
 	err error
 }
 
-// Used by List methods to specify what list parameters to send to the mailgun API
-type ListOptions struct {
-	Limit int
-}
-
 func (mg *MailgunImpl) ListMembers(address string, opts *ListOptions) *MemberListIterator {
 	r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, address) + "/pages")
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	if opts != nil {
 		if opts.Limit != 0 {
@@ -146,7 +141,7 @@ func (li *MemberListIterator) Previous(ctx context.Context, items *[]Member) boo
 func (li *MemberListIterator) fetch(ctx context.Context, url string) error {
 	li.Lists = nil
 	r := newHTTPRequest(url)
-	r.setClient(li.mg.Client())
+	r.setClient(li.mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, li.mg.APIKey())
 
 	return getResponseFromJSON(ctx, r, &li.memberListResponse)
@@ -156,7 +151,7 @@ func (li *MemberListIterator) fetch(ctx context.Context, url string) error {
 // given only their subscription e-mail address.
 func (mg *MailgunImpl) GetMember(ctx context.Context, s, l string) (Member, error) {
 	r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, l) + "/" + s)
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	response, err := makeGetRequest(ctx, r)
 	if err != nil {
@@ -177,7 +172,7 @@ func (mg *MailgunImpl) CreateMember(ctx context.Context, merge bool, addr string
 	}
 
 	r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, addr))
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := NewFormDataPayload()
 	p.addValue("upsert", yesNo(merge))
@@ -195,7 +190,7 @@ func (mg *MailgunImpl) CreateMember(ctx context.Context, merge bool, addr string
 // Address, Name, Vars, and Subscribed fields may be changed.
 func (mg *MailgunImpl) UpdateMember(ctx context.Context, s, l string, prototype Member) (Member, error) {
 	r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, l) + "/" + s)
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := NewFormDataPayload()
 	if prototype.Address != "" {
@@ -228,7 +223,7 @@ func (mg *MailgunImpl) UpdateMember(ctx context.Context, s, l string, prototype
 // DeleteMember removes the member from the list.
 func (mg *MailgunImpl) DeleteMember(ctx context.Context, member, addr string) error {
 	r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, addr) + "/" + member)
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
@@ -245,7 +240,7 @@ func (mg *MailgunImpl) DeleteMember(ctx context.Context, member, addr string) er
 // Other fields are optional, but may be set according to your needs.
 func (mg *MailgunImpl) CreateMemberList(ctx context.Context, u *bool, addr string, newMembers []any) error {
 	r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, addr) + ".json")
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := NewFormDataPayload()
 	if u != nil {
diff --git a/messages.go b/messages.go
index e5f0b1b..0acc65c 100644
--- a/messages.go
+++ b/messages.go
@@ -685,7 +685,7 @@ func (mg *MailgunImpl) Send(ctx context.Context, m SendableMessage) (mes, id str
 	}
 
 	r := newHTTPRequest(generateApiUrlWithDomain(mg, m.Endpoint(), m.Domain()))
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	// Override any HTTP headers if provided
 	for k, v := range mg.overrideHeaders {
diff --git a/messages_v5.go b/messages_v5.go
index 4342ed7..1204f44 100644
--- a/messages_v5.go
+++ b/messages_v5.go
@@ -441,7 +441,7 @@ func (mg *MailgunImpl) sendV5(ctx context.Context, m SendableMessage) (mes, id s
 	}
 
 	r := newHTTPRequest(generateApiUrlWithDomain(mg, m.Endpoint(), m.Domain()))
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	// Override any HTTP headers if provided
 	for k, v := range mg.overrideHeaders {
diff --git a/mock.go b/mock.go
index d66fd3e..4d65e9a 100644
--- a/mock.go
+++ b/mock.go
@@ -19,7 +19,7 @@ type MockServer interface {
 	Stop()
 	URL1() string
 	URL4() string
-	URL() string
+	URL3() string
 	DomainIPS() []string
 	DomainList() []DomainContainer
 	ExportList() []Export
@@ -155,13 +155,13 @@ func (ms *mockServer) URL1() string {
 	return ms.srv.URL + "/v1"
 }
 
-func (ms *mockServer) URL4() string {
-	return ms.srv.URL + "/v4"
+// URL3 returns the URL used to connect to the mock server
+func (ms *mockServer) URL3() string {
+	return ms.srv.URL + "/v3"
 }
 
-// URL returns the URL used to connect to the mock server
-func (ms *mockServer) URL() string {
-	return ms.srv.URL + "/v3"
+func (ms *mockServer) URL4() string {
+	return ms.srv.URL + "/v4"
 }
 
 func toJSON(w http.ResponseWriter, obj any) {
diff --git a/mock_messages.go b/mock_messages.go
index b0c8a6e..afb0e1d 100644
--- a/mock_messages.go
+++ b/mock_messages.go
@@ -34,7 +34,7 @@ func (ms *mockServer) createMessages(w http.ResponseWriter, r *http.Request) {
 		stored.Name = events.EventStored
 		stored.Timestamp = TimeToFloat(time.Now().UTC())
 		stored.ID = id
-		stored.Storage.URL = ms.URL() + "/se.storage.url/messages/" + id
+		stored.Storage.URL = ms.URL3() + "/se.storage.url/messages/" + id
 		stored.Storage.Key = id
 		stored.Message.Headers = events.MessageHeaders{
 			Subject:   r.FormValue("subject"),
diff --git a/routes.go b/routes.go
index e86895b..bbf2edd 100644
--- a/routes.go
+++ b/routes.go
@@ -118,7 +118,7 @@ func (mg *MailgunImpl) ListRoutes(opts *ListOptions) *RoutesIterator {
 
 	return &RoutesIterator{
 		mg:                 mg,
-		url:                generatePublicApiUrl(mg, routesEndpoint),
+		url:                generateApiUrl(mg, routesEndpoint),
 		routesListResponse: routesListResponse{TotalCount: -1},
 		limit:              limit,
 	}
@@ -245,7 +245,7 @@ func (ri *RoutesIterator) fetch(ctx context.Context, skip, limit int) error {
 	ri.Items = nil
 	r := newHTTPRequest(ri.url)
 	r.setBasicAuth(basicAuthUser, ri.mg.APIKey())
-	r.setClient(ri.mg.Client())
+	r.setClient(ri.mg.HTTPClient())
 
 	if skip != 0 {
 		r.addParameter("skip", strconv.Itoa(skip))
@@ -262,8 +262,8 @@ func (ri *RoutesIterator) fetch(ctx context.Context, skip, limit int) error {
 // only a subset of the fields influence the operation.
 // See the Route structure definition for more details.
 func (mg *MailgunImpl) CreateRoute(ctx context.Context, prototype Route) (_ignored Route, err error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, routesEndpoint))
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, routesEndpoint))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := newUrlEncodedPayload()
 	p.addValue("priority", strconv.Itoa(prototype.Priority))
@@ -284,8 +284,8 @@ func (mg *MailgunImpl) CreateRoute(ctx context.Context, prototype Route) (_ignor
 // To avoid ambiguity, Mailgun identifies the route by unique ID.
 // See the Route structure definition and the Mailgun API documentation for more details.
 func (mg *MailgunImpl) DeleteRoute(ctx context.Context, id string) error {
-	r := newHTTPRequest(generatePublicApiUrl(mg, routesEndpoint) + "/" + id)
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, routesEndpoint) + "/" + id)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
@@ -293,8 +293,8 @@ func (mg *MailgunImpl) DeleteRoute(ctx context.Context, id string) error {
 
 // GetRoute retrieves the complete route definition associated with the unique route ID.
 func (mg *MailgunImpl) GetRoute(ctx context.Context, id string) (Route, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, routesEndpoint) + "/" + id)
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, routesEndpoint) + "/" + id)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	var envelope struct {
 		Message string `json:"message"`
@@ -312,8 +312,8 @@ func (mg *MailgunImpl) GetRoute(ctx context.Context, id string) (Route, error) {
 // Only those route fields which are non-zero or non-empty are updated.
 // All other fields remain as-is.
 func (mg *MailgunImpl) UpdateRoute(ctx context.Context, id string, route Route) (Route, error) {
-	r := newHTTPRequest(generatePublicApiUrl(mg, routesEndpoint) + "/" + id)
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrl(mg, routesEndpoint) + "/" + id)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := newUrlEncodedPayload()
 	if route.Priority != 0 {
diff --git a/spam_complaints.go b/spam_complaints.go
index c7ed995..4494ace 100644
--- a/spam_complaints.go
+++ b/spam_complaints.go
@@ -25,9 +25,9 @@ type complaintsResponse struct {
 // ListComplaints returns a set of spam complaints registered against your domain.
 // Recipients of your messages can click on a link which sends feedback to Mailgun
 // indicating that the message they received is, to them, spam.
-func (mg *MailgunImpl) ListComplaints(opts *ListOptions) *ComplaintsIterator {
-	r := newHTTPRequest(generateApiUrl(mg, complaintsEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) ListComplaints(domain string, opts *ListOptions) *ComplaintsIterator {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, complaintsEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	if opts != nil {
 		if opts.Limit != 0 {
@@ -130,7 +130,7 @@ func (ci *ComplaintsIterator) Previous(ctx context.Context, items *[]Complaint)
 func (ci *ComplaintsIterator) fetch(ctx context.Context, url string) error {
 	ci.Items = nil
 	r := newHTTPRequest(url)
-	r.setClient(ci.mg.Client())
+	r.setClient(ci.mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, ci.mg.APIKey())
 
 	return getResponseFromJSON(ctx, r, &ci.complaintsResponse)
@@ -138,9 +138,9 @@ func (ci *ComplaintsIterator) fetch(ctx context.Context, url string) error {
 
 // GetComplaint returns a single complaint record filed by a recipient at the email address provided.
 // If no complaint exists, the Complaint instance returned will be empty.
-func (mg *MailgunImpl) GetComplaint(ctx context.Context, address string) (Complaint, error) {
-	r := newHTTPRequest(generateApiUrl(mg, complaintsEndpoint) + "/" + address)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) GetComplaint(ctx context.Context, domain, address string) (Complaint, error) {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, complaintsEndpoint, domain) + "/" + address)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	var c Complaint
@@ -150,9 +150,9 @@ func (mg *MailgunImpl) GetComplaint(ctx context.Context, address string) (Compla
 
 // CreateComplaint registers the specified address as a recipient who has complained of receiving spam
 // from your domain.
-func (mg *MailgunImpl) CreateComplaint(ctx context.Context, address string) error {
-	r := newHTTPRequest(generateApiUrl(mg, complaintsEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) CreateComplaint(ctx context.Context, domain, address string) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, complaintsEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := newUrlEncodedPayload()
 	p.addValue("address", address)
@@ -160,9 +160,9 @@ func (mg *MailgunImpl) CreateComplaint(ctx context.Context, address string) erro
 	return err
 }
 
-func (mg *MailgunImpl) CreateComplaints(ctx context.Context, addresses []string) error {
-	r := newHTTPRequest(generateApiUrl(mg, complaintsEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) CreateComplaints(ctx context.Context, domain string, addresses []string) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, complaintsEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	body := make([]map[string]string, len(addresses))
@@ -178,9 +178,9 @@ func (mg *MailgunImpl) CreateComplaints(ctx context.Context, addresses []string)
 
 // DeleteComplaint removes a previously registered e-mail address from the list of people who complained
 // of receiving spam from your domain.
-func (mg *MailgunImpl) DeleteComplaint(ctx context.Context, address string) error {
-	r := newHTTPRequest(generateApiUrl(mg, complaintsEndpoint) + "/" + address)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) DeleteComplaint(ctx context.Context, domain, address string) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, complaintsEndpoint, domain) + "/" + address)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
diff --git a/stored_messages.go b/stored_messages.go
index 727727f..46be347 100644
--- a/stored_messages.go
+++ b/stored_messages.go
@@ -53,7 +53,7 @@ type StoredMessageRaw struct {
 // This provides visibility into, e.g., replies to a message sent to a mailing list.
 func (mg *MailgunImpl) GetStoredMessage(ctx context.Context, url string) (StoredMessage, error) {
 	r := newHTTPRequest(url)
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	var response StoredMessage
@@ -64,7 +64,7 @@ func (mg *MailgunImpl) GetStoredMessage(ctx context.Context, url string) (Stored
 // Given a storage id resend the stored message to the specified recipients
 func (mg *MailgunImpl) ReSend(ctx context.Context, url string, recipients ...string) (msg, id string, err error) {
 	r := newHTTPRequest(url)
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := NewFormDataPayload()
@@ -91,7 +91,7 @@ func (mg *MailgunImpl) ReSend(ctx context.Context, url string, recipients ...str
 // thus delegates to the caller the required parsing.
 func (mg *MailgunImpl) GetStoredMessageRaw(ctx context.Context, url string) (StoredMessageRaw, error) {
 	r := newHTTPRequest(url)
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	r.addHeader("Accept", "message/rfc2822")
 
@@ -103,7 +103,7 @@ func (mg *MailgunImpl) GetStoredMessageRaw(ctx context.Context, url string) (Sto
 // GetStoredAttachment retrieves the raw MIME body of a received e-mail message attachment.
 func (mg *MailgunImpl) GetStoredAttachment(ctx context.Context, url string) ([]byte, error) {
 	r := newHTTPRequest(url)
-	r.setClient(mg.Client())
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	r.addHeader("Accept", "message/rfc2822")
 
diff --git a/subaccounts.go b/subaccounts.go
index 8b6bc1e..199f05b 100644
--- a/subaccounts.go
+++ b/subaccounts.go
@@ -183,7 +183,7 @@ func (ri *SubaccountsIterator) fetch(ctx context.Context, skip, limit int) error
 	ri.Items = nil
 	r := newHTTPRequest(ri.url)
 	r.setBasicAuth(basicAuthUser, ri.mg.APIKey())
-	r.setClient(ri.mg.Client())
+	r.setClient(ri.mg.HTTPClient())
 
 	if skip != 0 {
 		r.addParameter("skip", strconv.Itoa(skip))
diff --git a/tags.go b/tags.go
index 1fc7dd1..72b6c83 100644
--- a/tags.go
+++ b/tags.go
@@ -27,18 +27,18 @@ type ListTagOptions struct {
 }
 
 // DeleteTag removes all counters for a particular tag, including the tag itself.
-func (mg *MailgunImpl) DeleteTag(ctx context.Context, tag string) error {
-	r := newHTTPRequest(generateApiUrl(mg, tagsEndpoint) + "/" + tag)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) DeleteTag(ctx context.Context, domain, tag string) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, tagsEndpoint, domain) + "/" + tag)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
 }
 
 // GetTag retrieves metadata about the tag from the api
-func (mg *MailgunImpl) GetTag(ctx context.Context, tag string) (Tag, error) {
-	r := newHTTPRequest(generateApiUrl(mg, tagsEndpoint) + "/" + tag)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) GetTag(ctx context.Context, domain, tag string) (Tag, error) {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, tagsEndpoint, domain) + "/" + tag)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	var tagItem Tag
 	err := getResponseFromJSON(ctx, r, &tagItem)
@@ -57,8 +57,8 @@ func (mg *MailgunImpl) GetTag(ctx context.Context, tag string) (Tag, error) {
 //	if it.Err() != nil {
 //		log.Fatal(it.Err())
 //	}
-func (mg *MailgunImpl) ListTags(opts *ListTagOptions) *TagIterator {
-	req := newHTTPRequest(generateApiUrl(mg, tagsEndpoint))
+func (mg *MailgunImpl) ListTags(domain string, opts *ListTagOptions) *TagIterator {
+	req := newHTTPRequest(generateApiUrlWithDomain(mg, tagsEndpoint, domain))
 	if opts != nil {
 		if opts.Limit != 0 {
 			req.addParameter("limit", strconv.Itoa(opts.Limit))
@@ -158,7 +158,7 @@ func (ti *TagIterator) Err() error {
 func (ti *TagIterator) fetch(ctx context.Context, uri string) error {
 	ti.Items = nil
 	req := newHTTPRequest(uri)
-	req.setClient(ti.mg.Client())
+	req.setClient(ti.mg.HTTPClient())
 	req.setBasicAuth(basicAuthUser, ti.mg.APIKey())
 	return getResponseFromJSON(ctx, req, &ti.tagsResponse)
 }
diff --git a/template.go b/template.go
index d6317e7..ce96098 100644
--- a/template.go
+++ b/template.go
@@ -32,9 +32,9 @@ type templateListResp struct {
 }
 
 // Create a new template which can be used to attach template versions to
-func (mg *MailgunImpl) CreateTemplate(ctx context.Context, template *Template) error {
-	r := newHTTPRequest(generateApiUrl(mg, templatesEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) CreateTemplate(ctx context.Context, domain string, template *Template) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, templatesEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -68,9 +68,9 @@ func (mg *MailgunImpl) CreateTemplate(ctx context.Context, template *Template) e
 }
 
 // GetTemplate gets a template given the template name
-func (mg *MailgunImpl) GetTemplate(ctx context.Context, name string) (Template, error) {
-	r := newHTTPRequest(generateApiUrl(mg, templatesEndpoint) + "/" + name)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) GetTemplate(ctx context.Context, domain, name string) (Template, error) {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, templatesEndpoint, domain) + "/" + name)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	r.addParameter("active", "yes")
 
@@ -83,13 +83,13 @@ func (mg *MailgunImpl) GetTemplate(ctx context.Context, name string) (Template,
 }
 
 // Update the name and description of a template
-func (mg *MailgunImpl) UpdateTemplate(ctx context.Context, template *Template) error {
+func (mg *MailgunImpl) UpdateTemplate(ctx context.Context, domain string, template *Template) error {
 	if template.Name == "" {
 		return errors.New("UpdateTemplate() Template.Name cannot be empty")
 	}
 
-	r := newHTTPRequest(generateApiUrl(mg, templatesEndpoint) + "/" + template.Name)
-	r.setClient(mg.Client())
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, templatesEndpoint, domain) + "/" + template.Name)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := newUrlEncodedPayload()
 
@@ -110,9 +110,9 @@ func (mg *MailgunImpl) UpdateTemplate(ctx context.Context, template *Template) e
 }
 
 // Delete a template given a template name
-func (mg *MailgunImpl) DeleteTemplate(ctx context.Context, name string) error {
-	r := newHTTPRequest(generateApiUrl(mg, templatesEndpoint) + "/" + name)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) DeleteTemplate(ctx context.Context, domain, name string) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, templatesEndpoint, domain) + "/" + name)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
@@ -130,9 +130,9 @@ type ListTemplateOptions struct {
 }
 
 // List all available templates
-func (mg *MailgunImpl) ListTemplates(opts *ListTemplateOptions) *TemplatesIterator {
-	r := newHTTPRequest(generateApiUrl(mg, templatesEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) ListTemplates(domain string, opts *ListTemplateOptions) *TemplatesIterator {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, templatesEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	if opts != nil {
 		if opts.Limit != 0 {
@@ -232,7 +232,7 @@ func (ti *TemplatesIterator) Previous(ctx context.Context, items *[]Template) bo
 func (ti *TemplatesIterator) fetch(ctx context.Context, url string) error {
 	ti.Items = nil
 	r := newHTTPRequest(url)
-	r.setClient(ti.mg.Client())
+	r.setClient(ti.mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, ti.mg.APIKey())
 
 	return getResponseFromJSON(ctx, r, &ti.templateListResp)
diff --git a/template_versions.go b/template_versions.go
index 0581ee5..f4e50c5 100644
--- a/template_versions.go
+++ b/template_versions.go
@@ -23,9 +23,9 @@ type templateVersionListResp struct {
 }
 
 // AddTemplateVersion adds a template version to a template
-func (mg *MailgunImpl) AddTemplateVersion(ctx context.Context, templateName string, version *TemplateVersion) error {
-	r := newHTTPRequest(generateApiUrl(mg, templatesEndpoint) + "/" + templateName + "/versions")
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) AddTemplateVersion(ctx context.Context, domain, templateName string, version *TemplateVersion) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, templatesEndpoint, domain) + "/" + templateName + "/versions")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	payload := newUrlEncodedPayload()
@@ -53,9 +53,9 @@ func (mg *MailgunImpl) AddTemplateVersion(ctx context.Context, templateName stri
 }
 
 // GetTemplateVersion gets a specific version of a template
-func (mg *MailgunImpl) GetTemplateVersion(ctx context.Context, templateName, tag string) (TemplateVersion, error) {
-	r := newHTTPRequest(generateApiUrl(mg, templatesEndpoint) + "/" + templateName + "/versions/" + tag)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) GetTemplateVersion(ctx context.Context, domain, templateName, tag string) (TemplateVersion, error) {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, templatesEndpoint, domain) + "/" + templateName + "/versions/" + tag)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	var resp templateResp
@@ -67,9 +67,9 @@ func (mg *MailgunImpl) GetTemplateVersion(ctx context.Context, templateName, tag
 }
 
 // Update the comment and mark a version of a template active
-func (mg *MailgunImpl) UpdateTemplateVersion(ctx context.Context, templateName string, version *TemplateVersion) error {
-	r := newHTTPRequest(generateApiUrl(mg, templatesEndpoint) + "/" + templateName + "/versions/" + version.Tag)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) UpdateTemplateVersion(ctx context.Context, domain, templateName string, version *TemplateVersion) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, templatesEndpoint, domain) + "/" + templateName + "/versions/" + version.Tag)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := newUrlEncodedPayload()
 
@@ -93,9 +93,9 @@ func (mg *MailgunImpl) UpdateTemplateVersion(ctx context.Context, templateName s
 }
 
 // Delete a specific version of a template
-func (mg *MailgunImpl) DeleteTemplateVersion(ctx context.Context, templateName, tag string) error {
-	r := newHTTPRequest(generateApiUrl(mg, templatesEndpoint) + "/" + templateName + "/versions/" + tag)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) DeleteTemplateVersion(ctx context.Context, domain, templateName, tag string) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, templatesEndpoint, domain) + "/" + templateName + "/versions/" + tag)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
@@ -107,10 +107,10 @@ type TemplateVersionsIterator struct {
 	err error
 }
 
-// List all the versions of a specific template
-func (mg *MailgunImpl) ListTemplateVersions(templateName string, opts *ListOptions) *TemplateVersionsIterator {
-	r := newHTTPRequest(generateApiUrl(mg, templatesEndpoint) + "/" + templateName + "/versions")
-	r.setClient(mg.Client())
+// ListTemplateVersions lists all the versions of a specific template
+func (mg *MailgunImpl) ListTemplateVersions(domain, templateName string, opts *ListOptions) *TemplateVersionsIterator {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, templatesEndpoint, domain) + "/" + templateName + "/versions")
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	if opts != nil {
 		if opts.Limit != 0 {
@@ -207,7 +207,7 @@ func (li *TemplateVersionsIterator) Previous(ctx context.Context, items *[]Templ
 func (li *TemplateVersionsIterator) fetch(ctx context.Context, url string) error {
 	li.Template.Versions = nil
 	r := newHTTPRequest(url)
-	r.setClient(li.mg.Client())
+	r.setClient(li.mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, li.mg.APIKey())
 
 	return getResponseFromJSON(ctx, r, &li.templateVersionListResp)
diff --git a/unsubscribes.go b/unsubscribes.go
index 991663c..019b5c4 100644
--- a/unsubscribes.go
+++ b/unsubscribes.go
@@ -18,9 +18,9 @@ type unsubscribesResponse struct {
 }
 
 // Fetches the list of unsubscribes
-func (mg *MailgunImpl) ListUnsubscribes(opts *ListOptions) *UnsubscribesIterator {
-	r := newHTTPRequest(generateApiUrl(mg, unsubscribesEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) ListUnsubscribes(domain string, opts *ListOptions) *UnsubscribesIterator {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, unsubscribesEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	if opts != nil {
 		if opts.Limit != 0 {
@@ -123,16 +123,16 @@ func (ci *UnsubscribesIterator) Previous(ctx context.Context, items *[]Unsubscri
 func (ci *UnsubscribesIterator) fetch(ctx context.Context, url string) error {
 	ci.Items = nil
 	r := newHTTPRequest(url)
-	r.setClient(ci.mg.Client())
+	r.setClient(ci.mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, ci.mg.APIKey())
 
 	return getResponseFromJSON(ctx, r, &ci.unsubscribesResponse)
 }
 
 // Retreives a single unsubscribe record. Can be used to check if a given address is present in the list of unsubscribed users.
-func (mg *MailgunImpl) GetUnsubscribe(ctx context.Context, address string) (Unsubscribe, error) {
-	r := newHTTPRequest(generateApiUrlWithTarget(mg, unsubscribesEndpoint, address))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) GetUnsubscribe(ctx context.Context, domain, address string) (Unsubscribe, error) {
+	r := newHTTPRequest(generateApiUrlWithTarget(mg, unsubscribesEndpoint, domain, address))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	envelope := Unsubscribe{}
@@ -142,9 +142,9 @@ func (mg *MailgunImpl) GetUnsubscribe(ctx context.Context, address string) (Unsu
 }
 
 // Unsubscribe adds an e-mail address to the domain's unsubscription table.
-func (mg *MailgunImpl) CreateUnsubscribe(ctx context.Context, address, tag string) error {
-	r := newHTTPRequest(generateApiUrl(mg, unsubscribesEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) CreateUnsubscribe(ctx context.Context, domain, address, tag string) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, unsubscribesEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := newUrlEncodedPayload()
 	p.addValue("address", address)
@@ -154,9 +154,9 @@ func (mg *MailgunImpl) CreateUnsubscribe(ctx context.Context, address, tag strin
 }
 
 // CreateUnsubscribes adds multiple e-mail addresses to the domain's unsubscription table.
-func (mg *MailgunImpl) CreateUnsubscribes(ctx context.Context, unsubscribes []Unsubscribe) error {
-	r := newHTTPRequest(generateApiUrl(mg, unsubscribesEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) CreateUnsubscribes(ctx context.Context, domain string, unsubscribes []Unsubscribe) error {
+	r := newHTTPRequest(generateApiUrlWithDomain(mg, unsubscribesEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	r.addHeader("Content-Type", "application/json")
 
@@ -168,9 +168,9 @@ func (mg *MailgunImpl) CreateUnsubscribes(ctx context.Context, unsubscribes []Un
 // DeleteUnsubscribe removes the e-mail address given from the domain's unsubscription table.
 // If passing in an ID (discoverable from, e.g., ListUnsubscribes()), the e-mail address associated
 // with the given ID will be removed.
-func (mg *MailgunImpl) DeleteUnsubscribe(ctx context.Context, address string) error {
-	r := newHTTPRequest(generateApiUrlWithTarget(mg, unsubscribesEndpoint, address))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) DeleteUnsubscribe(ctx context.Context, domain, address string) error {
+	r := newHTTPRequest(generateApiUrlWithTarget(mg, unsubscribesEndpoint, domain, address))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
@@ -179,9 +179,9 @@ func (mg *MailgunImpl) DeleteUnsubscribe(ctx context.Context, address string) er
 // DeleteUnsubscribeWithTag removes the e-mail address given from the domain's unsubscription table with a matching tag.
 // If passing in an ID (discoverable from, e.g., ListUnsubscribes()), the e-mail address associated
 // with the given ID will be removed.
-func (mg *MailgunImpl) DeleteUnsubscribeWithTag(ctx context.Context, a, t string) error {
-	r := newHTTPRequest(generateApiUrlWithTarget(mg, unsubscribesEndpoint, a))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) DeleteUnsubscribeWithTag(ctx context.Context, domain, a, t string) error {
+	r := newHTTPRequest(generateApiUrlWithTarget(mg, unsubscribesEndpoint, domain, a))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	r.addParameter("tag", t)
 	_, err := makeDeleteRequest(ctx, r)
diff --git a/version.go b/version.go
index 84a8698..b847176 100644
--- a/version.go
+++ b/version.go
@@ -2,4 +2,4 @@ package mailgun
 
 // Version of current release
 // TODO(vtopc): automate this
-const Version = "4.18.5"
+const Version = "5.0.0-rc1"
diff --git a/webhooks.go b/webhooks.go
index ce951fc..2bbfe52 100644
--- a/webhooks.go
+++ b/webhooks.go
@@ -29,9 +29,9 @@ type WebHookResponse struct {
 
 // ListWebhooks returns the complete set of webhooks configured for your domain.
 // Note that a zero-length mapping is not an error.
-func (mg *MailgunImpl) ListWebhooks(ctx context.Context) (map[string][]string, error) {
-	r := newHTTPRequest(generateDomainApiUrl(mg, webhooksEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) ListWebhooks(ctx context.Context, domain string) (map[string][]string, error) {
+	r := newHTTPRequest(generateDomainsApiUrl(mg, webhooksEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 
 	var body WebHooksListResponse
@@ -53,9 +53,9 @@ func (mg *MailgunImpl) ListWebhooks(ctx context.Context) (map[string][]string, e
 }
 
 // CreateWebhook installs a new webhook for your domain.
-func (mg *MailgunImpl) CreateWebhook(ctx context.Context, id string, urls []string) error {
-	r := newHTTPRequest(generateDomainApiUrl(mg, webhooksEndpoint))
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) CreateWebhook(ctx context.Context, domain, id string, urls []string) error {
+	r := newHTTPRequest(generateDomainsApiUrl(mg, webhooksEndpoint, domain))
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := newUrlEncodedPayload()
 	p.addValue("id", id)
@@ -67,18 +67,18 @@ func (mg *MailgunImpl) CreateWebhook(ctx context.Context, id string, urls []stri
 }
 
 // DeleteWebhook removes the specified webhook from your domain's configuration.
-func (mg *MailgunImpl) DeleteWebhook(ctx context.Context, name string) error {
-	r := newHTTPRequest(generateDomainApiUrl(mg, webhooksEndpoint) + "/" + name)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) DeleteWebhook(ctx context.Context, domain, name string) error {
+	r := newHTTPRequest(generateDomainsApiUrl(mg, webhooksEndpoint, domain) + "/" + name)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	_, err := makeDeleteRequest(ctx, r)
 	return err
 }
 
 // GetWebhook retrieves the currently assigned webhook URL associated with the provided type of webhook.
-func (mg *MailgunImpl) GetWebhook(ctx context.Context, name string) ([]string, error) {
-	r := newHTTPRequest(generateDomainApiUrl(mg, webhooksEndpoint) + "/" + name)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) GetWebhook(ctx context.Context, domain, name string) ([]string, error) {
+	r := newHTTPRequest(generateDomainsApiUrl(mg, webhooksEndpoint, domain) + "/" + name)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	var body WebHookResponse
 	if err := getResponseFromJSON(ctx, r, &body); err != nil {
@@ -95,9 +95,9 @@ func (mg *MailgunImpl) GetWebhook(ctx context.Context, name string) ([]string, e
 }
 
 // UpdateWebhook replaces one webhook setting for another.
-func (mg *MailgunImpl) UpdateWebhook(ctx context.Context, name string, urls []string) error {
-	r := newHTTPRequest(generateDomainApiUrl(mg, webhooksEndpoint) + "/" + name)
-	r.setClient(mg.Client())
+func (mg *MailgunImpl) UpdateWebhook(ctx context.Context, domain, name string, urls []string) error {
+	r := newHTTPRequest(generateDomainsApiUrl(mg, webhooksEndpoint, domain) + "/" + name)
+	r.setClient(mg.HTTPClient())
 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 	p := newUrlEncodedPayload()
 	for _, url := range urls {


Test patch:
diff --git a/acceptance_test.go b/acceptance_test.go
index 5148b92..2b4602f 100644
--- a/acceptance_test.go
+++ b/acceptance_test.go
@@ -8,7 +8,7 @@ import (
 
 // Return the variable missing which caused the test to be skipped
 func SkipNetworkTest() string {
-	for _, env := range []string{"MG_DOMAIN", "MG_API_KEY", "MG_EMAIL_TO", "MG_PUBLIC_API_KEY"} {
+	for _, env := range []string{"MG_DOMAIN", "MG_API_KEY", "MG_EMAIL_TO"} {
 		if os.Getenv(env) == "" {
 			return fmt.Sprintf("'%s' missing from environment skipping...", env)
 		}
diff --git a/analytics_test.go b/analytics_test.go
index 1de81e0..abe86d9 100644
--- a/analytics_test.go
+++ b/analytics_test.go
@@ -10,7 +10,7 @@ import (
 )
 
 func TestListMetrics(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
+	mg := mailgun.NewMailgun(testKey)
 	mg.SetAPIBase(server.URL1())
 
 	start, _ := mailgun.NewRFC2822Time("Tue, 24 Sep 2024 00:00:00 +0000")
@@ -23,6 +23,12 @@ func TestListMetrics(t *testing.T) {
 			Limit: 10,
 		},
 	}
+	// filter by domain
+	opts.Filter.BoolGroupAnd = []mailgun.MetricsFilterPredicate{{
+		Attribute:     "domain",
+		Comparator:    "=",
+		LabeledValues: []mailgun.MetricsLabeledValue{{Label: testDomain, Value: testDomain}},
+	}}
 
 	wantResp := mailgun.MetricsResponse{
 		Start:      start,
diff --git a/attachments_test.go b/attachments_test.go
index e307b08..8e1de0a 100644
--- a/attachments_test.go
+++ b/attachments_test.go
@@ -26,8 +26,8 @@ func createAttachment(t *testing.T) string {
 }
 
 func TestMultipleAttachments(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	var ctx = context.Background()
 
@@ -56,7 +56,7 @@ func TestMultipleAttachments(t *testing.T) {
 }
 
 func findAcceptedMessage(mg mailgun.Mailgun, id string) (*events.Accepted, error) {
-	it := mg.ListEvents(nil)
+	it := mg.ListEvents(testDomain, nil)
 
 	var page []mailgun.Event
 	for it.Next(context.Background(), &page) {
diff --git a/bounces_test.go b/bounces_test.go
index 18cf064..048311c 100644
--- a/bounces_test.go
+++ b/bounces_test.go
@@ -14,11 +14,11 @@ import (
 )
 
 func TestGetBounces(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
-	it := mg.ListBounces(nil)
+	it := mg.ListBounces(testDomain, nil)
 
 	var page []mailgun.Bounce
 	for it.Next(ctx, &page) {
@@ -30,13 +30,13 @@ func TestGetBounces(t *testing.T) {
 }
 
 func TestGetSingleBounce(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 	exampleEmail := fmt.Sprintf("%s@%s", strings.ToLower(randomString(64, "")),
 		os.Getenv("MG_DOMAIN"))
-	_, err := mg.GetBounce(ctx, exampleEmail)
+	_, err := mg.GetBounce(ctx, testDomain, exampleEmail)
 	require.NotNil(t, err)
 
 	var ure *mailgun.UnexpectedResponseError
@@ -45,12 +45,12 @@ func TestGetSingleBounce(t *testing.T) {
 }
 
 func TestAddDelBounces(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	findBounce := func(address string) bool {
-		it := mg.ListBounces(nil)
+		it := mg.ListBounces(testDomain, nil)
 		var page []mailgun.Bounce
 		for it.Next(ctx, &page) {
 			require.True(t, len(page) != 0)
@@ -71,7 +71,7 @@ func TestAddDelBounces(t *testing.T) {
 	exampleEmail := fmt.Sprintf("%s@%s", strings.ToLower(randomString(8, "bounce")), domain)
 
 	// Add the bounce for our address.
-	err := mg.AddBounce(ctx, exampleEmail, "550", "TestAddDelBounces-generated error")
+	err := mg.AddBounce(ctx, testDomain, exampleEmail, "550", "TestAddDelBounces-generated error")
 	require.NoError(t, err)
 
 	// Give API some time to refresh cache
@@ -82,7 +82,7 @@ func TestAddDelBounces(t *testing.T) {
 		t.Fatalf("Expected bounce for address %s in list of bounces", exampleEmail)
 	}
 
-	bounce, err := mg.GetBounce(ctx, exampleEmail)
+	bounce, err := mg.GetBounce(ctx, testDomain, exampleEmail)
 	require.NoError(t, err)
 	if bounce.Address != exampleEmail {
 		t.Fatalf("Expected at least one bounce for %s", exampleEmail)
@@ -90,7 +90,7 @@ func TestAddDelBounces(t *testing.T) {
 	t.Logf("Bounce Created At: %s", bounce.CreatedAt)
 
 	// Delete it.  This should put us back the way we were.
-	err = mg.DeleteBounce(ctx, exampleEmail)
+	err = mg.DeleteBounce(ctx, testDomain, exampleEmail)
 	require.NoError(t, err)
 
 	// Make sure we're back to the way we were.
@@ -98,18 +98,18 @@ func TestAddDelBounces(t *testing.T) {
 		t.Fatalf("Un-expected bounce for address %s in list of bounces", exampleEmail)
 	}
 
-	_, err = mg.GetBounce(ctx, exampleEmail)
+	_, err = mg.GetBounce(ctx, testDomain, exampleEmail)
 	require.NotNil(t, err)
 }
 
 func TestAddDelBounceList(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 
 	findBounce := func(address string) bool {
-		it := mg.ListBounces(nil)
+		it := mg.ListBounces(testDomain, nil)
 		var page []mailgun.Bounce
 		for it.Next(ctx, &page) {
 			require.True(t, len(page) != 0)
@@ -147,7 +147,7 @@ func TestAddDelBounceList(t *testing.T) {
 	}
 
 	// Add the bounce for our address.
-	err = mg.AddBounces(ctx, bounces)
+	err = mg.AddBounces(ctx, testDomain, bounces)
 	require.NoError(t, err)
 
 	for _, expect := range bounces {
@@ -155,7 +155,7 @@ func TestAddDelBounceList(t *testing.T) {
 			t.Fatalf("Expected bounce for address %s in list of bounces", expect.Address)
 		}
 
-		bounce, err := mg.GetBounce(ctx, expect.Address)
+		bounce, err := mg.GetBounce(ctx, testDomain, expect.Address)
 		require.NoError(t, err)
 		if bounce.Address != expect.Address {
 			t.Fatalf("Expected at least one bounce for %s", expect.Address)
@@ -167,10 +167,10 @@ func TestAddDelBounceList(t *testing.T) {
 	}
 
 	// Delete the bounce list.  This should put us back the way we were.
-	err = mg.DeleteBounceList(ctx)
+	err = mg.DeleteBounceList(ctx, testDomain)
 	require.NoError(t, err)
 
-	it := mg.ListBounces(nil)
+	it := mg.ListBounces(testDomain, nil)
 	var page []mailgun.Bounce
 	if it.Next(ctx, &page) {
 		t.Fatalf("Expected no item in the bounce list")
diff --git a/credentials_test.go b/credentials_test.go
index e0b29e1..4accc29 100644
--- a/credentials_test.go
+++ b/credentials_test.go
@@ -11,11 +11,11 @@ import (
 )
 
 func TestGetCredentials(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
-	it := mg.ListCredentials(nil)
+	it := mg.ListCredentials(testDomain, nil)
 
 	var page []mailgun.Credential
 	for it.Next(ctx, &page) {
@@ -28,15 +28,15 @@ func TestGetCredentials(t *testing.T) {
 }
 
 func TestCreateDeleteCredentials(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	randomPassword := randomString(16, "pw")
 	randomID := strings.ToLower(randomString(16, "usr"))
 	randomLogin := fmt.Sprintf("%s@%s", randomID, testDomain)
 
 	ctx := context.Background()
-	require.NoError(t, mg.CreateCredential(ctx, randomLogin, randomPassword))
-	require.NoError(t, mg.ChangeCredentialPassword(ctx, randomID, randomString(16, "pw2")))
-	require.NoError(t, mg.DeleteCredential(ctx, randomID))
+	require.NoError(t, mg.CreateCredential(ctx, testDomain, randomLogin, randomPassword))
+	require.NoError(t, mg.ChangeCredentialPassword(ctx, testDomain, randomID, randomString(16, "pw2")))
+	require.NoError(t, mg.DeleteCredential(ctx, testDomain, randomID))
 }
diff --git a/domains_test.go b/domains_test.go
index fc459ed..87388b1 100644
--- a/domains_test.go
+++ b/domains_test.go
@@ -17,8 +17,8 @@ const (
 )
 
 func TestListDomains(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	it := mg.ListDomains(nil)
@@ -34,8 +34,8 @@ func TestListDomains(t *testing.T) {
 }
 
 func TestGetSingleDomain(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	it := mg.ListDomains(nil)
@@ -58,8 +58,8 @@ func TestGetSingleDomain(t *testing.T) {
 }
 
 func TestGetSingleDomainNotExist(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 	_, err := mg.GetDomain(ctx, "unknown.domain")
@@ -72,8 +72,8 @@ func TestGetSingleDomainNotExist(t *testing.T) {
 }
 
 func TestAddUpdateDeleteDomain(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	// First, we need to add the domain.
@@ -91,8 +91,8 @@ func TestAddUpdateDeleteDomain(t *testing.T) {
 }
 
 func TestDomainConnection(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	info, err := mg.GetDomainConnection(ctx, testDomain)
@@ -112,8 +112,8 @@ func TestDomainConnection(t *testing.T) {
 }
 
 func TestDomainTracking(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	info, err := mg.GetDomainTracking(ctx, testDomain)
@@ -153,8 +153,8 @@ func TestDomainTracking(t *testing.T) {
 }
 
 func TestDomainVerify(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	_, err := mg.VerifyDomain(ctx, testDomain)
@@ -162,8 +162,8 @@ func TestDomainVerify(t *testing.T) {
 }
 
 func TestDomainVerifyAndReturn(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	_, err := mg.VerifyAndReturnDomain(ctx, testDomain)
@@ -171,8 +171,8 @@ func TestDomainVerifyAndReturn(t *testing.T) {
 }
 
 func TestDomainDkimSelector(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	// Update Domain DKIM selector
@@ -181,8 +181,8 @@ func TestDomainDkimSelector(t *testing.T) {
 }
 
 func TestDomainTrackingWebPrefix(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	// Update Domain Tracking Web Prefix
diff --git a/events_test.go b/events_test.go
index a8eeb3e..6589c09 100644
--- a/events_test.go
+++ b/events_test.go
@@ -13,10 +13,10 @@ import (
 )
 
 func TestEventIteratorGetNext(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
-	it := mg.ListEvents(&mailgun.ListEventOptions{Limit: 5})
+	it := mg.ListEvents(testDomain, &mailgun.ListEventOptions{Limit: 5})
 
 	var firstPage, secondPage, previousPage []mailgun.Event
 	var ctx = context.Background()
@@ -62,11 +62,11 @@ func TestEventIteratorGetNext(t *testing.T) {
 }
 
 func TestEventPoller(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	// Very short poll interval
-	it := mg.PollEvents(&mailgun.ListEventOptions{
+	it := mg.PollEvents(testDomain, &mailgun.ListEventOptions{
 		// Only events with a timestamp after this date/time will be returned
 		Begin: time.Now().Add(time.Second * -3),
 		// How often we poll the api for new events
@@ -112,10 +112,10 @@ func TestEventPoller(t *testing.T) {
 }
 
 func ExampleMailgunImpl_ListEvents() {
-	mg := mailgun.NewMailgun("your-domain.com", "your-api-key")
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun("your-api-key")
+	mg.SetAPIBase(server.URL3())
 
-	it := mg.ListEvents(&mailgun.ListEventOptions{Limit: 100})
+	it := mg.ListEvents("your-domain.com", &mailgun.ListEventOptions{Limit: 100})
 
 	var page []mailgun.Event
 
diff --git a/examples_test.go b/examples_test.go
index aefd03c..8bdfd69 100644
--- a/examples_test.go
+++ b/examples_test.go
@@ -16,7 +16,7 @@ import (
 )
 
 func ExampleEmailValidatorImpl_ValidateEmail() {
-	v := mailgun.NewEmailValidator("my_public_validation_api_key")
+	v := mailgun.NewEmailValidator("my_private_api_key")
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
 	defer cancel()
@@ -36,7 +36,7 @@ func ExampleEmailValidatorImpl_ValidateEmail() {
 }
 
 func ExampleMailgunImpl_UpdateMailingList() {
-	mg := mailgun.NewMailgun("example.com", "my_api_key")
+	mg := mailgun.NewMailgun("my_api_key")
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
 	defer cancel()
@@ -51,12 +51,13 @@ func ExampleMailgunImpl_UpdateMailingList() {
 }
 
 func ExampleMailgunImpl_Send_constructed() {
-	mg := mailgun.NewMailgun("example.com", "my_api_key")
+	mg := mailgun.NewMailgun("my_api_key")
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
 	defer cancel()
 
 	m := mailgun.NewMessage(
+		"example.com",
 		"Excited User <me@example.com>",
 		"Hello World",
 		"Testing some Mailgun Awesomeness!",
@@ -87,7 +88,7 @@ Testing some Mailgun MIME awesomeness!
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
 	defer cancel()
 
-	mg := mailgun.NewMailgun("example.com", "my_api_key")
+	mg := mailgun.NewMailgun("my_api_key")
 	m := mailgun.NewMIMEMessage("example.com", io.NopCloser(strings.NewReader(exampleMime)), "bargle.garf@example.com")
 	_, id, err := mg.Send(ctx, m)
 	if err != nil {
@@ -97,7 +98,7 @@ Testing some Mailgun MIME awesomeness!
 }
 
 func ExampleMailgunImpl_ListRoutes() {
-	mg := mailgun.NewMailgun("example.com", "my_api_key")
+	mg := mailgun.NewMailgun("my_api_key")
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
 	defer cancel()
 
diff --git a/exports_test.go b/exports_test.go
index c66fb93..0fe9cf6 100644
--- a/exports_test.go
+++ b/exports_test.go
@@ -10,8 +10,8 @@ import (
 )
 
 func TestExports(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 	list, err := mg.ListExports(ctx, "")
@@ -37,8 +37,8 @@ func TestExports(t *testing.T) {
 }
 
 func TestExportsLink(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 	url, err := mg.GetExportLink(ctx, "12")
diff --git a/integration_test.go b/integration_test.go
index f91d6db..ca81f4e 100644
--- a/integration_test.go
+++ b/integration_test.go
@@ -6,6 +6,7 @@ import (
 	"context"
 	"encoding/json"
 	"net/http"
+	"os"
 	"testing"
 	"time"
 
@@ -20,6 +21,9 @@ func TestIntegrationMailgunImpl_ListMetrics(t *testing.T) {
 		require.NoError(t, err)
 	}
 
+	domain := os.Getenv("MG_DOMAIN")
+	require.NotEmpty(t, domain)
+
 	opts := mailgun.MetricsOptions{
 		End:      mailgun.RFC2822Time(time.Now().UTC()),
 		Duration: "30d",
@@ -27,6 +31,12 @@ func TestIntegrationMailgunImpl_ListMetrics(t *testing.T) {
 			Limit: 10,
 		},
 	}
+	// filter by domain
+	opts.Filter.BoolGroupAnd = []mailgun.MetricsFilterPredicate{{
+		Attribute:     "domain",
+		Comparator:    "=",
+		LabeledValues: []mailgun.MetricsLabeledValue{{Label: domain, Value: domain}},
+	}}
 
 	iter, err := mg.ListMetrics(opts)
 	require.NoError(t, err)
@@ -67,11 +77,14 @@ func TestIntegrationWebhooksCRUD(t *testing.T) {
 		require.NoError(t, err)
 	}
 
+	domain := os.Getenv("MG_DOMAIN")
+	require.NotEmpty(t, domain)
+
 	const name = "permanent_fail"
 	ctx := context.Background()
 	urls := []string{"https://example.com/1", "https://example.com/2"}
 
-	err = mg.DeleteWebhook(ctx, name)
+	err = mg.DeleteWebhook(ctx, domain, name)
 	if err != nil {
 		// 200 or 404 is expected
 		status := mailgun.GetStatusFromErr(err)
@@ -81,18 +94,18 @@ func TestIntegrationWebhooksCRUD(t *testing.T) {
 
 	defer func() {
 		// Cleanup
-		_ = mg.DeleteWebhook(ctx, name)
+		_ = mg.DeleteWebhook(ctx, domain, name)
 	}()
 
 	// Act
 
-	err = mg.CreateWebhook(ctx, name, urls)
+	err = mg.CreateWebhook(ctx, domain, name, urls)
 	require.NoError(t, err)
 	time.Sleep(3 * time.Second)
 
 	// Assert
 
-	gotUrls, err := mg.GetWebhook(ctx, name)
+	gotUrls, err := mg.GetWebhook(ctx, domain, name)
 	require.NoError(t, err)
 	t.Logf("Webhooks: %v", urls)
 	assert.ElementsMatch(t, urls, gotUrls)
diff --git a/ips_test.go b/ips_test.go
index 4c1d200..fa4fd03 100644
--- a/ips_test.go
+++ b/ips_test.go
@@ -20,8 +20,8 @@ func TestMain(m *testing.M) {
 }
 
 func TestListIPS(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 	list, err := mg.ListIPS(ctx, false)
@@ -37,23 +37,23 @@ func TestListIPS(t *testing.T) {
 }
 
 func TestDomainIPS(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
-	err := mg.AddDomainIP(ctx, "192.172.1.1")
+	err := mg.AddDomainIP(ctx, testDomain, "192.172.1.1")
 	require.NoError(t, err)
 
-	list, err := mg.ListDomainIPS(ctx)
+	list, err := mg.ListDomainIPS(ctx, testDomain)
 	require.NoError(t, err)
 
 	require.Len(t, list, 1)
 	require.Equal(t, "192.172.1.1", list[0].IP)
 
-	err = mg.DeleteDomainIP(ctx, "192.172.1.1")
+	err = mg.DeleteDomainIP(ctx, testDomain, "192.172.1.1")
 	require.NoError(t, err)
 
-	list, err = mg.ListDomainIPS(ctx)
+	list, err = mg.ListDomainIPS(ctx, testDomain)
 	require.NoError(t, err)
 
 	require.Len(t, list, 0)
diff --git a/limits_test.go b/limits_test.go
index 347284d..32642ad 100644
--- a/limits_test.go
+++ b/limits_test.go
@@ -10,8 +10,8 @@ import (
 )
 
 func TestLimits(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 	limits, err := mg.GetTagLimits(ctx, testDomain)
diff --git a/mailgun_test.go b/mailgun_test.go
index 2fc30be..d3ff512 100644
--- a/mailgun_test.go
+++ b/mailgun_test.go
@@ -17,19 +17,18 @@ const domain = "valid-mailgun-domain"
 const apiKey = "valid-mailgun-api-key" //nolint:gosec // This is a test
 
 func TestMailgun(t *testing.T) {
-	m := mailgun.NewMailgun(domain, apiKey)
+	m := mailgun.NewMailgun(apiKey)
 
-	assert.Equal(t, domain, m.Domain())
 	assert.Equal(t, apiKey, m.APIKey())
-	assert.Equal(t, http.DefaultClient, m.Client())
+	assert.Equal(t, http.DefaultClient, m.HTTPClient())
 
 	client := new(http.Client)
-	m.SetClient(client)
-	assert.Equal(t, m.Client(), client)
+	m.SetHTTPClient(client)
+	assert.Equal(t, m.HTTPClient(), client)
 }
 
 func TestInvalidBaseAPI(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
+	mg := mailgun.NewMailgun(testKey)
 	mg.SetAPIBase("https://localhost")
 
 	ctx := context.Background()
@@ -53,7 +52,7 @@ func TestValidBaseAPI(t *testing.T) {
 	}
 
 	for _, apiBase := range apiBases {
-		mg := mailgun.NewMailgun(testDomain, testKey)
+		mg := mailgun.NewMailgun(testKey)
 		mg.SetAPIBase(apiBase)
 
 		ctx := context.Background()
diff --git a/mailing_lists_test.go b/mailing_lists_test.go
index c18f40e..4d27cdc 100644
--- a/mailing_lists_test.go
+++ b/mailing_lists_test.go
@@ -11,8 +11,8 @@ import (
 )
 
 func TestMailingListMembers(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 	address := randomEmail("list", testDomain)
@@ -95,8 +95,8 @@ func TestMailingListMembers(t *testing.T) {
 }
 
 func TestMailingLists(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	address := randomEmail("list", testDomain)
@@ -151,8 +151,8 @@ func TestMailingLists(t *testing.T) {
 }
 
 func TestListMailingListRegression(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 	address := "test@example.com"
 
diff --git a/messages_test.go b/messages_test.go
index a49b012..aae656c 100644
--- a/messages_test.go
+++ b/messages_test.go
@@ -309,7 +309,7 @@ func TestSendMGOffline(t *testing.T) {
 	}))
 	defer srv.Close()
 
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
+	mg := mailgun.NewMailgun(exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 	ctx := context.Background()
 
@@ -342,7 +342,7 @@ func TestSendMGSeparateDomain(t *testing.T) {
 	}))
 	defer srv.Close()
 
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
+	mg := mailgun.NewMailgun(exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 
 	ctx := context.Background()
@@ -396,7 +396,7 @@ func TestSendMGMessageVariables(t *testing.T) {
 	}))
 	defer srv.Close()
 
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
+	mg := mailgun.NewMailgun(exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 
 	m := mailgun.NewMessage(exampleDomain, fromUser, exampleSubject, exampleText, toUser)
@@ -468,7 +468,7 @@ func TestSendDomainError(t *testing.T) {
 
 	for _, c := range cases {
 		ctx := context.Background()
-		mg := mailgun.NewMailgun(c.domain, exampleAPIKey)
+		mg := mailgun.NewMailgun(exampleAPIKey)
 		mg.SetAPIBase(srv.URL + "/v3")
 		m := mailgun.NewMessage(c.domain, fromUser, exampleSubject, exampleText, "test@test.com")
 
@@ -493,7 +493,7 @@ func TestSendEOFError(t *testing.T) {
 	}))
 	defer srv.Close()
 
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
+	mg := mailgun.NewMailgun(exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 
 	m := mailgun.NewMessage(exampleDomain, fromUser, exampleSubject, exampleText, toUser)
@@ -518,7 +518,7 @@ func TestHasRecipient(t *testing.T) {
 	}))
 	defer srv.Close()
 
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
+	mg := mailgun.NewMailgun(exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 
 	// No recipient
@@ -557,7 +557,7 @@ func TestResendStored(t *testing.T) {
 	}))
 	defer srv.Close()
 
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
+	mg := mailgun.NewMailgun(exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 
 	_, _, err := mg.ReSend(context.Background(), srv.URL+"/v3/some-url")
@@ -589,7 +589,7 @@ func TestAddOverrideHeader(t *testing.T) {
 	}))
 	defer srv.Close()
 
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
+	mg := mailgun.NewMailgun(exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 	mg.AddOverrideHeader("Host", "example.com")
 	mg.AddOverrideHeader("CustomHeader", "custom-value")
@@ -625,7 +625,7 @@ func TestOnBehalfOfSubaccount(t *testing.T) {
 	}))
 	defer srv.Close()
 
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
+	mg := mailgun.NewMailgun(exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 	mg.AddOverrideHeader("Host", "example.com")
 	mg.AddOverrideHeader("CustomHeader", "custom-value")
@@ -664,7 +664,7 @@ func TestSendTLSOptions(t *testing.T) {
 	}))
 	defer srv.Close()
 
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
+	mg := mailgun.NewMailgun(exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 	ctx := context.Background()
 
@@ -694,7 +694,7 @@ func TestSendTemplate(t *testing.T) {
 	}))
 	defer srv.Close()
 
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
+	mg := mailgun.NewMailgun(exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 	ctx := context.Background()
 
@@ -727,7 +727,7 @@ func TestSendTemplateOptions(t *testing.T) {
 	}))
 	defer srv.Close()
 
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
+	mg := mailgun.NewMailgun(exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 	ctx := context.Background()
 
diff --git a/routes_test.go b/routes_test.go
index 7536d95..6b6eea1 100644
--- a/routes_test.go
+++ b/routes_test.go
@@ -10,8 +10,8 @@ import (
 )
 
 func TestRouteCRUD(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 	var countRoutes = func() int {
@@ -58,8 +58,8 @@ func TestRouteCRUD(t *testing.T) {
 }
 
 func TestRoutesIterator(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	it := mg.ListRoutes(&mailgun.ListOptions{Limit: 2})
 
diff --git a/spam_complaints_test.go b/spam_complaints_test.go
index 3d4ea20..9f85d75 100644
--- a/spam_complaints_test.go
+++ b/spam_complaints_test.go
@@ -11,12 +11,12 @@ import (
 )
 
 func TestGetComplaints(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 
-	it := mg.ListComplaints(nil)
+	it := mg.ListComplaints(testDomain, nil)
 	var page []mailgun.Complaint
 	for it.Next(ctx, &page) {
 	}
@@ -24,11 +24,11 @@ func TestGetComplaints(t *testing.T) {
 }
 
 func TestGetComplaintFromRandomNoComplaint(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
-	_, err := mg.GetComplaint(ctx, randomString(64, "")+"@example.com")
+	_, err := mg.GetComplaint(ctx, testDomain, randomString(64, "")+"@example.com")
 	require.NotNil(t, err)
 
 	var ure *mailgun.UnexpectedResponseError
@@ -37,13 +37,13 @@ func TestGetComplaintFromRandomNoComplaint(t *testing.T) {
 }
 
 func TestCreateDeleteComplaint(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	var hasComplaint = func(email string) bool {
 		t.Logf("hasComplaint: %s\n", email)
-		it := mg.ListComplaints(nil)
+		it := mg.ListComplaints(testDomain, nil)
 		require.NoError(t, it.Err())
 
 		var page []mailgun.Complaint
@@ -61,20 +61,20 @@ func TestCreateDeleteComplaint(t *testing.T) {
 	randomMail := strings.ToLower(randomString(64, "")) + "@example.com"
 	require.False(t, hasComplaint(randomMail))
 
-	require.NoError(t, mg.CreateComplaint(ctx, randomMail))
+	require.NoError(t, mg.CreateComplaint(ctx, testDomain, randomMail))
 	require.True(t, hasComplaint(randomMail))
-	require.NoError(t, mg.DeleteComplaint(ctx, randomMail))
+	require.NoError(t, mg.DeleteComplaint(ctx, testDomain, randomMail))
 	require.False(t, hasComplaint(randomMail))
 }
 
 func TestCreateDeleteComplaintList(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	var hasComplaint = func(email string) bool {
 		t.Logf("hasComplaint: %s\n", email)
-		it := mg.ListComplaints(nil)
+		it := mg.ListComplaints(testDomain, nil)
 		require.NoError(t, it.Err())
 
 		var page []mailgun.Complaint
@@ -95,11 +95,11 @@ func TestCreateDeleteComplaintList(t *testing.T) {
 		strings.ToLower(randomString(64, "")) + "@example3.com",
 	}
 
-	require.NoError(t, mg.CreateComplaints(ctx, addresses))
+	require.NoError(t, mg.CreateComplaints(ctx, testDomain, addresses))
 
 	for _, address := range addresses {
 		require.True(t, hasComplaint(address))
-		require.NoError(t, mg.DeleteComplaint(ctx, address))
+		require.NoError(t, mg.DeleteComplaint(ctx, testDomain, address))
 		require.False(t, hasComplaint(address))
 	}
 }
diff --git a/storage_test.go b/storage_test.go
index 33a0df2..cd00dc0 100644
--- a/storage_test.go
+++ b/storage_test.go
@@ -13,8 +13,8 @@ import (
 )
 
 func TestStorage(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	var ctx = context.Background()
 
@@ -40,7 +40,7 @@ func TestStorage(t *testing.T) {
 
 // Tries to locate the first stored event type, returning the associated stored message key.
 func findStoredMessageURL(mg mailgun.Mailgun, id string) (string, error) {
-	it := mg.ListEvents(nil)
+	it := mg.ListEvents(testDomain, nil)
 
 	var page []mailgun.Event
 	for it.Next(context.Background(), &page) {
diff --git a/subaccounts_test.go b/subaccounts_test.go
index 8d92d63..acd14a5 100644
--- a/subaccounts_test.go
+++ b/subaccounts_test.go
@@ -17,8 +17,8 @@ const (
 )
 
 func TestListSubaccounts(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	iterator := mg.ListSubaccounts(nil)
 	require.NotNil(t, iterator)
@@ -37,8 +37,8 @@ func TestListSubaccounts(t *testing.T) {
 }
 
 func TestSubaccountDetails(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 
@@ -55,8 +55,8 @@ func TestSubaccountDetails(t *testing.T) {
 }
 
 func TestSubaccountDetailsStatusNotFound(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 
@@ -70,8 +70,8 @@ func TestSubaccountDetailsStatusNotFound(t *testing.T) {
 }
 
 func TestCreateSubaccount(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 
@@ -81,8 +81,8 @@ func TestCreateSubaccount(t *testing.T) {
 }
 
 func TestEnableSubaccountAlreadyEnabled(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 
@@ -91,8 +91,8 @@ func TestEnableSubaccountAlreadyEnabled(t *testing.T) {
 }
 
 func TestEnableSubaccount(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 
@@ -102,8 +102,8 @@ func TestEnableSubaccount(t *testing.T) {
 }
 
 func TestDisableSubaccount(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 
@@ -113,8 +113,8 @@ func TestDisableSubaccount(t *testing.T) {
 }
 
 func TestDisableSubaccountAlreadyDisabled(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
 
diff --git a/tags_test.go b/tags_test.go
index e7cf314..50e4b31 100644
--- a/tags_test.go
+++ b/tags_test.go
@@ -18,8 +18,8 @@ const (
 )
 
 func TestTags(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	msg := mailgun.NewMessage(testDomain, fromUser, exampleSubject, exampleText, "test@example.com")
 	require.NoError(t, msg.AddTag("newsletter"))
 	require.NoError(t, msg.AddTag("homer"))
@@ -36,7 +36,7 @@ func TestTags(t *testing.T) {
 	require.NoError(t, waitForTag(mg, "newsletter"))
 
 	// Should return a list of available tags
-	it := mg.ListTags(nil)
+	it := mg.ListTags(testDomain, nil)
 	var page []mailgun.Tag
 	for it.Next(ctx, &page) {
 		require.True(t, len(page) != 0)
@@ -44,7 +44,7 @@ func TestTags(t *testing.T) {
 	require.NoError(t, it.Err())
 
 	// Should return a limited list of available tags
-	cursor := mg.ListTags(&mailgun.ListTagOptions{Limit: 1})
+	cursor := mg.ListTags(testDomain, &mailgun.ListTagOptions{Limit: 1})
 
 	var tags []mailgun.Tag
 	for cursor.Next(ctx, &tags) {
@@ -52,14 +52,14 @@ func TestTags(t *testing.T) {
 	}
 	require.NoError(t, cursor.Err())
 
-	err = mg.DeleteTag(ctx, "newsletter")
+	err = mg.DeleteTag(ctx, testDomain, "newsletter")
 	require.NoError(t, err)
 
-	tag, err := mg.GetTag(ctx, "homer")
+	tag, err := mg.GetTag(ctx, testDomain, "homer")
 	require.NoError(t, err)
 	assert.Equal(t, "homer", tag.Value)
 
-	_, err = mg.GetTag(ctx, "i-dont-exist")
+	_, err = mg.GetTag(ctx, testDomain, "i-dont-exist")
 	require.NotNil(t, err)
 	assert.Equal(t, 404, mailgun.GetStatusFromErr(err))
 }
@@ -68,7 +68,7 @@ func waitForTag(mg mailgun.Mailgun, tag string) error {
 	ctx := context.Background()
 	var attempts int
 	for attempts <= 5 {
-		_, err := mg.GetTag(ctx, tag)
+		_, err := mg.GetTag(ctx, testDomain, tag)
 		if err != nil {
 			if mailgun.GetStatusFromErr(err) == 404 {
 				time.Sleep(time.Second * 2)
@@ -86,9 +86,9 @@ func waitForTag(mg mailgun.Mailgun, tag string) error {
 }
 
 func TestDeleteTag(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
-	require.NoError(t, mg.DeleteTag(ctx, "newsletter"))
+	require.NoError(t, mg.DeleteTag(ctx, testDomain, "newsletter"))
 }
diff --git a/template_test.go b/template_test.go
index 74bd74b..28cb6dd 100644
--- a/template_test.go
+++ b/template_test.go
@@ -13,12 +13,12 @@ import (
 )
 
 func TestTemplateCRUD(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	findTemplate := func(name string) bool {
-		it := mg.ListTemplates(nil)
+		it := mg.ListTemplates(testDomain, nil)
 
 		var page []mailgun.Template
 		for it.Next(ctx, &page) {
@@ -44,7 +44,7 @@ func TestTemplateCRUD(t *testing.T) {
 	}
 
 	// Create a template
-	require.NoError(t, mg.CreateTemplate(ctx, &tmpl))
+	require.NoError(t, mg.CreateTemplate(ctx, testDomain, &tmpl))
 	assert.Equal(t, strings.ToLower(Name), tmpl.Name)
 	assert.Equal(t, Description, tmpl.Description)
 
@@ -56,23 +56,23 @@ func TestTemplateCRUD(t *testing.T) {
 
 	// Update the description
 	tmpl.Description = UpdatedDesc
-	require.NoError(t, mg.UpdateTemplate(ctx, &tmpl))
+	require.NoError(t, mg.UpdateTemplate(ctx, testDomain, &tmpl))
 
 	// Ensure update took
-	updated, err := mg.GetTemplate(ctx, tmpl.Name)
+	updated, err := mg.GetTemplate(ctx, testDomain, tmpl.Name)
 	require.NoError(t, err)
 
 	assert.Equal(t, UpdatedDesc, updated.Description)
 
 	// Delete the template
-	require.NoError(t, mg.DeleteTemplate(ctx, tmpl.Name))
+	require.NoError(t, mg.DeleteTemplate(ctx, testDomain, tmpl.Name))
 }
 
 func waitForTemplate(mg mailgun.Mailgun, id string) error {
 	ctx := context.Background()
 	var attempts int
 	for attempts <= 5 {
-		_, err := mg.GetTemplate(ctx, id)
+		_, err := mg.GetTemplate(ctx, testDomain, id)
 		if err != nil {
 			if mailgun.GetStatusFromErr(err) == 404 {
 				time.Sleep(time.Second * 2)
diff --git a/template_versions_test.go b/template_versions_test.go
index 9de03d2..f6c8467 100644
--- a/template_versions_test.go
+++ b/template_versions_test.go
@@ -10,12 +10,12 @@ import (
 )
 
 func TestTemplateVersionsCRUD(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	findVersion := func(templateName, tag string) bool {
-		it := mg.ListTemplateVersions(templateName, nil)
+		it := mg.ListTemplateVersions(testDomain, templateName, nil)
 
 		var page []mailgun.TemplateVersion
 		for it.Next(ctx, &page) {
@@ -41,7 +41,7 @@ func TestTemplateVersionsCRUD(t *testing.T) {
 	}
 
 	// Create a template
-	require.NoError(t, mg.CreateTemplate(ctx, &tmpl))
+	require.NoError(t, mg.CreateTemplate(ctx, testDomain, &tmpl))
 
 	version := mailgun.TemplateVersion{
 		Tag:      Tag,
@@ -52,7 +52,7 @@ func TestTemplateVersionsCRUD(t *testing.T) {
 	}
 
 	// Add a version version
-	require.NoError(t, mg.AddTemplateVersion(ctx, tmpl.Name, &version))
+	require.NoError(t, mg.AddTemplateVersion(ctx, testDomain, tmpl.Name, &version))
 	assert.Equal(t, Tag, version.Tag)
 	assert.Equal(t, Comment, version.Comment)
 	assert.Equal(t, mailgun.TemplateEngineGo, version.Engine)
@@ -63,10 +63,10 @@ func TestTemplateVersionsCRUD(t *testing.T) {
 	// Update the Comment
 	version.Comment = UpdatedComment
 	version.Template = Template + "updated"
-	require.NoError(t, mg.UpdateTemplateVersion(ctx, tmpl.Name, &version))
+	require.NoError(t, mg.UpdateTemplateVersion(ctx, testDomain, tmpl.Name, &version))
 
 	// Ensure update took
-	updated, err := mg.GetTemplateVersion(ctx, tmpl.Name, version.Tag)
+	updated, err := mg.GetTemplateVersion(ctx, testDomain, tmpl.Name, version.Tag)
 
 	require.NoError(t, err)
 	assert.Equal(t, UpdatedComment, updated.Comment)
@@ -80,17 +80,17 @@ func TestTemplateVersionsCRUD(t *testing.T) {
 		Active:   true,
 		Engine:   mailgun.TemplateEngineGo,
 	}
-	require.NoError(t, mg.AddTemplateVersion(ctx, tmpl.Name, &version2))
+	require.NoError(t, mg.AddTemplateVersion(ctx, testDomain, tmpl.Name, &version2))
 
 	// Ensure the version is in the list
 	require.True(t, findVersion(tmpl.Name, version2.Tag))
 
 	// Delete the first version
-	require.NoError(t, mg.DeleteTemplateVersion(ctx, tmpl.Name, version.Tag))
+	require.NoError(t, mg.DeleteTemplateVersion(ctx, testDomain, tmpl.Name, version.Tag))
 
 	// Ensure version was deleted
 	require.False(t, findVersion(tmpl.Name, version.Tag))
 
 	// Delete the template
-	require.NoError(t, mg.DeleteTemplate(ctx, tmpl.Name))
+	require.NoError(t, mg.DeleteTemplate(ctx, testDomain, tmpl.Name))
 }
diff --git a/unsubscribes_test.go b/unsubscribes_test.go
index 9643abb..7787f9d 100644
--- a/unsubscribes_test.go
+++ b/unsubscribes_test.go
@@ -10,14 +10,14 @@ import (
 )
 
 func TestCreateUnsubscriber(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	email := randomEmail("unsubcribe", os.Getenv("MG_DOMAIN"))
 	ctx := context.Background()
 
 	// Create unsubscription record
-	require.NoError(t, mg.CreateUnsubscribe(ctx, email, "*"))
+	require.NoError(t, mg.CreateUnsubscribe(ctx, testDomain, email, "*"))
 }
 
 func TestCreateUnsubscribes(t *testing.T) {
@@ -30,20 +30,20 @@ func TestCreateUnsubscribes(t *testing.T) {
 			Tags:    []string{"tag1"},
 		},
 	}
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
 	// Create unsubscription records
-	require.NoError(t, mg.CreateUnsubscribes(ctx, unsubscribes))
+	require.NoError(t, mg.CreateUnsubscribes(ctx, testDomain, unsubscribes))
 }
 
 func TestListUnsubscribes(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 	ctx := context.Background()
 
-	it := mg.ListUnsubscribes(nil)
+	it := mg.ListUnsubscribes(testDomain, nil)
 	var page []mailgun.Unsubscribe
 	for it.Next(ctx, &page) {
 		t.Logf("Received %d unsubscribe records.\n", len(page))
@@ -58,38 +58,38 @@ func TestListUnsubscribes(t *testing.T) {
 }
 
 func TestGetUnsubscribe(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	email := randomEmail("unsubcribe", os.Getenv("MG_DOMAIN"))
 
 	ctx := context.Background()
 
 	// Create unsubscription record
-	require.NoError(t, mg.CreateUnsubscribe(ctx, email, "*"))
+	require.NoError(t, mg.CreateUnsubscribe(ctx, testDomain, email, "*"))
 
-	u, err := mg.GetUnsubscribe(ctx, email)
+	u, err := mg.GetUnsubscribe(ctx, testDomain, email)
 	require.NoError(t, err)
 	t.Logf("%s\t%s\t%s\t%s\t\n", u.ID, u.Address, u.CreatedAt, u.Tags)
 
 	// Destroy the unsubscription record
-	require.NoError(t, mg.DeleteUnsubscribe(ctx, email))
+	require.NoError(t, mg.DeleteUnsubscribe(ctx, testDomain, email))
 }
 
 func TestCreateDestroyUnsubscription(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	email := randomEmail("unsubcribe", os.Getenv("MG_DOMAIN"))
 
 	ctx := context.Background()
 
 	// Create unsubscription record
-	require.NoError(t, mg.CreateUnsubscribe(ctx, email, "*"))
+	require.NoError(t, mg.CreateUnsubscribe(ctx, testDomain, email, "*"))
 
-	_, err := mg.GetUnsubscribe(ctx, email)
+	_, err := mg.GetUnsubscribe(ctx, testDomain, email)
 	require.NoError(t, err)
 
 	// Destroy the unsubscription record
-	require.NoError(t, mg.DeleteUnsubscribe(ctx, email))
+	require.NoError(t, mg.DeleteUnsubscribe(ctx, testDomain, email))
 }
diff --git a/webhooks_test.go b/webhooks_test.go
index 9bb6969..c7aa2d2 100644
--- a/webhooks_test.go
+++ b/webhooks_test.go
@@ -19,41 +19,41 @@ import (
 )
 
 func TestGetWebhook(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
-	list, err := mg.ListWebhooks(ctx)
+	list, err := mg.ListWebhooks(ctx, testDomain)
 	require.NoError(t, err)
 	require.Len(t, list, 2)
 
-	urls, err := mg.GetWebhook(ctx, "new-webhook")
+	urls, err := mg.GetWebhook(ctx, testDomain, "new-webhook")
 	require.NoError(t, err)
 
 	assert.Equal(t, []string{"http://example.com/new"}, urls)
 }
 
 func TestWebhookCRUD(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
-	mg.SetAPIBase(server.URL())
+	mg := mailgun.NewMailgun(testKey)
+	mg.SetAPIBase(server.URL3())
 
 	ctx := context.Background()
-	list, err := mg.ListWebhooks(ctx)
+	list, err := mg.ListWebhooks(ctx, testDomain)
 	require.NoError(t, err)
 	require.Len(t, list, 2)
 
 	var countHooks = func() int {
-		hooks, err := mg.ListWebhooks(ctx)
+		hooks, err := mg.ListWebhooks(ctx, testDomain)
 		require.NoError(t, err)
 		return len(hooks)
 	}
 	hookCount := countHooks()
 
 	webHookURLs := []string{"http://api.mailgun.net/webhook"}
-	require.NoError(t, mg.CreateWebhook(ctx, "deliver", webHookURLs))
+	require.NoError(t, mg.CreateWebhook(ctx, testDomain, "deliver", webHookURLs))
 
 	defer func() {
-		require.NoError(t, mg.DeleteWebhook(ctx, "deliver"))
+		require.NoError(t, mg.DeleteWebhook(ctx, testDomain, "deliver"))
 		newCount := countHooks()
 		require.Equal(t, hookCount, newCount)
 	}()
@@ -61,14 +61,14 @@ func TestWebhookCRUD(t *testing.T) {
 	newCount := countHooks()
 	require.False(t, newCount <= hookCount)
 
-	urls, err := mg.GetWebhook(ctx, "deliver")
+	urls, err := mg.GetWebhook(ctx, testDomain, "deliver")
 	require.NoError(t, err)
 	require.Equal(t, webHookURLs, urls)
 
 	updatedWebHookURL := []string{"http://api.mailgun.net/messages"}
-	require.NoError(t, mg.UpdateWebhook(ctx, "deliver", updatedWebHookURL))
+	require.NoError(t, mg.UpdateWebhook(ctx, testDomain, "deliver", updatedWebHookURL))
 
-	hooks, err := mg.ListWebhooks(ctx)
+	hooks, err := mg.ListWebhooks(ctx, testDomain)
 	require.NoError(t, err)
 	require.Equal(t, updatedWebHookURL, hooks["deliver"])
 }
@@ -79,7 +79,7 @@ var signedTests = []bool{
 }
 
 func TestVerifyWebhookSignature(t *testing.T) {
-	mg := mailgun.NewMailgun(testDomain, testKey)
+	mg := mailgun.NewMailgun(testKey)
 	mg.SetWebhookSigningKey(testWebhookSigningKey)
 
 	for _, v := range signedTests {