Repository: prebid/prebid-server
Pull request #2814 (2023-05-31 08:21:44)

New adapter - MgidX

gargcreation1992: @xmgiddev PR checks are failing. Could you please check once?
xmgiddev: @gargcreation1992 fixed

Patch:
diff --git a/adapters/mgidX/mgidX.go b/adapters/mgidX/mgidX.go
new file mode 100644
index 00000000..29d2df46
--- /dev/null
+++ b/adapters/mgidX/mgidX.go
@@ -0,0 +1,158 @@
+package mgidX
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+
+	"github.com/prebid/openrtb/v19/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+type adapter struct {
+	endpoint string
+}
+
+type reqBodyExt struct {
+	MgidXBidderExt reqBodyExtBidder `json:"bidder"`
+}
+
+type reqBodyExtBidder struct {
+	Type        string `json:"type"`
+	PlacementID string `json:"placementId,omitempty"`
+	EndpointID  string `json:"endpointId,omitempty"`
+}
+
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
+	bidder := &adapter{
+		endpoint: config.Endpoint,
+	}
+	return bidder, nil
+}
+
+func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	var err error
+	var adapterRequests []*adapters.RequestData
+
+	reqCopy := *request
+	for _, imp := range request.Imp {
+		reqCopy.Imp = []openrtb2.Imp{imp}
+
+		var bidderExt adapters.ExtImpBidder
+		var mgidXExt openrtb_ext.ImpExtMgidX
+
+		if err = json.Unmarshal(reqCopy.Imp[0].Ext, &bidderExt); err != nil {
+			return nil, []error{err}
+		}
+		if err = json.Unmarshal(bidderExt.Bidder, &mgidXExt); err != nil {
+			return nil, []error{err}
+		}
+
+		impExt := reqBodyExt{MgidXBidderExt: reqBodyExtBidder{}}
+
+		if mgidXExt.PlacementID != "" {
+			impExt.MgidXBidderExt.PlacementID = mgidXExt.PlacementID
+			impExt.MgidXBidderExt.Type = "publisher"
+		} else if mgidXExt.EndpointID != "" {
+			impExt.MgidXBidderExt.EndpointID = mgidXExt.EndpointID
+			impExt.MgidXBidderExt.Type = "network"
+		} else {
+			continue
+		}
+
+		finalyImpExt, err := json.Marshal(impExt)
+		if err != nil {
+			return nil, []error{err}
+		}
+
+		reqCopy.Imp[0].Ext = finalyImpExt
+
+		adapterReq, err := a.makeRequest(&reqCopy)
+		if err != nil {
+			return nil, []error{err}
+		}
+
+		if adapterReq != nil {
+			adapterRequests = append(adapterRequests, adapterReq)
+		}
+	}
+
+	if len(adapterRequests) == 0 {
+		return nil, []error{errors.New("found no valid impressions")}
+	}
+
+	return adapterRequests, nil
+}
+
+func (a *adapter) makeRequest(request *openrtb2.BidRequest) (*adapters.RequestData, error) {
+	reqJSON, err := json.Marshal(request)
+	if err != nil {
+		return nil, err
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	return &adapters.RequestData{
+		Method:  "POST",
+		Uri:     a.endpoint,
+		Body:    reqJSON,
+		Headers: headers,
+	}, nil
+}
+
+func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	if adapters.IsResponseStatusCodeNoContent(responseData) {
+		return nil, nil
+	}
+
+	if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil {
+		return nil, []error{err}
+	}
+
+	var response openrtb2.BidResponse
+	if err := json.Unmarshal(responseData.Body, &response); err != nil {
+		return nil, []error{err}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp))
+	bidResponse.Currency = response.Cur
+
+	impsMappedByID := make(map[string]openrtb2.Imp, len(request.Imp))
+	for i, imp := range request.Imp {
+		impsMappedByID[request.Imp[i].ID] = imp
+	}
+
+	for _, seatBid := range response.SeatBid {
+		for i := range seatBid.Bid {
+			bidType, err := getBidMediaType(&seatBid.Bid[i])
+			if err != nil {
+				return nil, []error{err}
+			}
+
+			b := &adapters.TypedBid{
+				Bid:     &seatBid.Bid[i],
+				BidType: bidType,
+			}
+			bidResponse.Bids = append(bidResponse.Bids, b)
+		}
+	}
+	return bidResponse, nil
+}
+
+func getBidMediaType(bid *openrtb2.Bid) (openrtb_ext.BidType, error) {
+	var extBid openrtb_ext.ExtBid
+	err := json.Unmarshal(bid.Ext, &extBid)
+	if err != nil {
+		return "", fmt.Errorf("unable to deserialize imp %v bid.ext", bid.ImpID)
+	}
+
+	if extBid.Prebid == nil {
+		return "", fmt.Errorf("imp %v with unknown media type", bid.ImpID)
+	}
+
+	return extBid.Prebid.Type, nil
+}
diff --git a/adapters/motorik/motorik.go b/adapters/motorik/motorik.go
new file mode 100644
index 00000000..c804c095
--- /dev/null
+++ b/adapters/motorik/motorik.go
@@ -0,0 +1,175 @@
+package motorik
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"text/template"
+
+	"github.com/prebid/openrtb/v19/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/macros"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+type adapter struct {
+	endpoint *template.Template
+}
+
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
+	template, err := template.New("endpointTemplate").Parse(config.Endpoint)
+	if err != nil {
+		return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
+	}
+
+	bidder := &adapter{
+		endpoint: template,
+	}
+	return bidder, nil
+}
+
+func getHeaders(request *openrtb2.BidRequest) http.Header {
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	headers.Add("X-Openrtb-Version", "2.5")
+
+	if request.Device != nil {
+		if len(request.Device.UA) > 0 {
+			headers.Add("User-Agent", request.Device.UA)
+		}
+
+		if len(request.Device.IPv6) > 0 {
+			headers.Add("X-Forwarded-For", request.Device.IPv6)
+		}
+
+		if len(request.Device.IP) > 0 {
+			headers.Add("X-Forwarded-For", request.Device.IP)
+		}
+	}
+
+	return headers
+}
+
+func (a *adapter) MakeRequests(openRTBRequest *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) (requestsToBidder []*adapters.RequestData, errs []error) {
+	motorikExt, err := getImpressionExt(&openRTBRequest.Imp[0])
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	openRTBRequest.Imp[0].Ext = nil
+
+	url, err := a.buildEndpointURL(motorikExt)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	reqJSON, err := json.Marshal(openRTBRequest)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	return []*adapters.RequestData{{
+		Method:  http.MethodPost,
+		Body:    reqJSON,
+		Uri:     url,
+		Headers: getHeaders(openRTBRequest),
+	}}, nil
+}
+
+func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtMotorik, error) {
+	var bidderExt adapters.ExtImpBidder
+	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
+		return nil, &errortypes.BadInput{
+			Message: "Error parsing motorikExt - " + err.Error(),
+		}
+	}
+	var motorikExt openrtb_ext.ExtMotorik
+	if err := json.Unmarshal(bidderExt.Bidder, &motorikExt); err != nil {
+		return nil, &errortypes.BadInput{
+			Message: "Error parsing bidderExt - " + err.Error(),
+		}
+	}
+
+	return &motorikExt, nil
+}
+
+func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtMotorik) (string, error) {
+	endpointParams := macros.EndpointTemplateParams{AccountID: params.AccountID, SourceId: params.PlacementID}
+	return macros.ResolveMacros(a.endpoint, endpointParams)
+}
+
+func checkResponseStatusCodes(response *adapters.ResponseData) error {
+	if response.StatusCode == http.StatusServiceUnavailable {
+		return &errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Something went wrong Status Code: [ %d ] ", response.StatusCode),
+		}
+	}
+
+	return adapters.CheckResponseStatusCodeForErrors(response)
+}
+
+func (a *adapter) MakeBids(openRTBRequest *openrtb2.BidRequest, requestToBidder *adapters.RequestData, bidderRawResponse *adapters.ResponseData) (bidderResponse *adapters.BidderResponse, errs []error) {
+	if adapters.IsResponseStatusCodeNoContent(bidderRawResponse) {
+		return nil, nil
+	}
+
+	httpStatusError := checkResponseStatusCodes(bidderRawResponse)
+	if httpStatusError != nil {
+		return nil, []error{httpStatusError}
+	}
+
+	responseBody := bidderRawResponse.Body
+	var bidResp openrtb2.BidResponse
+	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Bad Server Response",
+		}}
+	}
+
+	if len(bidResp.SeatBid) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid array",
+		}}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(5)
+	var bidsArray []*adapters.TypedBid
+
+	for _, sb := range bidResp.SeatBid {
+		for idx, bid := range sb.Bid {
+			bidType, err := getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp)
+			if err != nil {
+				return nil, []error{err}
+			}
+
+			bidsArray = append(bidsArray, &adapters.TypedBid{
+				Bid:     &sb.Bid[idx],
+				BidType: bidType,
+			})
+		}
+	}
+
+	bidResponse.Bids = bidsArray
+	return bidResponse, nil
+}
+
+func getMediaTypeForImp(impId string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {
+	for _, imp := range imps {
+		if imp.ID == impId {
+			if imp.Banner != nil {
+				return openrtb_ext.BidTypeBanner, nil
+			} else if imp.Video != nil {
+				return openrtb_ext.BidTypeVideo, nil
+			} else if imp.Native != nil {
+				return openrtb_ext.BidTypeNative, nil
+			}
+			break
+		}
+	}
+	return "", &errortypes.BadInput{
+		Message: fmt.Sprintf("Failed to find impression \"%s\"", impId),
+	}
+}
diff --git a/adapters/yahoossp/yahoossp.go b/adapters/yahooAdvertising/yahooAdvertising.go
similarity index 93%
rename from adapters/yahoossp/yahoossp.go
rename to adapters/yahooAdvertising/yahooAdvertising.go
index 797ea708..d476adb4 100644
--- a/adapters/yahoossp/yahoossp.go
+++ b/adapters/yahooAdvertising/yahooAdvertising.go
@@ -1,4 +1,4 @@
-package yahoossp
+package yahooAdvertising
 
 import (
 	"encoding/json"
@@ -41,8 +41,8 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E
 			continue
 		}
 
-		var yahoosspExt openrtb_ext.ExtImpYahooSSP
-		err = json.Unmarshal(bidderExt.Bidder, &yahoosspExt)
+		var yahooAdvertisingExt openrtb_ext.ExtImpYahooAdvertising
+		err = json.Unmarshal(bidderExt.Bidder, &yahooAdvertisingExt)
 		if err != nil {
 			err = &errortypes.BadInput{
 				Message: fmt.Sprintf("imp #%d: %s", idx, err.Error()),
@@ -64,7 +64,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E
 			reqCopy.App = &appCopy
 		}
 
-		if err := changeRequestForBidService(&reqCopy, &yahoosspExt); err != nil {
+		if err := changeRequestForBidService(&reqCopy, &yahooAdvertisingExt); err != nil {
 			errors = append(errors, err)
 			continue
 		}
@@ -150,7 +150,7 @@ func getImpInfo(impId string, imps []openrtb2.Imp) (bool, openrtb_ext.BidType) {
 	return exists, mediaType
 }
 
-func changeRequestForBidService(request *openrtb2.BidRequest, extension *openrtb_ext.ExtImpYahooSSP) error {
+func changeRequestForBidService(request *openrtb2.BidRequest, extension *openrtb_ext.ExtImpYahooAdvertising) error {
 	/* Always override the tag ID and (site ID or app ID) of the request */
 	request.Imp[0].TagID = extension.Pos
 	if request.Site != nil {
@@ -218,7 +218,7 @@ func validateBanner(banner *openrtb2.Banner) error {
 	return nil
 }
 
-// Builder builds a new instance of the YahooSSP adapter for the given bidder with the given config.
+// Builder builds a new instance of the YahooAdvertising adapter for the given bidder with the given config.
 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
 	bidder := &adapter{
 		URI: config.Endpoint,
diff --git a/config/compression.go b/config/compression.go
new file mode 100644
index 00000000..db85202b
--- /dev/null
+++ b/config/compression.go
@@ -0,0 +1,21 @@
+package config
+
+import "github.com/prebid/prebid-server/util/httputil"
+
+type Compression struct {
+	Request  CompressionInfo `mapstructure:"request"`
+	Response CompressionInfo `mapstructure:"response"`
+}
+
+// CompressionInfo defines what types of compression algorithms are supported.
+type CompressionInfo struct {
+	GZIP bool `mapstructure:"enable_gzip"`
+}
+
+func (cfg *CompressionInfo) IsSupported(contentEncoding httputil.ContentEncoding) bool {
+	switch contentEncoding.Normalize() {
+	case httputil.ContentEncodingGZIP:
+		return cfg.GZIP
+	}
+	return false
+}
diff --git a/config/config.go b/config/config.go
index b537d128..eabf62ca 100644
--- a/config/config.go
+++ b/config/config.go
@@ -22,15 +22,16 @@ import (
 
 // Configuration specifies the static application config.
 type Configuration struct {
-	ExternalURL      string     `mapstructure:"external_url"`
-	Host             string     `mapstructure:"host"`
-	Port             int        `mapstructure:"port"`
-	UnixSocketEnable bool       `mapstructure:"unix_socket_enable"`
-	UnixSocketName   string     `mapstructure:"unix_socket_name"`
-	Client           HTTPClient `mapstructure:"http_client"`
-	CacheClient      HTTPClient `mapstructure:"http_client_cache"`
-	AdminPort        int        `mapstructure:"admin_port"`
-	EnableGzip       bool       `mapstructure:"enable_gzip"`
+	ExternalURL      string      `mapstructure:"external_url"`
+	Host             string      `mapstructure:"host"`
+	Port             int         `mapstructure:"port"`
+	UnixSocketEnable bool        `mapstructure:"unix_socket_enable"`
+	UnixSocketName   string      `mapstructure:"unix_socket_name"`
+	Client           HTTPClient  `mapstructure:"http_client"`
+	CacheClient      HTTPClient  `mapstructure:"http_client_cache"`
+	AdminPort        int         `mapstructure:"admin_port"`
+	EnableGzip       bool        `mapstructure:"enable_gzip"`
+	Compression      Compression `mapstructure:"compression"`
 	// GarbageCollectorThreshold allocates virtual memory (in bytes) which is not used by PBS but
 	// serves as a hack to trigger the garbage collector only when the heap reaches at least this size.
 	// More info: https://github.com/golang/go/issues/48409
@@ -837,7 +838,6 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) {
 	v.SetDefault("unix_socket_enable", false)              // boolean which decide if the socket-server will be started.
 	v.SetDefault("unix_socket_name", "prebid-server.sock") // path of the socket's file which must be listened.
 	v.SetDefault("admin_port", 6060)
-	v.SetDefault("enable_gzip", false)
 	v.SetDefault("garbage_collector_threshold", 0)
 	v.SetDefault("status_response", "")
 	v.SetDefault("datacenter", "")
@@ -1022,6 +1022,9 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) {
 	v.SetDefault("account_defaults.price_floors.max_schema_dims", 3)
 	v.SetDefault("account_defaults.events_enabled", false)
 
+	v.SetDefault("compression.response.enable_gzip", false)
+	v.SetDefault("compression.request.enable_gzip", false)
+
 	v.SetDefault("certificates_file", "")
 	v.SetDefault("auto_gen_source_tid", true)
 	v.SetDefault("generate_bid_id", false)
@@ -1070,6 +1073,7 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) {
 	migrateConfigSpecialFeature1(v)
 	migrateConfigTCF2PurposeFlags(v)
 	migrateConfigDatabaseConnection(v)
+	migrateConfigCompression(v)
 
 	// These defaults must be set after the migrate functions because those functions look for the presence of these
 	// config fields and there isn't a way to detect presence of a config field using the viper package if a default
@@ -1110,6 +1114,8 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) {
 	v.SetDefault("gdpr.tcf2.special_feature1.vendor_exceptions", []openrtb_ext.BidderName{})
 	v.SetDefault("price_floors.enabled", false)
 
+	v.SetDefault("enable_gzip", false)
+
 	// Defaults for account_defaults.events.default_url
 	v.SetDefault("account_defaults.events.default_url", "https://PBS_HOST/event?t=##PBS-EVENTTYPE##&vtype=##PBS-VASTEVENT##&b=##PBS-BIDID##&f=i&a=##PBS-ACCOUNTID##&ts=##PBS-TIMESTAMP##&bidder=##PBS-BIDDER##&int=##PBS-INTEGRATION##&mt=##PBS-MEDIATYPE##&ch=##PBS-CHANNEL##&aid=##PBS-AUCTIONID##&l=##PBS-LINEID##")
 
@@ -1141,6 +1147,20 @@ func migrateConfig(v *viper.Viper) {
 	}
 }
 
+func migrateConfigCompression(v *viper.Viper) {
+	oldField := "enable_gzip"
+	newField := "compression.response.enable_gzip"
+	if v.IsSet(oldField) {
+		oldConfig := v.GetBool(oldField)
+		if v.IsSet(newField) {
+			glog.Warningf("using %s and ignoring deprecated %s", newField, oldField)
+		} else {
+			glog.Warningf("%s is deprecated and should be changed to %s", oldField, newField)
+			v.Set(newField, oldConfig)
+		}
+	}
+}
+
 func migrateConfigPurposeOneTreatment(v *viper.Viper) {
 	if oldConfig, ok := v.Get("gdpr.tcf2.purpose_one_treatement").(map[string]interface{}); ok {
 		if v.IsSet("gdpr.tcf2.purpose_one_treatment") {
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index 62353711..46a31138 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -1,11 +1,13 @@
 package openrtb2
 
 import (
+	"compress/gzip"
 	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"net/http"
 	"net/url"
 	"regexp"
@@ -340,28 +342,49 @@ func sendAuctionResponse(
 //
 // If the errors list has at least one element, then no guarantees are made about the returned request.
 func (deps *endpointDeps) parseRequest(httpRequest *http.Request, labels *metrics.Labels, hookExecutor hookexecution.HookStageExecutor) (req *openrtb_ext.RequestWrapper, impExtInfoMap map[string]exchange.ImpExtInfo, storedAuctionResponses stored_responses.ImpsWithBidResponses, storedBidResponses stored_responses.ImpBidderStoredResp, bidderImpReplaceImpId stored_responses.BidderImpReplaceImpID, account *config.Account, errs []error) {
-	req = &openrtb_ext.RequestWrapper{}
-	req.BidRequest = &openrtb2.BidRequest{}
 	errs = nil
-
-	// Pull the request body into a buffer, so we have it for later usage.
-	lr := &io.LimitedReader{
-		R: httpRequest.Body,
+	var err error
+	var r io.ReadCloser = httpRequest.Body
+	reqContentEncoding := httputil.ContentEncoding(httpRequest.Header.Get("Content-Encoding"))
+	if reqContentEncoding != "" {
+		if !deps.cfg.Compression.Request.IsSupported(reqContentEncoding) {
+			errs = []error{fmt.Errorf("Content-Encoding of type %s is not supported", reqContentEncoding)}
+			return
+		} else {
+			r, err = getCompressionEnabledReader(httpRequest.Body, reqContentEncoding)
+			if err != nil {
+				errs = []error{err}
+				return
+			}
+		}
+	}
+	defer r.Close()
+	limitedReqReader := &io.LimitedReader{
+		R: r,
 		N: deps.cfg.MaxRequestSize,
 	}
-	requestJson, err := io.ReadAll(lr)
+
+	requestJson, err := ioutil.ReadAll(limitedReqReader)
 	if err != nil {
 		errs = []error{err}
 		return
 	}
-	// If the request size was too large, read through the rest of the request body so that the connection can be reused.
-	if lr.N <= 0 {
-		if written, err := io.Copy(io.Discard, httpRequest.Body); written > 0 || err != nil {
-			errs = []error{fmt.Errorf("Request size exceeded max size of %d bytes.", deps.cfg.MaxRequestSize)}
+
+	if limitedReqReader.N <= 0 {
+		// Limited Reader returns 0 if the request was exactly at the max size or over the limit.
+		// This is because it only reads up to N bytes. To check if the request was too large,
+		//  we need to look at the next byte of its underlying reader, limitedReader.R.
+		if _, err := limitedReqReader.R.Read(make([]byte, 1)); err != io.EOF {
+			// Discard the rest of the request body so that the connection can be reused.
+			io.Copy(io.Discard, httpRequest.Body)
+			errs = []error{fmt.Errorf("request size exceeded max size of %d bytes.", deps.cfg.MaxRequestSize)}
 			return
 		}
 	}
 
+	req = &openrtb_ext.RequestWrapper{}
+	req.BidRequest = &openrtb2.BidRequest{}
+
 	requestJson, rejectErr := hookExecutor.ExecuteEntrypointStage(httpRequest, requestJson)
 	if rejectErr != nil {
 		errs = []error{rejectErr}
@@ -472,6 +495,15 @@ func (deps *endpointDeps) parseRequest(httpRequest *http.Request, labels *metric
 	return
 }
 
+func getCompressionEnabledReader(body io.ReadCloser, contentEncoding httputil.ContentEncoding) (io.ReadCloser, error) {
+	switch contentEncoding {
+	case httputil.ContentEncodingGZIP:
+		return gzip.NewReader(body)
+	default:
+		return nil, fmt.Errorf("unsupported compression type '%s'", contentEncoding)
+	}
+}
+
 // hasPayloadUpdatesAt checks if there are any successful payload updates at given stage
 func hasPayloadUpdatesAt(stageName string, outcomes []hookexecution.StageOutcome) bool {
 	for _, outcome := range outcomes {
@@ -1584,29 +1616,50 @@ func validateTargeting(t *openrtb_ext.ExtRequestTargeting) error {
 	}
 
 	if t.PriceGranularity != nil {
-		pg := t.PriceGranularity
+		if err := validatePriceGranularity(t.PriceGranularity); err != nil {
+			return err
+		}
+	}
 
-		if pg.Precision == nil {
-			return errors.New("Price granularity error: precision is required")
-		} else if *pg.Precision < 0 {
-			return errors.New("Price granularity error: precision must be non-negative")
-		} else if *pg.Precision > openrtb_ext.MaxDecimalFigures {
-			return fmt.Errorf("Price granularity error: precision of more than %d significant figures is not supported", openrtb_ext.MaxDecimalFigures)
+	if t.MediaTypePriceGranularity.Video != nil {
+		if err := validatePriceGranularity(t.MediaTypePriceGranularity.Video); err != nil {
+			return err
+		}
+	}
+	if t.MediaTypePriceGranularity.Banner != nil {
+		if err := validatePriceGranularity(t.MediaTypePriceGranularity.Banner); err != nil {
+			return err
 		}
+	}
+	if t.MediaTypePriceGranularity.Native != nil {
+		if err := validatePriceGranularity(t.MediaTypePriceGranularity.Native); err != nil {
+			return err
+		}
+	}
 
-		var prevMax float64 = 0
-		for _, gr := range pg.Ranges {
-			if gr.Max <= prevMax {
-				return errors.New(`Price granularity error: range list must be ordered with increasing "max"`)
-			}
+	return nil
+}
 
-			if gr.Increment <= 0.0 {
-				return errors.New("Price granularity error: increment must be a nonzero positive number")
-			}
-			prevMax = gr.Max
-		}
+func validatePriceGranularity(pg *openrtb_ext.PriceGranularity) error {
+	if pg.Precision == nil {
+		return errors.New("Price granularity error: precision is required")
+	} else if *pg.Precision < 0 {
+		return errors.New("Price granularity error: precision must be non-negative")
+	} else if *pg.Precision > openrtb_ext.MaxDecimalFigures {
+		return fmt.Errorf("Price granularity error: precision of more than %d significant figures is not supported", openrtb_ext.MaxDecimalFigures)
 	}
 
+	var prevMax float64 = 0
+	for _, gr := range pg.Ranges {
+		if gr.Max <= prevMax {
+			return errors.New(`Price granularity error: range list must be ordered with increasing "max"`)
+		}
+
+		if gr.Increment <= 0.0 {
+			return errors.New("Price granularity error: increment must be a nonzero positive number")
+		}
+		prevMax = gr.Max
+	}
 	return nil
 }
 
diff --git a/endpoints/openrtb2/sample-requests/amp/consent-through-query/addtl-consent-through-query.json b/endpoints/openrtb2/sample-requests/amp/consent-through-query/addtl-consent-through-query.json
index c775d332..034d3235 100644
--- a/endpoints/openrtb2/sample-requests/amp/consent-through-query/addtl-consent-through-query.json
+++ b/endpoints/openrtb2/sample-requests/amp/consent-through-query/addtl-consent-through-query.json
@@ -105,7 +105,8 @@
             ]
           },
           "includewinners": true,
-          "includebidderkeys": true
+          "includebidderkeys": true,
+          "mediatypepricegranularity": {}
         }
       }
     }
diff --git a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-ccpa-through-query.json b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-ccpa-through-query.json
index f2e2a217..8dc19f6f 100644
--- a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-ccpa-through-query.json
+++ b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-ccpa-through-query.json
@@ -99,7 +99,8 @@
             ]
           },
           "includewinners": true,
-          "includebidderkeys": true
+          "includebidderkeys": true,
+          "mediatypepricegranularity": {}
         }
       }
     }
diff --git a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-legacy-tcf2-consent-through-query.json b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-legacy-tcf2-consent-through-query.json
index 1cf81ea2..4003abf9 100644
--- a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-legacy-tcf2-consent-through-query.json
+++ b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-legacy-tcf2-consent-through-query.json
@@ -104,7 +104,8 @@
             ]
           },
           "includewinners": true,
-          "includebidderkeys": true
+          "includebidderkeys": true,
+          "mediatypepricegranularity": {}
         }
       }
     }
diff --git a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf1-consent-through-query.json b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf1-consent-through-query.json
index c596a832..c6389dad 100644
--- a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf1-consent-through-query.json
+++ b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf1-consent-through-query.json
@@ -104,7 +104,8 @@
             ]
           },
           "includewinners": true,
-          "includebidderkeys": true
+          "includebidderkeys": true,
+          "mediatypepricegranularity": {}
         }
       }
     }
diff --git a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf2-consent-through-query.json b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf2-consent-through-query.json
index fdc25ed9..b62a745b 100644
--- a/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf2-consent-through-query.json
+++ b/endpoints/openrtb2/sample-requests/amp/consent-through-query/gdpr-tcf2-consent-through-query.json
@@ -104,7 +104,8 @@
             ]
           },
           "includewinners": true,
-          "includebidderkeys": true
+          "includebidderkeys": true,
+          "mediatypepricegranularity": {}
         }
       }
     }
diff --git a/endpoints/openrtb2/sample-requests/hooks/auction_reject_with_error.json b/endpoints/openrtb2/sample-requests/hooks/auction_reject_with_error.json
new file mode 100644
index 00000000..5ca617a4
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/hooks/auction_reject_with_error.json
@@ -0,0 +1,87 @@
+{
+  "description": "Auction request",
+  "config": {
+    "mockBidders": [
+      {"bidderName": "appnexus", "currency": "USD", "price": 0.00}
+    ]
+  },
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "site": {
+      "page": "prebid.org"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "appnexus": {
+            "placementId": 12883451
+          }
+        }
+      }
+    ],
+    "tmax": 500,
+    "test": 1,
+    "ext": {
+      "prebid": {
+        "trace": "verbose"
+      }
+    }
+  },
+  "expectedBidResponse": {
+    "id": "some-request-id",
+    "bidid": "test bid id",
+    "nbr": 123,
+    "ext": {
+      "prebid": {
+        "modules": {
+          "errors": {
+            "foobar": {
+              "foo": [
+                "dummy",
+                "Module foobar (hook: foo) rejected request with code 123 at entrypoint stage"
+              ]
+            }
+          },
+          "trace": {
+            "stages": [
+              {
+                "stage": "entrypoint",
+                "outcomes": [
+                  {
+                    "entity": "http-request",
+                    "groups": [
+                      {
+                        "invocation_results": [
+                          {
+                            "analytics_tags": {},
+                            "hook_id": {
+                              "module_code": "foobar",
+                              "hook_impl_code": "foo"
+                            },
+                            "status": "execution_failure",
+                            "action": "reject",
+                            "message": ""
+                          }
+                        ]
+                      }
+                    ]
+                  }
+                ]
+              }
+            ]
+          }
+        }
+      }
+    }
+  },
+  "expectedReturnCode": 200
+}
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/supplementary/req-ext-bidder-params-backward-compatible-merge.json b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/req-ext-bidder-params-backward-compatible-merge.json
index 9e9fd538..908e20e5 100644
--- a/endpoints/openrtb2/sample-requests/valid-whole/supplementary/req-ext-bidder-params-backward-compatible-merge.json
+++ b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/req-ext-bidder-params-backward-compatible-merge.json
@@ -74,6 +74,7 @@
             }
           ]
         },
+        "mediatypepricegranularity": {},
         "includewinners": true,
         "includebidderkeys": true
       },
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/supplementary/req-ext-bidder-params-merge.json b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/req-ext-bidder-params-merge.json
index 9f0e78be..1e2f58cb 100644
--- a/endpoints/openrtb2/sample-requests/valid-whole/supplementary/req-ext-bidder-params-merge.json
+++ b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/req-ext-bidder-params-merge.json
@@ -76,6 +76,7 @@
             }
           ]
         },
+        "mediatypepricegranularity": {},
         "includewinners": true,
         "includebidderkeys": true
       },
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/supplementary/req-ext-bidder-params.json b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/req-ext-bidder-params.json
index 27ee9da4..311d4e11 100644
--- a/endpoints/openrtb2/sample-requests/valid-whole/supplementary/req-ext-bidder-params.json
+++ b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/req-ext-bidder-params.json
@@ -69,6 +69,7 @@
             }
           ]
         },
+        "mediatypepricegranularity": {},
         "includewinners": true,
         "includebidderkeys": true
       },
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 7ad3afe4..4525514e 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -111,8 +111,10 @@ import (
 	"github.com/prebid/prebid-server/adapters/marsmedia"
 	"github.com/prebid/prebid-server/adapters/medianet"
 	"github.com/prebid/prebid-server/adapters/mgid"
+	"github.com/prebid/prebid-server/adapters/mgidX"
 	"github.com/prebid/prebid-server/adapters/mobfoxpb"
 	"github.com/prebid/prebid-server/adapters/mobilefuse"
+	"github.com/prebid/prebid-server/adapters/motorik"
 	"github.com/prebid/prebid-server/adapters/nanointeractive"
 	"github.com/prebid/prebid-server/adapters/nextmillennium"
 	"github.com/prebid/prebid-server/adapters/ninthdecimal"
@@ -165,7 +167,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/visx"
 	"github.com/prebid/prebid-server/adapters/vrtcal"
 	"github.com/prebid/prebid-server/adapters/xeworks"
-	"github.com/prebid/prebid-server/adapters/yahoossp"
+	"github.com/prebid/prebid-server/adapters/yahooAdvertising"
 	"github.com/prebid/prebid-server/adapters/yeahmobi"
 	"github.com/prebid/prebid-server/adapters/yieldlab"
 	"github.com/prebid/prebid-server/adapters/yieldmo"
@@ -257,6 +259,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderEngageBDR:         engagebdr.Builder,
 		openrtb_ext.BidderEPlanning:         eplanning.Builder,
 		openrtb_ext.BidderEpom:              epom.Builder,
+		openrtb_ext.BidderEpsilon:           conversant.Builder,
 		openrtb_ext.BidderEVolution:         evolution.Builder,
 		openrtb_ext.BidderEvtech:            limelightDigital.Builder,
 		openrtb_ext.BidderFlipp:             flipp.Builder,
@@ -267,7 +270,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderGamoshi:           gamoshi.Builder,
 		openrtb_ext.BidderGlobalsun:         globalsun.Builder,
 		openrtb_ext.BidderGrid:              grid.Builder,
-		openrtb_ext.BidderGroupm:            pubmatic.Builder,
 		openrtb_ext.BidderGumGum:            gumgum.Builder,
 		openrtb_ext.BidderHuaweiAds:         huaweiads.Builder,
 		openrtb_ext.BidderIionads:           limelightDigital.Builder,
@@ -298,8 +300,10 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderMediafuse:         appnexus.Builder,
 		openrtb_ext.BidderMedianet:          medianet.Builder,
 		openrtb_ext.BidderMgid:              mgid.Builder,
+		openrtb_ext.BidderMgidX:             mgidX.Builder,
 		openrtb_ext.BidderMobfoxpb:          mobfoxpb.Builder,
 		openrtb_ext.BidderMobileFuse:        mobilefuse.Builder,
+		openrtb_ext.BidderMotorik:           motorik.Builder,
 		openrtb_ext.BidderNanoInteractive:   nanointeractive.Builder,
 		openrtb_ext.BidderNextMillennium:    nextmillennium.Builder,
 		openrtb_ext.BidderNinthDecimal:      ninthdecimal.Builder,
@@ -351,7 +355,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderUnicorn:           unicorn.Builder,
 		openrtb_ext.BidderUnruly:            unruly.Builder,
 		openrtb_ext.BidderValueImpression:   apacdex.Builder,
-		openrtb_ext.BidderVerizonMedia:      yahoossp.Builder,
 		openrtb_ext.BidderVideoByte:         videobyte.Builder,
 		openrtb_ext.BidderVideoHeroes:       videoheroes.Builder,
 		openrtb_ext.BidderVidoomy:           vidoomy.Builder,
@@ -360,7 +363,8 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderVisx:              visx.Builder,
 		openrtb_ext.BidderVrtcal:            vrtcal.Builder,
 		openrtb_ext.BidderXeworks:           xeworks.Builder,
-		openrtb_ext.BidderYahooSSP:          yahoossp.Builder,
+		openrtb_ext.BidderYahooAdvertising:  yahooAdvertising.Builder,
+		openrtb_ext.BidderYahooSSP:          yahooAdvertising.Builder,
 		openrtb_ext.BidderYeahmobi:          yeahmobi.Builder,
 		openrtb_ext.BidderYieldlab:          yieldlab.Builder,
 		openrtb_ext.BidderYieldmo:           yieldmo.Builder,
diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go
index 056dbf35..33904aae 100644
--- a/exchange/adapter_util.go
+++ b/exchange/adapter_util.go
@@ -88,9 +88,10 @@ func GetDisabledBiddersErrorMessages(infos config.BidderInfos) map[string]string
 		"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
 		"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
 		"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-		"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+		"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahooAdvertising" in your configuration.`,
 		"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
 		"oftmedia":       `Bidder "oftmedia" is no longer available in Prebid Server. Please update your configuration.`,
+		"groupm":         `Bidder "groupm" is no longer available in Prebid Server. Please update your configuration.`,
 	}
 
 	for name, info := range infos {
diff --git a/exchange/auction.go b/exchange/auction.go
index 330aa50c..b2d6eb57 100644
--- a/exchange/auction.go
+++ b/exchange/auction.go
@@ -185,12 +185,12 @@ func (a *auction) validateAndUpdateMultiBid(adapterBids map[openrtb_ext.BidderNa
 	}
 }
 
-func (a *auction) setRoundedPrices(priceGranularity openrtb_ext.PriceGranularity) {
+func (a *auction) setRoundedPrices(targetingData targetData) {
 	roundedPrices := make(map[*entities.PbsOrtbBid]string, 5*len(a.winningBids))
 	for _, topBidsPerImp := range a.winningBidsByBidder {
 		for _, topBidsPerBidder := range topBidsPerImp {
 			for _, topBid := range topBidsPerBidder {
-				roundedPrices[topBid] = GetPriceBucket(topBid.Bid.Price, priceGranularity)
+				roundedPrices[topBid] = GetPriceBucket(*topBid.Bid, targetingData)
 			}
 		}
 	}
diff --git a/exchange/exchange.go b/exchange/exchange.go
index 04ffd79e..2b1f4df8 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -425,7 +425,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog
 			// A non-nil auction is only needed if targeting is active. (It is used below this block to extract cache keys)
 			auc = newAuction(adapterBids, len(r.BidRequestWrapper.Imp), targData.preferDeals)
 			auc.validateAndUpdateMultiBid(adapterBids, targData.preferDeals, r.Account.DefaultBidLimit)
-			auc.setRoundedPrices(targData.priceGranularity)
+			auc.setRoundedPrices(*targData)
 
 			if requestExtPrebid.SupportDeals {
 				dealErrs := applyDealSupport(r.BidRequestWrapper.BidRequest, auc, bidCategory, multiBidMap)
@@ -959,7 +959,7 @@ func applyCategoryMapping(ctx context.Context, targeting openrtb_ext.ExtRequestT
 			bidID := bid.Bid.ID
 			var duration int
 			var category string
-			var pb string
+			var priceBucket string
 
 			if bid.BidVideo != nil {
 				duration = bid.BidVideo.Duration
@@ -993,7 +993,7 @@ func applyCategoryMapping(ctx context.Context, targeting openrtb_ext.ExtRequestT
 
 			// TODO: consider should we remove bids with zero duration here?
 
-			pb = GetPriceBucket(bid.Bid.Price, targData.priceGranularity)
+			priceBucket = GetPriceBucket(*bid.Bid, *targData)
 
 			newDur := duration
 			if len(targeting.DurationRangeSec) > 0 {
@@ -1018,10 +1018,10 @@ func applyCategoryMapping(ctx context.Context, targeting openrtb_ext.ExtRequestT
 			var categoryDuration string
 			var dupeKey string
 			if brandCatExt.WithCategory {
-				categoryDuration = fmt.Sprintf("%s_%s_%ds", pb, category, newDur)
+				categoryDuration = fmt.Sprintf("%s_%s_%ds", priceBucket, category, newDur)
 				dupeKey = category
 			} else {
-				categoryDuration = fmt.Sprintf("%s_%ds", pb, newDur)
+				categoryDuration = fmt.Sprintf("%s_%ds", priceBucket, newDur)
 				dupeKey = categoryDuration
 			}
 
@@ -1035,7 +1035,7 @@ func applyCategoryMapping(ctx context.Context, targeting openrtb_ext.ExtRequestT
 				if err != nil {
 					dupeBidPrice = 0
 				}
-				currBidPrice, err := strconv.ParseFloat(pb, 64)
+				currBidPrice, err := strconv.ParseFloat(priceBucket, 64)
 				if err != nil {
 					currBidPrice = 0
 				}
@@ -1076,7 +1076,7 @@ func applyCategoryMapping(ctx context.Context, targeting openrtb_ext.ExtRequestT
 				}
 			}
 			res[bidID] = categoryDuration
-			dedupe[dupeKey] = bidDedupe{bidderName: bidderName, bidIndex: bidInd, bidID: bidID, bidPrice: pb}
+			dedupe[dupeKey] = bidDedupe{bidderName: bidderName, bidIndex: bidInd, bidID: bidID, bidPrice: priceBucket}
 		}
 
 		if len(bidsToRemove) > 0 {
@@ -1401,20 +1401,6 @@ func listBiddersWithRequests(bidderRequests []BidderRequest) []openrtb_ext.Bidde
 	return liveAdapters
 }
 
-func getPrebidMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
-	if bid.Ext != nil {
-		var bidExt openrtb_ext.ExtBid
-		err := json.Unmarshal(bid.Ext, &bidExt)
-		if err == nil && bidExt.Prebid != nil {
-			return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type))
-		}
-	}
-
-	return "", &errortypes.BadServerResponse{
-		Message: fmt.Sprintf("Failed to parse bid mediatype for impression \"%s\"", bid.ImpID),
-	}
-}
-
 func buildStoredAuctionResponse(storedAuctionResponses map[string]json.RawMessage) (
 	map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid,
 	*openrtb_ext.Fledge,
@@ -1435,29 +1421,9 @@ func buildStoredAuctionResponse(storedAuctionResponses map[string]json.RawMessag
 			//set imp id from request
 			for i := range seat.Bid {
 				seat.Bid[i].ImpID = impId
-				mType := seat.Bid[i].MType
-				var bidType openrtb_ext.BidType
-				if mType > 0 {
-					switch mType {
-					case openrtb2.MarkupBanner:
-						bidType = openrtb_ext.BidTypeBanner
-					case openrtb2.MarkupVideo:
-						bidType = openrtb_ext.BidTypeVideo
-					case openrtb2.MarkupAudio:
-						bidType = openrtb_ext.BidTypeAudio
-					case openrtb2.MarkupNative:
-						bidType = openrtb_ext.BidTypeNative
-					default:
-						return nil, nil, nil, &errortypes.BadServerResponse{
-							Message: fmt.Sprintf("Failed to parse bid mType for impression \"%s\"", seat.Bid[i].ImpID),
-						}
-					}
-				} else {
-					var err error
-					bidType, err = getPrebidMediaTypeForBid(seat.Bid[i])
-					if err != nil {
-						return nil, nil, nil, err
-					}
+				bidType, err := getMediaTypeForBid(seat.Bid[i])
+				if err != nil {
+					return nil, nil, nil, err
 				}
 				bidsToAdd = append(bidsToAdd, &entities.PbsOrtbBid{Bid: &seat.Bid[i], BidType: bidType})
 			}
diff --git a/exchange/price_granularity.go b/exchange/price_granularity.go
index 1af56ea2..af9e46b2 100644
--- a/exchange/price_granularity.go
+++ b/exchange/price_granularity.go
@@ -1,20 +1,34 @@
 package exchange
 
 import (
+	"github.com/prebid/openrtb/v19/openrtb2"
+	"github.com/prebid/prebid-server/openrtb_ext"
 	"math"
 	"strconv"
-
-	"github.com/prebid/prebid-server/openrtb_ext"
 )
 
 // GetPriceBucket is the externally facing function for computing CPM buckets
-func GetPriceBucket(cpm float64, config openrtb_ext.PriceGranularity) string {
+func GetPriceBucket(bid openrtb2.Bid, targetingData targetData) string {
 	cpmStr := ""
 	bucketMax := 0.0
 	bucketMin := 0.0
 	increment := 0.0
+
+	config := targetingData.priceGranularity //assign default price granularity
+
+	if bidType, err := getMediaTypeForBid(bid); err == nil {
+		if bidType == openrtb_ext.BidTypeBanner && targetingData.mediaTypePriceGranularity.Banner != nil {
+			config = *targetingData.mediaTypePriceGranularity.Banner
+		} else if bidType == openrtb_ext.BidTypeVideo && targetingData.mediaTypePriceGranularity.Video != nil {
+			config = *targetingData.mediaTypePriceGranularity.Video
+		} else if bidType == openrtb_ext.BidTypeNative && targetingData.mediaTypePriceGranularity.Native != nil {
+			config = *targetingData.mediaTypePriceGranularity.Native
+		}
+	}
+
 	precision := *config.Precision
 
+	cpm := bid.Price
 	for i := 0; i < len(config.Ranges); i++ {
 		if config.Ranges[i].Max > bucketMax {
 			bucketMax = config.Ranges[i].Max
diff --git a/exchange/targeting.go b/exchange/targeting.go
index 987c6aa6..dbbf1004 100644
--- a/exchange/targeting.go
+++ b/exchange/targeting.go
@@ -18,13 +18,14 @@ const MaxKeyLength = 20
 // All functions on this struct are all nil-safe.
 // If the value is nil, then no targeting data will be tracked.
 type targetData struct {
-	priceGranularity  openrtb_ext.PriceGranularity
-	includeWinners    bool
-	includeBidderKeys bool
-	includeCacheBids  bool
-	includeCacheVast  bool
-	includeFormat     bool
-	preferDeals       bool
+	priceGranularity          openrtb_ext.PriceGranularity
+	mediaTypePriceGranularity openrtb_ext.MediaTypePriceGranularity
+	includeWinners            bool
+	includeBidderKeys         bool
+	includeCacheBids          bool
+	includeCacheVast          bool
+	includeFormat             bool
+	preferDeals               bool
 	// cacheHost and cachePath exist to supply cache host and path as targeting parameters
 	cacheHost string
 	cachePath string
diff --git a/exchange/utils.go b/exchange/utils.go
index 7145e72b..d43a4182 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -15,6 +15,7 @@ import (
 	"github.com/prebid/openrtb/v19/openrtb2"
 
 	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
 	"github.com/prebid/prebid-server/firstpartydata"
 	"github.com/prebid/prebid-server/gdpr"
 	"github.com/prebid/prebid-server/metrics"
@@ -804,13 +805,14 @@ func getExtCacheInstructions(requestExtPrebid *openrtb_ext.ExtRequestPrebid) ext
 func getExtTargetData(requestExtPrebid *openrtb_ext.ExtRequestPrebid, cacheInstructions extCacheInstructions) *targetData {
 	if requestExtPrebid != nil && requestExtPrebid.Targeting != nil {
 		return &targetData{
-			includeWinners:    *requestExtPrebid.Targeting.IncludeWinners,
-			includeBidderKeys: *requestExtPrebid.Targeting.IncludeBidderKeys,
-			includeCacheBids:  cacheInstructions.cacheBids,
-			includeCacheVast:  cacheInstructions.cacheVAST,
-			includeFormat:     requestExtPrebid.Targeting.IncludeFormat,
-			priceGranularity:  *requestExtPrebid.Targeting.PriceGranularity,
-			preferDeals:       requestExtPrebid.Targeting.PreferDeals,
+			includeWinners:            *requestExtPrebid.Targeting.IncludeWinners,
+			includeBidderKeys:         *requestExtPrebid.Targeting.IncludeBidderKeys,
+			includeCacheBids:          cacheInstructions.cacheBids,
+			includeCacheVast:          cacheInstructions.cacheVAST,
+			includeFormat:             requestExtPrebid.Targeting.IncludeFormat,
+			priceGranularity:          *requestExtPrebid.Targeting.PriceGranularity,
+			mediaTypePriceGranularity: requestExtPrebid.Targeting.MediaTypePriceGranularity,
+			preferDeals:               requestExtPrebid.Targeting.PreferDeals,
 		}
 	}
 
@@ -980,3 +982,53 @@ func WrapJSONInData(data []byte) []byte {
 	res = append(res, []byte(`}`)...)
 	return res
 }
+
+func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
+	mType := bid.MType
+	var bidType openrtb_ext.BidType
+	if mType > 0 {
+		switch mType {
+		case openrtb2.MarkupBanner:
+			bidType = openrtb_ext.BidTypeBanner
+		case openrtb2.MarkupVideo:
+			bidType = openrtb_ext.BidTypeVideo
+		case openrtb2.MarkupAudio:
+			bidType = openrtb_ext.BidTypeAudio
+		case openrtb2.MarkupNative:
+			bidType = openrtb_ext.BidTypeNative
+		default:
+			return bidType, fmt.Errorf("Failed to parse bid mType for impression \"%s\"", bid.ImpID)
+		}
+	} else {
+		var err error
+		bidType, err = getPrebidMediaTypeForBid(bid)
+		if err != nil {
+			return bidType, err
+		}
+	}
+	return bidType, nil
+}
+
+func getPrebidMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
+	var err error
+	var bidType openrtb_ext.BidType
+
+	if bid.Ext != nil {
+		var bidExt openrtb_ext.ExtBid
+		err = json.Unmarshal(bid.Ext, &bidExt)
+		if err == nil && bidExt.Prebid != nil {
+			if bidType, err = openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)); err == nil {
+				return bidType, nil
+			}
+		}
+	}
+
+	errMsg := fmt.Sprintf("Failed to parse bid mediatype for impression \"%s\"", bid.ImpID)
+	if err != nil {
+		errMsg = fmt.Sprintf("%s, %s", errMsg, err.Error())
+	}
+
+	return bidType, &errortypes.BadServerResponse{
+		Message: errMsg,
+	}
+}
diff --git a/hooks/hookexecution/execution.go b/hooks/hookexecution/execution.go
index 20fa76d8..18c92789 100644
--- a/hooks/hookexecution/execution.go
+++ b/hooks/hookexecution/execution.go
@@ -190,12 +190,10 @@ func handleHookResponse[P any](
 		ExecutionTime: ExecutionTime{ExecutionTimeMillis: hr.ExecutionTime},
 	}
 
-	switch true {
-	case hr.Err != nil:
+	if hr.Err != nil || hr.Result.Reject {
 		handleHookError(hr, &hookOutcome, metricEngine, labels)
-	case hr.Result.Reject:
 		rejectErr = handleHookReject(ctx, hr, &hookOutcome, metricEngine, labels)
-	default:
+	} else {
 		payload = handleHookMutations(payload, hr, &hookOutcome, metricEngine, labels)
 	}
 
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 52dd503f..52b9d380 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -162,6 +162,7 @@ const (
 	BidderEmxDigital        BidderName = "emx_digital"
 	BidderEngageBDR         BidderName = "engagebdr"
 	BidderEPlanning         BidderName = "eplanning"
+	BidderEpsilon           BidderName = "epsilon"
 	BidderEpom              BidderName = "epom"
 	BidderEVolution         BidderName = "e_volution"
 	BidderEvtech            BidderName = "evtech"
@@ -173,7 +174,6 @@ const (
 	BidderGamoshi           BidderName = "gamoshi"
 	BidderGlobalsun         BidderName = "globalsun"
 	BidderGrid              BidderName = "grid"
-	BidderGroupm            BidderName = "groupm"
 	BidderGumGum            BidderName = "gumgum"
 	BidderHuaweiAds         BidderName = "huaweiads"
 	BidderIionads           BidderName = "iionads"
@@ -204,8 +204,10 @@ const (
 	BidderMediafuse         BidderName = "mediafuse"
 	BidderMedianet          BidderName = "medianet"
 	BidderMgid              BidderName = "mgid"
+	BidderMgidX             BidderName = "mgidX"
 	BidderMobfoxpb          BidderName = "mobfoxpb"
 	BidderMobileFuse        BidderName = "mobilefuse"
+	BidderMotorik           BidderName = "motorik"
 	BidderNanoInteractive   BidderName = "nanointeractive"
 	BidderNextMillennium    BidderName = "nextmillennium"
 	BidderNinthDecimal      BidderName = "ninthdecimal"
@@ -257,7 +259,6 @@ const (
 	BidderUnicorn           BidderName = "unicorn"
 	BidderUnruly            BidderName = "unruly"
 	BidderValueImpression   BidderName = "valueimpression"
-	BidderVerizonMedia      BidderName = "verizonmedia"
 	BidderVideoByte         BidderName = "videobyte"
 	BidderVideoHeroes       BidderName = "videoheroes"
 	BidderVidoomy           BidderName = "vidoomy"
@@ -266,6 +267,7 @@ const (
 	BidderVisx              BidderName = "visx"
 	BidderVrtcal            BidderName = "vrtcal"
 	BidderXeworks           BidderName = "xeworks"
+	BidderYahooAdvertising  BidderName = "yahooAdvertising"
 	BidderYahooSSP          BidderName = "yahoossp"
 	BidderYeahmobi          BidderName = "yeahmobi"
 	BidderYieldlab          BidderName = "yieldlab"
@@ -355,6 +357,7 @@ func CoreBidderNames() []BidderName {
 		BidderEngageBDR,
 		BidderEPlanning,
 		BidderEpom,
+		BidderEpsilon,
 		BidderEVolution,
 		BidderEvtech,
 		BidderFlipp,
@@ -365,7 +368,6 @@ func CoreBidderNames() []BidderName {
 		BidderGamoshi,
 		BidderGlobalsun,
 		BidderGrid,
-		BidderGroupm,
 		BidderGumGum,
 		BidderHuaweiAds,
 		BidderIionads,
@@ -396,8 +398,10 @@ func CoreBidderNames() []BidderName {
 		BidderMediafuse,
 		BidderMedianet,
 		BidderMgid,
+		BidderMgidX,
 		BidderMobfoxpb,
 		BidderMobileFuse,
+		BidderMotorik,
 		BidderNanoInteractive,
 		BidderNextMillennium,
 		BidderNinthDecimal,
@@ -449,7 +453,6 @@ func CoreBidderNames() []BidderName {
 		BidderUnicorn,
 		BidderUnruly,
 		BidderValueImpression,
-		BidderVerizonMedia,
 		BidderVideoByte,
 		BidderVideoHeroes,
 		BidderVidoomy,
@@ -458,6 +461,7 @@ func CoreBidderNames() []BidderName {
 		BidderVisx,
 		BidderVrtcal,
 		BidderXeworks,
+		BidderYahooAdvertising,
 		BidderYahooSSP,
 		BidderYeahmobi,
 		BidderYieldlab,
diff --git a/openrtb_ext/imp_mgidX.go b/openrtb_ext/imp_mgidX.go
new file mode 100644
index 00000000..1a16fcc4
--- /dev/null
+++ b/openrtb_ext/imp_mgidX.go
@@ -0,0 +1,6 @@
+package openrtb_ext
+
+type ImpExtMgidX struct {
+	PlacementID string `json:"placementId"`
+	EndpointID  string `json:"endpointId"`
+}
diff --git a/openrtb_ext/imp_motorik.go b/openrtb_ext/imp_motorik.go
new file mode 100644
index 00000000..0b6fca78
--- /dev/null
+++ b/openrtb_ext/imp_motorik.go
@@ -0,0 +1,6 @@
+package openrtb_ext
+
+type ExtMotorik struct {
+	AccountID   string `json:"accountId"`
+	PlacementID string `json:"placementId"`
+}
diff --git a/openrtb_ext/imp_verizonmedia.go b/openrtb_ext/imp_verizonmedia.go
deleted file mode 100644
index 2ae8e5ea..00000000
--- a/openrtb_ext/imp_verizonmedia.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package openrtb_ext
-
-// ExtImpVerizonMedia defines the contract for bidrequest.imp[i].ext.prebid.bidder.verizonmedia
-type ExtImpVerizonMedia struct {
-	Dcn string `json:"dcn"`
-	Pos string `json:"pos"`
-}
diff --git a/openrtb_ext/imp_yahooAdvertising.go b/openrtb_ext/imp_yahooAdvertising.go
new file mode 100644
index 00000000..e0e8614a
--- /dev/null
+++ b/openrtb_ext/imp_yahooAdvertising.go
@@ -0,0 +1,7 @@
+package openrtb_ext
+
+// ExtImpYahooAdvertising defines the contract for bidrequest.imp[i].ext.prebid.bidder.yahooAdvertising
+type ExtImpYahooAdvertising struct {
+	Dcn string `json:"dcn"`
+	Pos string `json:"pos"`
+}
diff --git a/openrtb_ext/request.go b/openrtb_ext/request.go
index 9d82e424..67f196bf 100644
--- a/openrtb_ext/request.go
+++ b/openrtb_ext/request.go
@@ -184,14 +184,15 @@ type Adjustment struct {
 
 // ExtRequestTargeting defines the contract for bidrequest.ext.prebid.targeting
 type ExtRequestTargeting struct {
-	PriceGranularity     *PriceGranularity        `json:"pricegranularity,omitempty"`
-	IncludeWinners       *bool                    `json:"includewinners,omitempty"`
-	IncludeBidderKeys    *bool                    `json:"includebidderkeys,omitempty"`
-	IncludeBrandCategory *ExtIncludeBrandCategory `json:"includebrandcategory,omitempty"`
-	IncludeFormat        bool                     `json:"includeformat,omitempty"`
-	DurationRangeSec     []int                    `json:"durationrangesec,omitempty"`
-	PreferDeals          bool                     `json:"preferdeals,omitempty"`
-	AppendBidderNames    bool                     `json:"appendbiddernames,omitempty"`
+	PriceGranularity          *PriceGranularity         `json:"pricegranularity,omitempty"`
+	MediaTypePriceGranularity MediaTypePriceGranularity `json:"mediatypepricegranularity,omitempty"`
+	IncludeWinners            *bool                     `json:"includewinners,omitempty"`
+	IncludeBidderKeys         *bool                     `json:"includebidderkeys,omitempty"`
+	IncludeBrandCategory      *ExtIncludeBrandCategory  `json:"includebrandcategory,omitempty"`
+	IncludeFormat             bool                      `json:"includeformat,omitempty"`
+	DurationRangeSec          []int                     `json:"durationrangesec,omitempty"`
+	PreferDeals               bool                      `json:"preferdeals,omitempty"`
+	AppendBidderNames         bool                      `json:"appendbiddernames,omitempty"`
 }
 
 type ExtIncludeBrandCategory struct {
@@ -201,7 +202,15 @@ type ExtIncludeBrandCategory struct {
 	TranslateCategories *bool  `json:"translatecategories,omitempty"`
 }
 
+// MediaTypePriceGranularity specify price granularity configuration at the bid type level
+type MediaTypePriceGranularity struct {
+	Banner *PriceGranularity `json:"banner,omitempty"`
+	Video  *PriceGranularity `json:"video,omitempty"`
+	Native *PriceGranularity `json:"native,omitempty"`
+}
+
 // PriceGranularity defines the allowed values for bidrequest.ext.prebid.targeting.pricegranularity
+// or bidrequest.ext.prebid.targeting.mediatypepricegranularity.banner|video|native
 type PriceGranularity struct {
 	Precision *int               `json:"precision,omitempty"`
 	Ranges    []GranularityRange `json:"ranges,omitempty"`
diff --git a/ortb/default.go b/ortb/default.go
index 1581961b..cd9d8c24 100644
--- a/ortb/default.go
+++ b/ortb/default.go
@@ -46,11 +46,32 @@ func setDefaultsTargeting(targeting *openrtb_ext.ExtRequestTargeting) bool {
 
 	modified := false
 
-	if targeting.PriceGranularity == nil || len(targeting.PriceGranularity.Ranges) == 0 {
-		targeting.PriceGranularity = ptrutil.ToPtr(openrtb_ext.NewPriceGranularityDefault())
-		modified = true
-	} else if setDefaultsPriceGranularity(targeting.PriceGranularity) {
+	if newPG, updated := setDefaultsPriceGranularity(targeting.PriceGranularity); updated {
 		modified = true
+		targeting.PriceGranularity = newPG
+	}
+
+	// If price granularity is not specified in request then default one should be set.
+	// Default price granularity can be overwritten for video, banner or native bid type
+	// only in case targeting.MediaTypePriceGranularity.Video|Banner|Native != nil.
+
+	if targeting.MediaTypePriceGranularity.Video != nil {
+		if newVideoPG, updated := setDefaultsPriceGranularity(targeting.MediaTypePriceGranularity.Video); updated {
+			modified = true
+			targeting.MediaTypePriceGranularity.Video = newVideoPG
+		}
+	}
+	if targeting.MediaTypePriceGranularity.Banner != nil {
+		if newBannerPG, updated := setDefaultsPriceGranularity(targeting.MediaTypePriceGranularity.Banner); updated {
+			modified = true
+			targeting.MediaTypePriceGranularity.Banner = newBannerPG
+		}
+	}
+	if targeting.MediaTypePriceGranularity.Native != nil {
+		if newNativePG, updated := setDefaultsPriceGranularity(targeting.MediaTypePriceGranularity.Native); updated {
+			modified = true
+			targeting.MediaTypePriceGranularity.Native = newNativePG
+		}
 	}
 
 	if targeting.IncludeWinners == nil {
@@ -66,7 +87,12 @@ func setDefaultsTargeting(targeting *openrtb_ext.ExtRequestTargeting) bool {
 	return modified
 }
 
-func setDefaultsPriceGranularity(pg *openrtb_ext.PriceGranularity) bool {
+func setDefaultsPriceGranularity(pg *openrtb_ext.PriceGranularity) (*openrtb_ext.PriceGranularity, bool) {
+	if pg == nil || len(pg.Ranges) == 0 {
+		pg = ptrutil.ToPtr(openrtb_ext.NewPriceGranularityDefault())
+		return pg, true
+	}
+
 	modified := false
 
 	if pg.Precision == nil {
@@ -78,7 +104,7 @@ func setDefaultsPriceGranularity(pg *openrtb_ext.PriceGranularity) bool {
 		modified = true
 	}
 
-	return modified
+	return pg, modified
 }
 
 func setDefaultsPriceGranularityRange(ranges []openrtb_ext.GranularityRange) bool {
diff --git a/privacy/enforcement.go b/privacy/enforcement.go
index e1669f78..50d42e89 100644
--- a/privacy/enforcement.go
+++ b/privacy/enforcement.go
@@ -69,17 +69,9 @@ func (e Enforcement) getGeoScrubStrategy() ScrubStrategyGeo {
 }
 
 func (e Enforcement) getUserScrubStrategy() ScrubStrategyUser {
-	if e.COPPA {
+	if e.COPPA || e.CCPA || e.LMT || e.GDPRID {
 		return ScrubStrategyUserIDAndDemographic
 	}
 
-	if e.CCPA || e.LMT {
-		return ScrubStrategyUserID
-	}
-
-	if e.GDPRID {
-		return ScrubStrategyUserID
-	}
-
 	return ScrubStrategyUserNone
 }
diff --git a/privacy/scrubber.go b/privacy/scrubber.go
index c2ea7d63..428193bc 100644
--- a/privacy/scrubber.go
+++ b/privacy/scrubber.go
@@ -55,9 +55,6 @@ const (
 
 	// ScrubStrategyUserIDAndDemographic removes the user's buyer id, exchange id year of birth, and gender.
 	ScrubStrategyUserIDAndDemographic
-
-	// ScrubStrategyUserID removes the user's buyer id.
-	ScrubStrategyUserID
 )
 
 // ScrubStrategyDeviceID defines the approach to remove hardware id and device id data.
@@ -131,17 +128,12 @@ func (scrubber) ScrubUser(user *openrtb2.User, strategy ScrubStrategyUser, geo S
 
 	userCopy := *user
 
-	switch strategy {
-	case ScrubStrategyUserIDAndDemographic:
+	if strategy == ScrubStrategyUserIDAndDemographic {
 		userCopy.BuyerUID = ""
 		userCopy.ID = ""
 		userCopy.Ext = scrubUserExtIDs(userCopy.Ext)
 		userCopy.Yob = 0
 		userCopy.Gender = ""
-	case ScrubStrategyUserID:
-		userCopy.BuyerUID = ""
-		userCopy.ID = ""
-		userCopy.Ext = scrubUserExtIDs(userCopy.Ext)
 	}
 
 	switch geo {
diff --git a/server/server.go b/server/server.go
index ce77fdc8..31764cc4 100644
--- a/server/server.go
+++ b/server/server.go
@@ -91,10 +91,7 @@ func newAdminServer(cfg *config.Configuration, handler http.Handler) *http.Serve
 }
 
 func newMainServer(cfg *config.Configuration, handler http.Handler) *http.Server {
-	var serverHandler = handler
-	if cfg.EnableGzip {
-		serverHandler = gziphandler.GzipHandler(handler)
-	}
+	serverHandler := getCompressionEnabledHandler(handler, cfg.Compression.Response)
 
 	return &http.Server{
 		Addr:         cfg.Host + ":" + strconv.Itoa(cfg.Port),
@@ -106,10 +103,7 @@ func newMainServer(cfg *config.Configuration, handler http.Handler) *http.Server
 }
 
 func newSocketServer(cfg *config.Configuration, handler http.Handler) *http.Server {
-	var serverHandler = handler
-	if cfg.EnableGzip {
-		serverHandler = gziphandler.GzipHandler(handler)
-	}
+	serverHandler := getCompressionEnabledHandler(handler, cfg.Compression.Response)
 
 	return &http.Server{
 		Addr:         cfg.UnixSocketName,
@@ -119,6 +113,13 @@ func newSocketServer(cfg *config.Configuration, handler http.Handler) *http.Serv
 	}
 }
 
+func getCompressionEnabledHandler(h http.Handler, compressionInfo config.CompressionInfo) http.Handler {
+	if compressionInfo.GZIP {
+		h = gziphandler.GzipHandler(h)
+	}
+	return h
+}
+
 func runServer(server *http.Server, name string, listener net.Listener) (err error) {
 	if server == nil {
 		err = fmt.Errorf(">> Server is a nil_ptr.")
diff --git a/static/bidder-info/adsinteractive.yaml b/static/bidder-info/adsinteractive.yaml
index 0fb63903..ae60ec88 100644
--- a/static/bidder-info/adsinteractive.yaml
+++ b/static/bidder-info/adsinteractive.yaml
@@ -1,6 +1,7 @@
 endpoint: "http://bid.adsinteractive.com/prebid"
 maintainer:
   email: it@adsinteractive.com
+gvlVendorID: 1212
 modifyingVastXmlAllowed: false
 capabilities:
   app:
diff --git a/static/bidder-info/conversant.yaml b/static/bidder-info/conversant.yaml
index da003b25..2135544d 100644
--- a/static/bidder-info/conversant.yaml
+++ b/static/bidder-info/conversant.yaml
@@ -1,6 +1,6 @@
 endpoint: "http://api.hb.ad.cpe.dotomi.com/cvx/server/hb/ortb/25"
 maintainer:
-  email: "CNVR_PublisherIntegration@conversantmedia.com"
+  email: "PublisherIntegration@epsilon.com"
 gvlVendorID: 24
 capabilities:
   app:
@@ -15,4 +15,4 @@ userSync:
   redirect:
     url: "https://prebid-match.dotomi.com/match/bounce/current?version=1&networkId=72582&rurl={{.RedirectURL}}"
     userMacro: ""
-    # conversant appends the user id to end of the redirect url and does not utilize a macro
+    # epsilon appends the user id to end of the redirect url and does not utilize a macro
diff --git a/static/bidder-info/epsilon.yaml b/static/bidder-info/epsilon.yaml
new file mode 100644
index 00000000..856d82a6
--- /dev/null
+++ b/static/bidder-info/epsilon.yaml
@@ -0,0 +1,18 @@
+endpoint: "http://api.hb.ad.cpe.dotomi.com/cvx/server/hb/ortb/25"
+maintainer:
+  email: "PublisherIntegration@epsilon.com"
+gvlVendorID: 24
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+  site:
+    mediaTypes:
+      - banner
+      - video
+userSync:
+  redirect:
+    url: "https://prebid-match.dotomi.com/match/bounce/current?version=1&networkId=72582&rurl={{.RedirectURL}}"
+    userMacro: ""
+    # epsilon/conversant appends the user id to end of the redirect url and does not utilize a macro
diff --git a/static/bidder-info/groupm.yaml b/static/bidder-info/groupm.yaml
deleted file mode 100644
index 189527d5..00000000
--- a/static/bidder-info/groupm.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-endpoint: "https://hbopenbid.pubmatic.com/translator?source=prebid-server"
-maintainer:
-  email: "header-bidding@pubmatic.com"
-gvlVendorID: 98
-capabilities:
-  app:
-    mediaTypes:
-      - banner
-      - video
-  site:
-    mediaTypes:
-      - banner
-      - video
-userSync:
-  iframe:
-    url: "https://ads.pubmatic.com/AdServer/js/user_sync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&predirect={{.RedirectURL}}"
-    userMacro: ""
-    # groupm appends the user id to end of the redirect url and does not utilize a macro
-
-
diff --git a/static/bidder-info/mgidX.yaml b/static/bidder-info/mgidX.yaml
new file mode 100644
index 00000000..ab783beb
--- /dev/null
+++ b/static/bidder-info/mgidX.yaml
@@ -0,0 +1,23 @@
+endpoint: "https://us-east-x.mgid.com/pserver"
+maintainer:
+  email: "prebid@mgid.com"
+gvlVendorID: 358
+capabilities:
+  site:
+    mediaTypes:
+    - banner
+    - video
+    - native
+    
+  app:
+    mediaTypes:
+    - banner
+    - video
+    - native
+userSync:
+  redirect:
+    url: "https://cm.mgid.com/i.gif?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&adu={{.RedirectURL}}"
+    userMacro: "{muidn}"
+  iframe:
+    url: "https://cm.mgid.com/i.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&adu={{.RedirectURL}}"
+    userMacro: "{muidn}"
diff --git a/static/bidder-info/motorik.yaml b/static/bidder-info/motorik.yaml
new file mode 100644
index 00000000..6818de9d
--- /dev/null
+++ b/static/bidder-info/motorik.yaml
@@ -0,0 +1,14 @@
+endpoint: "http://lb-east.motorik.io/?k={{.AccountID}}&name={{.SourceId}}"
+maintainer:
+  email: "support@motorik.io"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - native
\ No newline at end of file
diff --git a/static/bidder-info/verizonmedia.yaml b/static/bidder-info/verizonmedia.yaml
deleted file mode 100644
index 9be15b84..00000000
--- a/static/bidder-info/verizonmedia.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-disabled: true
-maintainer:
-  email: "dsp-supply-prebid@verizonmedia.com"
-gvlVendorID: 25
-capabilities:
-  app:
-    mediaTypes:
-      - banner
-  site:
-    mediaTypes:
-      - banner
-userSync:
-  # verizonmedia supports user syncing, but requires configuration by the host. contact this
-  # bidder directly at the email address in this file to ask about enabling user sync.
-  supports:
-    - redirect
\ No newline at end of file
diff --git a/static/bidder-info/yahooAdvertising.yaml b/static/bidder-info/yahooAdvertising.yaml
new file mode 100644
index 00000000..3798adf7
--- /dev/null
+++ b/static/bidder-info/yahooAdvertising.yaml
@@ -0,0 +1,18 @@
+endpoint: "https://s2shb.ssp.yahoo.com/admax/bid/partners/PBS"
+maintainer:
+  email: "hb-fe-tech@yahooinc.com"
+gvlVendorID: 25
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+  site:
+    mediaTypes:
+      - banner
+      - video
+userSync:
+  # yahooAdvertising supports user syncing, but requires configuration by the host. contact this
+  # bidder directly at the email address in this file to ask about enabling user sync.
+  supports:
+    - redirect
\ No newline at end of file
diff --git a/static/bidder-params/conversant.json b/static/bidder-params/conversant.json
index ba9c6bd5..883ef053 100644
--- a/static/bidder-params/conversant.json
+++ b/static/bidder-params/conversant.json
@@ -1,12 +1,12 @@
 {
   "$schema": "http://json-schema.org/draft-04/schema#",
-  "title": "Conversant Adapter Params",
-  "description": "A schema which validates params accepted by the Conversant adapter.",
+  "title": "Epsilon (formerly Conversant) Adapter Params",
+  "description": "A schema which validates params accepted by the Epsilon (Conversant) adapter.",
   "type": "object",
   "properties": {
     "site_id": {
       "type": "string",
-      "description": "A Conversant specific ID which identifies the site."
+      "description": "An Epsilon (Conversant) specific ID which identifies the site."
     },
    	"secure": {
    	  "type": "integer",
diff --git a/static/bidder-params/epsilon.json b/static/bidder-params/epsilon.json
new file mode 100644
index 00000000..a33a6832
--- /dev/null
+++ b/static/bidder-params/epsilon.json
@@ -0,0 +1,54 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Epsilon Adapter Params",
+  "description": "A schema which validates params accepted by the Epsilon adapter.",
+  "type": "object",
+  "properties": {
+    "site_id": {
+      "type": "string",
+      "description": "An Epsilon specific ID which identifies the site."
+    },
+    "secure": {
+      "type": "integer",
+      "description": "Override http/https context on ad markup."
+    },
+    "bidfloor" : {
+      "type": "number",
+      "description": "Minimum bid price that will be considered."
+    },
+    "tag_id": {
+      "type": "string",
+      "description": "Identifies specific ad placement."
+    },
+    "position": {
+      "type": "integer",
+      "description": "Ad position on screen."
+    },
+    "mimes": {
+      "type": "array",
+      "description": "Array of content MIME types.  For videos only.",
+      "items": {
+        "type": "string"
+      }
+    },
+    "maxduration": {
+      "type": "integer",
+      "description": "Maximum duration in seconds.  For videos only."
+    },
+    "api": {
+      "type": "array",
+      "description": "Array of supported API frameworks.  For videos only.",
+      "items": {
+        "type": "integer"
+      }
+    },
+    "protocols": {
+      "type": "array",
+      "description": "Array of supported video protocols.  For videos only.",
+      "items": {
+        "type": "integer"
+      }
+    }
+  },
+  "required": ["site_id"]
+}
\ No newline at end of file
diff --git a/static/bidder-params/groupm.json b/static/bidder-params/groupm.json
deleted file mode 100644
index cfebd2ad..00000000
--- a/static/bidder-params/groupm.json
+++ /dev/null
@@ -1,61 +0,0 @@
-{
-	"$schema": "http://json-schema.org/draft-04/schema#",
-	"title": "Groupm Adapter Params",
-	"description": "A schema which validates params accepted by the Groupm adapter",
-	"type": "object",
-	"properties": {
-		"publisherId": {
-			"type": "string",
-			"description": "An ID which identifies the publisher"
-		},
-		"adSlot": {
-			"type": "string",
-			"description": "An ID which identifies the ad slot"
-		},
-		"pmzoneid": {
-			"type": "string",
-			"description": "Comma separated zone id. Used im deal targeting & site section targeting. e.g drama,sport"
-		},
-		"dctr": {
-			"type": "string",
-			"description": "Deals Custom Targeting, pipe separated key-value pairs e.g key1=V1,V2,V3|key2=v1|key3=v3,v5"
-		},
-		"wrapper": {
-			"type": "object",
-			"description": "Specifies Groupm openwrap configuration for a publisher",
-			"properties": {
-				"profile": {
-					"type": "integer",
-					"description": "An ID which identifies the openwrap profile of publisher"
-				},
-				"version": {
-					"type": "integer",
-					"description": "An ID which identifies version of the openwrap profile"
-				}
-			},
-			"required": ["profile"]
-		},
-		"keywords": {
-			"type": "array",
-			"minItems": 1,
-			"items": {
-			  "type": "object",
-			  "description": "A key with one or more values associated with it. These are used in buy-side segment targeting.",
-			  "properties": {
-				"key": {
-				  "type": "string"
-				},
-				"value": {
-				  "type": "array",
-				  "minItems": 1,
-				  "items": {
-					"type": "string"
-				  }
-				}
-			  },
-			  "required": ["key", "value"]
-			}
-		  }
-	},
-	"required": ["publisherId"]
-}
diff --git a/static/bidder-params/mgidX.json b/static/bidder-params/mgidX.json
new file mode 100644
index 00000000..7b24582d
--- /dev/null
+++ b/static/bidder-params/mgidX.json
@@ -0,0 +1,23 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "MGIDX Adapter Params",
+    "description": "A schema which validates params accepted by the MGIDX adapter",
+    "type": "object",
+  
+    "properties": {
+      "placementId": {
+        "type": "string",
+        "minLength": 1,
+        "description": "Placement ID"
+      },
+      "endpointId": {
+        "type": "string",
+        "minLength": 1,
+        "description": "Endpoint ID"
+      }
+    },
+    "oneOf": [
+      { "required": ["placementId"] },
+      { "required": ["endpointId"] }
+    ]
+  }
\ No newline at end of file
diff --git a/static/bidder-params/motorik.json b/static/bidder-params/motorik.json
new file mode 100644
index 00000000..261e9c1e
--- /dev/null
+++ b/static/bidder-params/motorik.json
@@ -0,0 +1,19 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "Motorik Adapter Params",
+    "description": "A schema which validates params accepted by the Motorik adapter",
+    "type": "object",
+    "properties": {
+      "accountId": {
+        "type": "string",
+        "description": "Account id",
+        "minLength": 1
+      },
+      "placementId": {
+        "type": "string",
+        "description": "Placement id",
+        "minLength": 1
+      }
+    },
+    "required": ["accountId", "placementId"]
+  }
\ No newline at end of file
diff --git a/static/bidder-params/verizonmedia.json b/static/bidder-params/yahooAdvertising.json
similarity index 75%
rename from static/bidder-params/verizonmedia.json
rename to static/bidder-params/yahooAdvertising.json
index 96649f08..4778f077 100644
--- a/static/bidder-params/verizonmedia.json
+++ b/static/bidder-params/yahooAdvertising.json
@@ -1,15 +1,17 @@
 {
 	"$schema": "http://json-schema.org/draft-04/schema#",
-	"title": "VerizonMedia Adapter Params",
-	"description": "A schema which validates params accepted by the VerizonMedia adapter",
+	"title": "YahooAdvertising Adapter Params",
+	"description": "A schema which validates params accepted by the YahooAdvertising adapter",
 	"type": "object",
 	"properties": {
 		"dcn": {
 			"type": "string",
+			"minLength": 1,
 			"description": "Site ID provided by One Mobile"
 		},
 		"pos": {
 			"type": "string",
+			"minLength": 1,
 			"description": "Placement ID"
 		}
 	},
diff --git a/usersync/cookie.go b/usersync/cookie.go
index 51474afd..4f80fa5d 100644
--- a/usersync/cookie.go
+++ b/usersync/cookie.go
@@ -23,9 +23,8 @@ const uidTTL = 14 * 24 * time.Hour
 // To get an instance of this from a request, use ParseCookieFromRequest.
 // To write an instance onto a response, use SetCookieOnResponse.
 type Cookie struct {
-	uids     map[string]uidWithExpiry
-	optOut   bool
-	birthday *time.Time
+	uids   map[string]uidWithExpiry
+	optOut bool
 }
 
 // uidWithExpiry bundles the UID with an Expiration date.
@@ -83,8 +82,7 @@ func ParseCookie(httpCookie *http.Cookie) *Cookie {
 // NewCookie returns a new empty cookie.
 func NewCookie() *Cookie {
 	return &Cookie{
-		uids:     make(map[string]uidWithExpiry),
-		birthday: timestamp(),
+		uids: make(map[string]uidWithExpiry),
 	}
 }
 
@@ -226,16 +224,14 @@ func (cookie *Cookie) TrySync(key string, uid string) error {
 // This exists so that Cookie (which is public) can have private fields, and the rest of
 // the code doesn't have to worry about the cookie data storage format.
 type cookieJson struct {
-	UIDs     map[string]uidWithExpiry `json:"tempUIDs,omitempty"`
-	OptOut   bool                     `json:"optout,omitempty"`
-	Birthday *time.Time               `json:"bday,omitempty"`
+	UIDs   map[string]uidWithExpiry `json:"tempUIDs,omitempty"`
+	OptOut bool                     `json:"optout,omitempty"`
 }
 
 func (cookie *Cookie) MarshalJSON() ([]byte, error) {
 	return json.Marshal(cookieJson{
-		UIDs:     cookie.uids,
-		OptOut:   cookie.optOut,
-		Birthday: cookie.birthday,
+		UIDs:   cookie.uids,
+		OptOut: cookie.optOut,
 	})
 }
 
@@ -246,7 +242,6 @@ func (cookie *Cookie) UnmarshalJSON(b []byte) error {
 	}
 
 	cookie.optOut = cookieContract.OptOut
-	cookie.birthday = cookieContract.Birthday
 
 	if cookie.optOut {
 		cookie.uids = nil
@@ -265,8 +260,3 @@ func (cookie *Cookie) UnmarshalJSON(b []byte) error {
 
 	return nil
 }
-
-func timestamp() *time.Time {
-	birthday := time.Now()
-	return &birthday
-}
diff --git a/util/httputil/httputil.go b/util/httputil/httputil.go
index 99236489..28334a54 100644
--- a/util/httputil/httputil.go
+++ b/util/httputil/httputil.go
@@ -14,6 +14,16 @@ var (
 	xRealIP       = http.CanonicalHeaderKey("X-Real-IP")
 )
 
+type ContentEncoding string
+
+const (
+	ContentEncodingGZIP ContentEncoding = "gzip"
+)
+
+func (k ContentEncoding) Normalize() ContentEncoding {
+	return ContentEncoding(strings.ToLower(string(k)))
+}
+
 // FindIP returns the first ip address found in the http request matching the predicate v.
 func FindIP(r *http.Request, v iputil.IPValidator) (net.IP, iputil.IPVersion) {
 	if ip, ver := findTrueClientIP(r, v); ip != nil {


Test patch:
diff --git a/adapters/mgidX/mgidX_test.go b/adapters/mgidX/mgidX_test.go
new file mode 100644
index 00000000..5a717507
--- /dev/null
+++ b/adapters/mgidX/mgidX_test.go
@@ -0,0 +1,20 @@
+package mgidX
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderEmtv, config.Adapter{
+		Endpoint: "http://example.com/pserver"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "mgidXtest", bidder)
+}
diff --git a/adapters/mgidX/mgidXtest/exemplary/endpointId.json b/adapters/mgidX/mgidXtest/exemplary/endpointId.json
new file mode 100644
index 00000000..2c3b74bc
--- /dev/null
+++ b/adapters/mgidX/mgidXtest/exemplary/endpointId.json
@@ -0,0 +1,133 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "device": {
+            "ip": "123.123.123.123",
+            "ua": "iPad"
+        },
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "tagid": "test",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "endpointId": "test"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://example.com/pserver",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "tagid": "test",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ]
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "endpointId": "test",
+                                    "type": "network"
+                                }
+                            }
+                        }
+                    ],
+                    "app": {
+                        "id": "1",
+                        "bundle": "com.wls.testwlsapplication"
+                    },
+                    "device": {
+                        "ip": "123.123.123.123",
+                        "ua": "iPad"
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "bid": [
+                                {
+                                    "id": "test_bid_id",
+                                    "impid": "test-imp-id",
+                                    "price": 0.27543,
+                                    "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"http://example.com/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                                    "cid": "test_cid",
+                                    "crid": "test_crid",
+                                    "dealid": "test_dealid",
+                                    "w": 300,
+                                    "h": 250,
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "banner"
+                                        }
+                                    }
+                                }
+                            ],
+                            "seat": "mgidX"
+                        }
+                    ],
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test_bid_id",
+                        "impid": "test-imp-id",
+                        "price": 0.27543,
+                        "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"http://example.com/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                        "cid": "test_cid",
+                        "crid": "test_crid",
+                        "dealid": "test_dealid",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "prebid": {
+                                "type": "banner"
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/mgidX/mgidXtest/exemplary/simple-banner.json b/adapters/mgidX/mgidXtest/exemplary/simple-banner.json
new file mode 100644
index 00000000..69c65439
--- /dev/null
+++ b/adapters/mgidX/mgidXtest/exemplary/simple-banner.json
@@ -0,0 +1,133 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "device": {
+            "ip": "123.123.123.123",
+            "ua": "iPad"
+        },
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "tagid": "test",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placementId": "test"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://example.com/pserver",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "tagid": "test",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ]
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": "test",
+                                    "type": "publisher"
+                                }
+                            }
+                        }
+                    ],
+                    "app": {
+                        "id": "1",
+                        "bundle": "com.wls.testwlsapplication"
+                    },
+                    "device": {
+                        "ip": "123.123.123.123",
+                        "ua": "iPad"
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "bid": [
+                                {
+                                    "id": "test_bid_id",
+                                    "impid": "test-imp-id",
+                                    "price": 0.27543,
+                                    "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"http://example.com/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                                    "cid": "test_cid",
+                                    "crid": "test_crid",
+                                    "dealid": "test_dealid",
+                                    "w": 300,
+                                    "h": 250,
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "banner"
+                                        }
+                                    }
+                                }
+                            ],
+                            "seat": "mgidX"
+                        }
+                    ],
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test_bid_id",
+                        "impid": "test-imp-id",
+                        "price": 0.27543,
+                        "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"http://example.com/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                        "cid": "test_cid",
+                        "crid": "test_crid",
+                        "dealid": "test_dealid",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "prebid": {
+                                "type": "banner"
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/mgidX/mgidXtest/exemplary/simple-native.json b/adapters/mgidX/mgidXtest/exemplary/simple-native.json
new file mode 100644
index 00000000..74b2e31f
--- /dev/null
+++ b/adapters/mgidX/mgidXtest/exemplary/simple-native.json
@@ -0,0 +1,117 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "device": {
+            "ip": "123.123.123.123",
+            "ua": "iPad"
+        },
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "tagid": "test",
+                "native": {
+                    "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}",
+                    "ver": "1.1"
+                },
+                "ext": {
+                    "bidder": {
+                        "placementId": "test"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://example.com/pserver",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "tagid": "test",
+                            "native": {
+                                "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}",
+                                "ver": "1.1"
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": "test",
+                                    "type": "publisher"
+                                }
+                            }
+                        }
+                    ],
+                    "app": {
+                        "id": "1",
+                        "bundle": "com.wls.testwlsapplication"
+                    },
+                    "device": {
+                        "ip": "123.123.123.123",
+                        "ua": "iPad"
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "bid": [
+                                {
+                                    "id": "test_bid_id",
+                                    "impid": "test-imp-id",
+                                    "price": 0.27543,
+                                    "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"http://example.com/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                                    "cid": "test_cid",
+                                    "crid": "test_crid",
+                                    "dealid": "test_dealid",
+                                    "w": 300,
+                                    "h": 250,
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "native"
+                                        }
+                                    }
+                                }
+                            ],
+                            "seat": "mgidX"
+                        }
+                    ],
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test_bid_id",
+                        "impid": "test-imp-id",
+                        "price": 0.27543,
+                        "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"http://example.com/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                        "cid": "test_cid",
+                        "crid": "test_crid",
+                        "dealid": "test_dealid",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "prebid": {
+                                "type": "native"
+                            }
+                        }
+                    },
+                    "type": "native"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/mgidX/mgidXtest/exemplary/simple-video.json b/adapters/mgidX/mgidXtest/exemplary/simple-video.json
new file mode 100644
index 00000000..29159388
--- /dev/null
+++ b/adapters/mgidX/mgidXtest/exemplary/simple-video.json
@@ -0,0 +1,128 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "device": {
+            "ip": "123.123.123.123",
+            "ua": "iPad"
+        },
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "tagid": "test",
+                "video": {
+                    "mimes": [
+                        "video/mp4"
+                    ],
+                    "protocols": [
+                        2,
+                        5
+                    ],
+                    "w": 1024,
+                    "h": 576
+                },
+                "ext": {
+                    "bidder": {
+                        "placementId": "test"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://example.com/pserver",
+                "body": {
+                    "id": "test-request-id",
+                    "device": {
+                        "ip": "123.123.123.123",
+                        "ua": "iPad"
+                    },
+                    "app": {
+                        "id": "1",
+                        "bundle": "com.wls.testwlsapplication"
+                    },
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "tagid": "test",
+                            "video": {
+                                "mimes": [
+                                    "video/mp4"
+                                ],
+                                "protocols": [
+                                    2,
+                                    5
+                                ],
+                                "w": 1024,
+                                "h": 576
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": "test",
+                                    "type": "publisher"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "bid": [
+                                {
+                                    "id": "test_bid_id",
+                                    "impid": "test-imp-id",
+                                    "price": 0.27543,
+                                    "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>",
+                                    "cid": "test_cid",
+                                    "crid": "test_crid",
+                                    "dealid": "test_dealid",
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "video"
+                                        }
+                                    }
+                                }
+                            ],
+                            "seat": "mgidX"
+                        }
+                    ],
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test_bid_id",
+                        "impid": "test-imp-id",
+                        "price": 0.27543,
+                        "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>",
+                        "cid": "test_cid",
+                        "crid": "test_crid",
+                        "dealid": "test_dealid",
+                        "ext": {
+                            "prebid": {
+                                "type": "video"
+                            }
+                        }
+                    },
+                    "type": "video"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/mgidX/mgidXtest/exemplary/simple-web-banner.json b/adapters/mgidX/mgidXtest/exemplary/simple-web-banner.json
new file mode 100644
index 00000000..6460b410
--- /dev/null
+++ b/adapters/mgidX/mgidXtest/exemplary/simple-web-banner.json
@@ -0,0 +1,133 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "tagid": "test",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placementId": "test"
+                    }
+                }
+            }
+        ],
+        "site": {
+            "id": "1",
+            "domain": "test.com"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ua": "Ubuntu"
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://example.com/pserver",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "tagid": "test",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ]
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": "test",
+                                    "type": "publisher"
+                                }
+                            }
+                        }
+                    ],
+                    "site": {
+                        "id": "1",
+                        "domain": "test.com"
+                    },
+                    "device": {
+                        "ip": "123.123.123.123",
+                        "ua": "Ubuntu"
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "bid": [
+                                {
+                                    "id": "test_bid_id",
+                                    "impid": "test-imp-id",
+                                    "price": 0.27543,
+                                    "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"http://example.com/pserver&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>",
+                                    "cid": "test_cid",
+                                    "crid": "test_crid",
+                                    "dealid": "test_dealid",
+                                    "w": 468,
+                                    "h": 60,
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "banner"
+                                        }
+                                    }
+                                }
+                            ],
+                            "seat": "mgidX"
+                        }
+                    ],
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test_bid_id",
+                        "impid": "test-imp-id",
+                        "price": 0.27543,
+                        "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"http://example.com/pserver&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>",
+                        "cid": "test_cid",
+                        "crid": "test_crid",
+                        "dealid": "test_dealid",
+                        "w": 468,
+                        "h": 60,
+                        "ext": {
+                            "prebid": {
+                                "type": "banner"
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/mgidX/mgidXtest/supplemental/bad_media_type.json b/adapters/mgidX/mgidXtest/supplemental/bad_media_type.json
new file mode 100644
index 00000000..22d09ce2
--- /dev/null
+++ b/adapters/mgidX/mgidXtest/supplemental/bad_media_type.json
@@ -0,0 +1,82 @@
+{
+	"mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "ext": {
+                    "bidder": {
+                        "placementId": "test"
+                    }
+                }
+            }
+        ],
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+        }
+    },
+	"httpCalls": [{
+		"expectedRequest": {
+			"uri": "http://example.com/pserver",
+			"body": {
+                "id": "test-request-id",
+                "imp": [
+                    {
+                        "id": "test-imp-id",
+                        "ext": {
+                            "bidder": {
+                                "placementId": "test",
+                                "type": "publisher"
+                            }
+                        }
+                    }
+                ],
+                "app": {
+                    "id": "1",
+                    "bundle": "com.wls.testwlsapplication"
+                },
+                "device": {
+                    "ip": "123.123.123.123",
+                    "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+                }
+            }
+		},
+		"mockResponse": {
+			"status": 200,
+			"body": {
+                "id": "test-request-id",
+                "seatbid": [
+                    {
+                        "bid": [
+                            {
+                                "id": "test_bid_id",
+                                "impid": "test-imp-id",
+                                "price": 0.27543,
+                                "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"http://example.com/pserver&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                                "cid": "test_cid",
+                                "crid": "test_crid",
+                                "dealid": "test_dealid",
+                                "w": 300,
+                                "h": 250,
+                                "ext": {}
+                            }
+                        ],
+                        "seat": "mgidX"
+                    }
+                ],
+                "cur": "USD"
+            }
+        }
+    }],
+    "expectedMakeBidsErrors": [
+        {
+          "value": "imp test-imp-id with unknown media type",
+          "comparison": "literal"
+        }
+    ]
+}
diff --git a/adapters/mgidX/mgidXtest/supplemental/bad_response.json b/adapters/mgidX/mgidXtest/supplemental/bad_response.json
new file mode 100644
index 00000000..8c1cc375
--- /dev/null
+++ b/adapters/mgidX/mgidXtest/supplemental/bad_response.json
@@ -0,0 +1,84 @@
+{
+	"mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placementId": "test"
+                    }
+                }
+            }
+        ],
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+        }
+    },
+	"httpCalls": [{
+		"expectedRequest": {
+			"uri": "http://example.com/pserver",
+			"body": {
+                "id": "test-request-id",
+                "imp": [
+                    {
+                        "id": "test-imp-id",
+                        "banner": {
+                            "format": [
+                                {
+                                    "w": 300,
+                                    "h": 250
+                                },
+                                {
+                                    "w": 300,
+                                    "h": 600
+                                }
+                            ]
+                        },
+                        "ext": {
+                            "bidder": {
+                                "placementId": "test",
+                                "type": "publisher"
+                            }
+                        }
+                    }
+                ],
+                "app": {
+                    "id": "1",
+                    "bundle": "com.wls.testwlsapplication"
+                },
+                "device": {
+                    "ip": "123.123.123.123",
+                    "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+                }
+            }
+		},
+		"mockResponse": {
+			"status": 200,
+			"body": ""
+        }
+    }],
+    "expectedMakeBidsErrors": [
+        {
+          "value": "json: cannot unmarshal string into Go value of type openrtb2.BidResponse",
+          "comparison": "literal"
+        }
+    ]
+}
diff --git a/adapters/mgidX/mgidXtest/supplemental/no-valid-impressions.json b/adapters/mgidX/mgidXtest/supplemental/no-valid-impressions.json
new file mode 100644
index 00000000..cc1edd68
--- /dev/null
+++ b/adapters/mgidX/mgidXtest/supplemental/no-valid-impressions.json
@@ -0,0 +1,20 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [],
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "found no valid impressions",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/mgidX/mgidXtest/supplemental/status-204.json b/adapters/mgidX/mgidXtest/supplemental/status-204.json
new file mode 100644
index 00000000..3e536c25
--- /dev/null
+++ b/adapters/mgidX/mgidXtest/supplemental/status-204.json
@@ -0,0 +1,79 @@
+{
+	"mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placementId": "test"
+                    }
+                }
+            }
+        ],
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+        }
+    },
+	"httpCalls": [{
+		"expectedRequest": {
+			"uri": "http://example.com/pserver",
+			"body": {
+                "id": "test-request-id",
+                "imp": [
+                    {
+                        "id": "test-imp-id",
+                        "banner": {
+                            "format": [
+                                {
+                                    "w": 300,
+                                    "h": 250
+                                },
+                                {
+                                    "w": 300,
+                                    "h": 600
+                                }
+                            ]
+                        },
+                        "ext": {
+                            "bidder": {
+                                "placementId": "test",
+                                "type": "publisher"
+                            }
+                        }
+                    }
+                ],
+                "app": {
+                    "id": "1",
+                    "bundle": "com.wls.testwlsapplication"
+                },
+                "device": {
+                    "ip": "123.123.123.123",
+                    "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+                }
+            }
+		},
+		"mockResponse": {
+			"status": 204,
+			"body": {}
+		}
+    }],
+    "expectedBidResponses": []
+}
diff --git a/adapters/mgidX/mgidXtest/supplemental/status-not-200.json b/adapters/mgidX/mgidXtest/supplemental/status-not-200.json
new file mode 100644
index 00000000..4bb3c8d5
--- /dev/null
+++ b/adapters/mgidX/mgidXtest/supplemental/status-not-200.json
@@ -0,0 +1,84 @@
+{
+	"mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placementId": "test"
+                    }
+                }
+            }
+        ],
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+        }
+    },
+	"httpCalls": [{
+		"expectedRequest": {
+			"uri": "http://example.com/pserver",
+			"body": {
+                "id": "test-request-id",
+                "imp": [
+                    {
+                        "id": "test-imp-id",
+                        "banner": {
+                            "format": [
+                                {
+                                    "w": 300,
+                                    "h": 250
+                                },
+                                {
+                                    "w": 300,
+                                    "h": 600
+                                }
+                            ]
+                        },
+                        "ext": {
+                            "bidder": {
+                                "placementId": "test",
+                                "type": "publisher"
+                            }
+                        }
+                    }
+                ],
+                "app": {
+                    "id": "1",
+                    "bundle": "com.wls.testwlsapplication"
+                },
+                "device": {
+                    "ip": "123.123.123.123",
+                    "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+                }
+            }
+		},
+		"mockResponse": {
+			"status": 404,
+			"body": {}
+		}
+    }],
+    "expectedMakeBidsErrors": [
+        {
+          "value": "Unexpected status code: 404. Run with request.debug = 1 for more info",
+          "comparison": "literal"
+        }
+    ]
+}
diff --git a/adapters/mgidX/params_test.go b/adapters/mgidX/params_test.go
new file mode 100644
index 00000000..85779ec6
--- /dev/null
+++ b/adapters/mgidX/params_test.go
@@ -0,0 +1,47 @@
+package mgidX
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestValidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json schema. %v", err)
+	}
+
+	for _, p := range validParams {
+		if err := validator.Validate(openrtb_ext.BidderMgidX, json.RawMessage(p)); err != nil {
+			t.Errorf("Schema rejected valid params: %s", p)
+		}
+	}
+}
+
+func TestInvalidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json schema. %v", err)
+	}
+
+	for _, p := range invalidParams {
+		if err := validator.Validate(openrtb_ext.BidderMgidX, json.RawMessage(p)); err == nil {
+			t.Errorf("Schema allowed invalid params: %s", p)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"placementId": "test"}`,
+	`{"placementId": "1"}`,
+	`{"endpointId": "test"}`,
+	`{"endpointId": "1"}`,
+}
+
+var invalidParams = []string{
+	`{"placementId": 42}`,
+	`{"endpointId": 42}`,
+	`{"placementId": "1", "endpointId": "1"}`,
+}
diff --git a/adapters/motorik/motorik_test.go b/adapters/motorik/motorik_test.go
new file mode 100644
index 00000000..1a14feda
--- /dev/null
+++ b/adapters/motorik/motorik_test.go
@@ -0,0 +1,28 @@
+package motorik
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderMotorik, config.Adapter{
+		Endpoint: "http://us.example.com/?k={{.AccountID}}&name={{.SourceId}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "motoriktest", bidder)
+}
+
+func TestEndpointTemplateMalformed(t *testing.T) {
+	_, buildErr := Builder(openrtb_ext.BidderMotorik, config.Adapter{
+		Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
+
+	assert.Error(t, buildErr)
+}
diff --git a/adapters/motorik/motoriktest/exemplary/banner-app.json b/adapters/motorik/motoriktest/exemplary/banner-app.json
new file mode 100644
index 00000000..18d8efc7
--- /dev/null
+++ b/adapters/motorik/motoriktest/exemplary/banner-app.json
@@ -0,0 +1,150 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "1",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://us.example.com/?k=accountId&name=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "1",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "1",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50
+                }
+              ],
+              "type": "banner",
+              "seat": "motorik"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "1",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 320,
+            "h": 50
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/motorik/motoriktest/exemplary/banner-web.json b/adapters/motorik/motoriktest/exemplary/banner-web.json
new file mode 100644
index 00000000..024b553a
--- /dev/null
+++ b/adapters/motorik/motoriktest/exemplary/banner-web.json
@@ -0,0 +1,193 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id1",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w":320,
+          "h":50
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      },     
+       {
+        "id": "some-impression-id2",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w":320,
+          "h":50
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://us.example.com/?k=accountId&name=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id1",
+              "tagid": "ogTAGID",
+              "banner": {
+                "w":320,
+                "h":50
+              }
+            },
+            {
+              "id": "some-impression-id2",
+              "tagid": "ogTAGID",
+              "banner": {
+                "w":320,
+                "h":50
+              },
+              "ext": {
+                "bidder": {
+                  "accountId": "accountId",
+                  "placementId": "placementId"
+              }
+            }
+        }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id1",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50
+                },
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e162",
+                  "impid": "some-impression-id2",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50
+                }
+              ],
+              "type": "banner",
+              "seat": "motorik"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id1",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "w": 320,
+            "h": 50
+          },
+          "type": "banner"
+        },
+        {
+          "bid":  {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e162",
+            "impid": "some-impression-id2",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "w": 320,
+            "h": 50
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/motorik/motoriktest/exemplary/native-app.json b/adapters/motorik/motoriktest/exemplary/native-app.json
new file mode 100644
index 00000000..2f917f02
--- /dev/null
+++ b/adapters/motorik/motoriktest/exemplary/native-app.json
@@ -0,0 +1,147 @@
+{
+    "mockBidRequest": {
+      "id": "some-request-id",
+      "device": {
+        "ua": "test-user-agent",
+        "ip": "123.123.123.123",
+        "language": "en",
+        "dnt": 0
+      },
+      "tmax": 1000,
+      "user": {
+        "buyeruid": "awesome-user"
+      },
+      "app": {
+        "publisher": {
+          "id": "123456789"
+        },
+        "cat": [
+          "IAB22-1"
+        ],
+        "bundle": "com.app.awesome",
+        "name": "Awesome App",
+        "domain": "awesomeapp.com",
+        "id": "123456789"
+      },
+      "imp": [
+        {
+          "id": "some-impression-id",
+          "tagid": "ogTAGID",
+          "native": {
+            "ver":"1.1",
+            "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+          },
+          "ext": {
+            "bidder": {
+              "accountId": "accountId",
+              "placementId": "placementId"
+            }
+          }
+        }
+      ]
+    },
+    "httpCalls": [
+      {
+        "expectedRequest": {
+          "headers": {
+            "Content-Type": [
+              "application/json;charset=utf-8"
+            ],
+            "Accept": [
+              "application/json"
+            ],
+            "X-Openrtb-Version": [
+              "2.5"
+            ],
+            "User-Agent": [
+              "test-user-agent"
+            ],
+            "X-Forwarded-For": [
+              "123.123.123.123"
+            ]
+          },
+          "uri": "http://us.example.com/?k=accountId&name=placementId",
+          "body": {
+            "id": "some-request-id",
+            "device": {
+              "ua": "test-user-agent",
+              "ip": "123.123.123.123",
+              "language": "en",
+              "dnt": 0
+            },
+            "imp": [
+              {
+                "id": "some-impression-id",
+                "native": {
+                  "ver":"1.1",
+                  "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+                },
+                "tagid": "ogTAGID"
+              }
+            ],
+            "app": {
+              "id": "123456789",
+              "name": "Awesome App",
+              "bundle": "com.app.awesome",
+              "domain": "awesomeapp.com",
+              "cat": [
+                "IAB22-1"
+              ],
+              "publisher": {
+                "id": "123456789"
+              }
+            },
+            "user": {
+              "buyeruid": "awesome-user"
+            },
+            "tmax": 1000
+          }
+        },
+        "mockResponse": {
+          "status": 200,
+          "body": {
+            "id": "awesome-resp-id",
+            "seatbid": [
+              {
+                "bid": [
+                  {
+                    "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                    "impid": "some-impression-id",
+                    "price": 3.5,
+                    "adm": "awesome-markup",
+                    "adomain": [
+                      "awesome.com"
+                    ],
+                    "crid": "20"
+                  }
+                ],
+                "type": "native",
+                "seat": "motorik"
+              }
+            ],
+            "cur": "USD"
+          }
+        }
+      }
+    ],
+    "expectedBidResponses": [
+      {
+        "bids":[
+          {
+            "bid":  {
+              "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+              "impid": "some-impression-id",
+              "price": 3.5,
+              "adm": "awesome-markup",
+              "crid": "20",
+              "adomain": [
+                "awesome.com"
+              ]
+            },
+            "type": "native"
+          }
+        ]
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/adapters/motorik/motoriktest/exemplary/native-web.json b/adapters/motorik/motoriktest/exemplary/native-web.json
new file mode 100644
index 00000000..7ffc0bb2
--- /dev/null
+++ b/adapters/motorik/motoriktest/exemplary/native-web.json
@@ -0,0 +1,133 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "native": {
+          "ver":"1.1",
+          "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "2607:fb90:f27:4512:d800:cb23:a603:e245"
+          ]
+        },
+        "uri": "http://us.example.com/?k=accountId&name=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "native": {
+                "ver":"1.1",
+                "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20"
+                }
+              ],
+              "seat": "motorik"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ]
+          },
+          "type": "native"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/motorik/motoriktest/exemplary/video-app.json b/adapters/motorik/motoriktest/exemplary/video-app.json
new file mode 100644
index 00000000..caee18cd
--- /dev/null
+++ b/adapters/motorik/motoriktest/exemplary/video-app.json
@@ -0,0 +1,159 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://us.example.com/?k=accountId&name=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 1280,
+                  "h": 720
+                }
+              ],
+              "seat": "motorik"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "w": 1280,
+            "h": 720
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/motorik/motoriktest/exemplary/video-web.json b/adapters/motorik/motoriktest/exemplary/video-web.json
new file mode 100644
index 00000000..0c3afebc
--- /dev/null
+++ b/adapters/motorik/motoriktest/exemplary/video-web.json
@@ -0,0 +1,157 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://us.example.com/?k=accountId&name=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 1280,
+                  "h": 720,
+                  "ext": {
+                    "prebid": {
+                      "type": "video"
+                    }
+                  }
+                }
+              ],
+              "seat": "motorik"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 1280,
+            "h": 720,
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          },
+          "type":"video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/motorik/motoriktest/supplemental/bad_media_type.json b/adapters/motorik/motoriktest/supplemental/bad_media_type.json
new file mode 100644
index 00000000..103b9cf8
--- /dev/null
+++ b/adapters/motorik/motoriktest/supplemental/bad_media_type.json
@@ -0,0 +1,135 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "1",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://us.example.com/?k=accountId&name=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "1",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "test-imp-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50
+                }
+              ],
+              "type": "banner",
+              "seat": "motorik"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Failed to find impression \"test-imp-id\"",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/motorik/motoriktest/supplemental/empty-seatbid-array.json b/adapters/motorik/motoriktest/supplemental/empty-seatbid-array.json
new file mode 100644
index 00000000..9447d661
--- /dev/null
+++ b/adapters/motorik/motoriktest/supplemental/empty-seatbid-array.json
@@ -0,0 +1,131 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://us.example.com/?k=accountId&name=placementId",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+    "mockResponse": {
+      "status": 200,
+      "body": "invalid response"
+    },
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Empty SeatBid array",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/motorik/motoriktest/supplemental/invalid-bidder-ext-object.json b/adapters/motorik/motoriktest/supplemental/invalid-bidder-ext-object.json
new file mode 100644
index 00000000..fb89a589
--- /dev/null
+++ b/adapters/motorik/motoriktest/supplemental/invalid-bidder-ext-object.json
@@ -0,0 +1,33 @@
+{
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Error parsing bidderExt - json: cannot unmarshal string into Go value of type openrtb_ext.ExtMotorik",
+      "comparison": "literal"
+    }
+  ],
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "my-adcode",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": "wrongBidderExt"
+        }
+      }
+    ],
+    "site": {
+      "page": "test.com"
+    }
+  },
+  "httpCalls": []
+}
\ No newline at end of file
diff --git a/adapters/motorik/motoriktest/supplemental/invalid-motorik-ext-object.json b/adapters/motorik/motoriktest/supplemental/invalid-motorik-ext-object.json
new file mode 100644
index 00000000..1b2cce8d
--- /dev/null
+++ b/adapters/motorik/motoriktest/supplemental/invalid-motorik-ext-object.json
@@ -0,0 +1,31 @@
+{
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Error parsing motorikExt - json: cannot unmarshal string into Go value of type adapters.ExtImpBidder",
+      "comparison": "literal"
+    }
+  ],
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "my-adcode",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": "wrongMotorikExt"
+      }
+    ],
+    "site": {
+      "page": "test.com"
+    }
+  },
+  "httpCalls": []
+}
\ No newline at end of file
diff --git a/adapters/motorik/motoriktest/supplemental/invalid-response.json b/adapters/motorik/motoriktest/supplemental/invalid-response.json
new file mode 100644
index 00000000..c497f9df
--- /dev/null
+++ b/adapters/motorik/motoriktest/supplemental/invalid-response.json
@@ -0,0 +1,112 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w":320,
+          "h":50
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "headers": {
+        "Content-Type": [
+          "application/json;charset=utf-8"
+        ],
+        "Accept": [
+          "application/json"
+        ],
+        "X-Openrtb-Version": [
+          "2.5"
+        ],
+        "User-Agent": [
+          "test-user-agent"
+        ],
+        "X-Forwarded-For": [
+          "123.123.123.123"
+        ]
+      },
+      "uri": "http://us.example.com/?k=accountId&name=placementId",
+      "body": {
+        "id": "some-request-id",
+        "device": {
+          "ua": "test-user-agent",
+          "ip": "123.123.123.123",
+          "language": "en",
+          "dnt": 0
+        },
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "banner": {
+                "w":320,
+                "h":50
+            },
+            "tagid": "ogTAGID"
+          }
+        ],
+        "app": {
+          "id": "123456789",
+          "name": "Awesome App",
+          "bundle": "com.app.awesome",
+          "domain": "awesomeapp.com",
+          "cat": [
+            "IAB22-1"
+          ],
+          "publisher": {
+            "id": "123456789"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": "invalid response"
+    }
+  }],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bad Server Response",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/motorik/motoriktest/supplemental/status-code-bad-request.json b/adapters/motorik/motoriktest/supplemental/status-code-bad-request.json
new file mode 100644
index 00000000..293c74b8
--- /dev/null
+++ b/adapters/motorik/motoriktest/supplemental/status-code-bad-request.json
@@ -0,0 +1,93 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://us.example.com/?k=accountId&name=placementId",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            },
+            "tagid": "ogTAGID"
+          }
+        ],
+        "app":  {
+          "publisher": {
+            "id": "123456789"
+          },
+          "cat": [
+            "IAB22-1"
+          ],
+          "bundle": "com.app.awesome",
+          "name": "Awesome App",
+          "domain": "awesomeapp.com",
+          "id": "123456789"
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 400
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 400. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/motorik/motoriktest/supplemental/status-code-no-content.json b/adapters/motorik/motoriktest/supplemental/status-code-no-content.json
new file mode 100644
index 00000000..095b869e
--- /dev/null
+++ b/adapters/motorik/motoriktest/supplemental/status-code-no-content.json
@@ -0,0 +1,69 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [{
+      "id": "some-impression-id",
+      "tagid": "ogTAGID",
+      "video": {
+        "mimes": ["video/mp4"],
+        "w": 640,
+        "h": 480,
+        "minduration": 120,
+        "maxduration": 150
+      },
+      "ext": {
+        "bidder": {
+          "accountId": "accountId",
+          "placementId": "placementId"
+        }
+      }
+    }]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://us.example.com/?k=accountId&name=placementId",
+      "body": {
+        "id": "some-request-id",
+        "imp": [{
+          "id": "some-impression-id",
+          "tagid": "ogTAGID",
+          "video": {
+            "mimes": [
+              "video/mp4"
+            ],
+            "minduration": 120,
+            "maxduration": 150,
+            "w": 640,
+            "h": 480
+          }
+        }],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "123456789"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 204
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": []
+}
\ No newline at end of file
diff --git a/adapters/motorik/motoriktest/supplemental/status-code-other-error.json b/adapters/motorik/motoriktest/supplemental/status-code-other-error.json
new file mode 100644
index 00000000..95e607be
--- /dev/null
+++ b/adapters/motorik/motoriktest/supplemental/status-code-other-error.json
@@ -0,0 +1,79 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://us.example.com/?k=accountId&name=placementId",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "tagid": "ogTAGID",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            }
+          }
+        ],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "123456789"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 306
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 306. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/motorik/motoriktest/supplemental/status-code-service-unavailable.json b/adapters/motorik/motoriktest/supplemental/status-code-service-unavailable.json
new file mode 100644
index 00000000..aa03e6f1
--- /dev/null
+++ b/adapters/motorik/motoriktest/supplemental/status-code-service-unavailable.json
@@ -0,0 +1,79 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountId": "accountId",
+            "placementId": "placementId"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://us.example.com/?k=accountId&name=placementId",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "tagid": "ogTAGID",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            }
+          }
+        ],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "123456789"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 503
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Something went wrong Status Code: [ 503 ] ",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/motorik/params_test.go b/adapters/motorik/params_test.go
new file mode 100644
index 00000000..9ee05b58
--- /dev/null
+++ b/adapters/motorik/params_test.go
@@ -0,0 +1,50 @@
+package motorik
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+var validParams = []string{
+	`{  "accountId": "hash",  "placementId": "hash"}`,
+}
+
+func TestValidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, validParam := range validParams {
+		if err := validator.Validate(openrtb_ext.BidderMotorik, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected Motorik params: %s", validParam)
+		}
+	}
+}
+
+var invalidParams = []string{
+	``,
+	`null`,
+	`true`,
+	`5`,
+	`4.2`,
+	`[]`,
+	`{}`,
+	`{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`,
+	`{  "accountid": "" }`,
+}
+
+func TestInvalidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, invalidParam := range invalidParams {
+		if err := validator.Validate(openrtb_ext.BidderMotorik, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
diff --git a/adapters/yahoossp/params_test.go b/adapters/yahooAdvertising/params_test.go
similarity index 63%
rename from adapters/yahoossp/params_test.go
rename to adapters/yahooAdvertising/params_test.go
index 47d8d268..10d504cb 100644
--- a/adapters/yahoossp/params_test.go
+++ b/adapters/yahooAdvertising/params_test.go
@@ -1,4 +1,4 @@
-package yahoossp
+package yahooAdvertising
 
 import (
 	"encoding/json"
@@ -7,11 +7,11 @@ import (
 	"github.com/prebid/prebid-server/openrtb_ext"
 )
 
-// This file actually intends to test static/bidder-params/yahoossp.json
+// This file actually intends to test static/bidder-params/yahooAdvertising.json
 //
-// These also validate the format of the external API: request.imp[i].ext.yahoossp
+// These also validate the format of the external API: request.imp[i].ext.yahooAdvertising
 
-// TestValidParams makes sure that the yahoossp schema accepts all imp.ext fields which we intend to support.
+// TestValidParams makes sure that the yahooAdvertising schema accepts all imp.ext fields which we intend to support.
 func TestValidParams(t *testing.T) {
 	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
 	if err != nil {
@@ -19,13 +19,13 @@ func TestValidParams(t *testing.T) {
 	}
 
 	for _, validParam := range validParams {
-		if err := validator.Validate(openrtb_ext.BidderYahooSSP, json.RawMessage(validParam)); err != nil {
-			t.Errorf("Schema rejected yahoossp params: %s", validParam)
+		if err := validator.Validate(openrtb_ext.BidderYahooAdvertising, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected yahooAdvertising params: %s", validParam)
 		}
 	}
 }
 
-// TestInvalidParams makes sure that the yahoossp schema rejects all the imp.ext fields we don't support.
+// TestInvalidParams makes sure that the yahooAdvertising schema rejects all the imp.ext fields we don't support.
 func TestInvalidParams(t *testing.T) {
 	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
 	if err != nil {
@@ -33,7 +33,7 @@ func TestInvalidParams(t *testing.T) {
 	}
 
 	for _, invalidParam := range invalidParams {
-		if err := validator.Validate(openrtb_ext.BidderYahooSSP, json.RawMessage(invalidParam)); err == nil {
+		if err := validator.Validate(openrtb_ext.BidderYahooAdvertising, json.RawMessage(invalidParam)); err == nil {
 			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
 		}
 	}
diff --git a/adapters/yahoossp/yahoossp_test.go b/adapters/yahooAdvertising/yahooAdvertising_test.go
similarity index 51%
rename from adapters/yahoossp/yahoossp_test.go
rename to adapters/yahooAdvertising/yahooAdvertising_test.go
index eeb739c6..e701c333 100644
--- a/adapters/yahoossp/yahoossp_test.go
+++ b/adapters/yahooAdvertising/yahooAdvertising_test.go
@@ -1,4 +1,4 @@
-package yahoossp
+package yahooAdvertising
 
 import (
 	"testing"
@@ -10,8 +10,8 @@ import (
 	"github.com/prebid/prebid-server/openrtb_ext"
 )
 
-func TestYahooSSPBidderEndpointConfig(t *testing.T) {
-	bidder, buildErr := Builder(openrtb_ext.BidderYahooSSP, config.Adapter{
+func TestYahooAdvertisingBidderEndpointConfig(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderYahooAdvertising, config.Adapter{
 		Endpoint: "http://localhost/bid",
 	}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
 
@@ -19,17 +19,17 @@ func TestYahooSSPBidderEndpointConfig(t *testing.T) {
 		t.Fatalf("Builder returned unexpected error %v", buildErr)
 	}
 
-	bidderYahooSSP := bidder.(*adapter)
+	bidderYahooAdvertising := bidder.(*adapter)
 
-	assert.Equal(t, "http://localhost/bid", bidderYahooSSP.URI)
+	assert.Equal(t, "http://localhost/bid", bidderYahooAdvertising.URI)
 }
 
 func TestJsonSamples(t *testing.T) {
-	bidder, buildErr := Builder(openrtb_ext.BidderYahooSSP, config.Adapter{}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
+	bidder, buildErr := Builder(openrtb_ext.BidderYahooAdvertising, config.Adapter{}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
 
 	if buildErr != nil {
 		t.Fatalf("Builder returned unexpected error %v", buildErr)
 	}
 
-	adapterstest.RunJSONBidderTest(t, "yahoossptest", bidder)
+	adapterstest.RunJSONBidderTest(t, "yahooAdvertisingtest", bidder)
 }
diff --git a/adapters/yahoossp/yahoossptest/exemplary/simple-app-banner.json b/adapters/yahooAdvertising/yahooAdvertisingtest/exemplary/simple-app-banner.json
similarity index 98%
rename from adapters/yahoossp/yahoossptest/exemplary/simple-app-banner.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/exemplary/simple-app-banner.json
index 319e22e3..d5e77c71 100644
--- a/adapters/yahoossp/yahoossptest/exemplary/simple-app-banner.json
+++ b/adapters/yahooAdvertising/yahooAdvertisingtest/exemplary/simple-app-banner.json
@@ -77,7 +77,7 @@
           "id": "test-request-id",
           "seatbid": [
             {
-              "seat": "yahoossp",
+              "seat": "yahooAdvertising",
               "bid": [{
                 "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
                 "impid": "test-imp-id",
diff --git a/adapters/yahoossp/yahoossptest/exemplary/simple-banner.json b/adapters/yahooAdvertising/yahooAdvertisingtest/exemplary/simple-banner.json
similarity index 98%
rename from adapters/yahoossp/yahoossptest/exemplary/simple-banner.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/exemplary/simple-banner.json
index 344bbe9a..d08bdf06 100644
--- a/adapters/yahoossp/yahoossptest/exemplary/simple-banner.json
+++ b/adapters/yahooAdvertising/yahooAdvertisingtest/exemplary/simple-banner.json
@@ -77,7 +77,7 @@
           "id": "test-request-id",
           "seatbid": [
             {
-              "seat": "yahoossp",
+              "seat": "yahooAdvertising",
               "bid": [{
                 "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
                 "impid": "test-imp-id",
diff --git a/adapters/yahoossp/yahoossptest/exemplary/simple-video.json b/adapters/yahooAdvertising/yahooAdvertisingtest/exemplary/simple-video.json
similarity index 98%
rename from adapters/yahoossp/yahoossptest/exemplary/simple-video.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/exemplary/simple-video.json
index d6227264..ea95ec40 100644
--- a/adapters/yahoossp/yahoossptest/exemplary/simple-video.json
+++ b/adapters/yahooAdvertising/yahooAdvertisingtest/exemplary/simple-video.json
@@ -92,7 +92,7 @@
           "id": "test-request-id",
           "seatbid": [
             {
-              "seat": "yahoossp",
+              "seat": "yahooAdvertising",
               "bid": [{
                 "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
                 "impid": "test-imp-id",
diff --git a/adapters/yahoossp/yahoossptest/supplemental/empty-banner-format.json b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/empty-banner-format.json
similarity index 100%
rename from adapters/yahoossp/yahoossptest/supplemental/empty-banner-format.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/empty-banner-format.json
diff --git a/adapters/yahoossp/yahoossptest/supplemental/invalid-banner-height.json b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/invalid-banner-height.json
similarity index 100%
rename from adapters/yahoossp/yahoossptest/supplemental/invalid-banner-height.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/invalid-banner-height.json
diff --git a/adapters/yahoossp/yahoossptest/supplemental/invalid-banner-width.json b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/invalid-banner-width.json
similarity index 100%
rename from adapters/yahoossp/yahoossptest/supplemental/invalid-banner-width.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/invalid-banner-width.json
diff --git a/adapters/yahoossp/yahoossptest/supplemental/non-supported-requests-bids-ignored.json b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/non-supported-requests-bids-ignored.json
similarity index 98%
rename from adapters/yahoossp/yahoossptest/supplemental/non-supported-requests-bids-ignored.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/non-supported-requests-bids-ignored.json
index 11a93f68..a44020da 100644
--- a/adapters/yahoossp/yahoossptest/supplemental/non-supported-requests-bids-ignored.json
+++ b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/non-supported-requests-bids-ignored.json
@@ -74,7 +74,7 @@
           "id": "test-request-id",
           "seatbid": [
             {
-              "seat": "yahoossp",
+              "seat": "yahooAdvertising",
               "bid": [{
                 "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
                 "impid": "test-imp-id",
diff --git a/adapters/yahoossp/yahoossptest/supplemental/required-nobidder-info.json b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/required-nobidder-info.json
similarity index 100%
rename from adapters/yahoossp/yahoossptest/supplemental/required-nobidder-info.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/required-nobidder-info.json
diff --git a/adapters/yahoossp/yahoossptest/supplemental/server-error.json b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/server-error.json
similarity index 100%
rename from adapters/yahoossp/yahoossptest/supplemental/server-error.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/server-error.json
diff --git a/adapters/yahoossp/yahoossptest/supplemental/server-response-wrong-impid.json b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/server-response-wrong-impid.json
similarity index 98%
rename from adapters/yahoossp/yahoossptest/supplemental/server-response-wrong-impid.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/server-response-wrong-impid.json
index 5b33f3af..1fcf61e1 100644
--- a/adapters/yahoossp/yahoossptest/supplemental/server-response-wrong-impid.json
+++ b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/server-response-wrong-impid.json
@@ -76,7 +76,7 @@
           "id": "test-request-id",
           "seatbid": [
             {
-              "seat": "yahoossp",
+              "seat": "yahooAdvertising",
               "bid": [{
                 "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
                 "impid": "wrong",
diff --git a/adapters/yahoossp/yahoossptest/supplemental/simple-banner-gpp-overwrite.json b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/simple-banner-gpp-overwrite.json
similarity index 98%
rename from adapters/yahoossp/yahoossptest/supplemental/simple-banner-gpp-overwrite.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/simple-banner-gpp-overwrite.json
index ffc7ae65..190f96bf 100644
--- a/adapters/yahoossp/yahoossptest/supplemental/simple-banner-gpp-overwrite.json
+++ b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/simple-banner-gpp-overwrite.json
@@ -92,7 +92,7 @@
           "id": "test-request-id",
           "seatbid": [
             {
-              "seat": "yahoossp",
+              "seat": "yahooAdvertising",
               "bid": [{
                 "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
                 "impid": "test-imp-id",
diff --git a/adapters/yahoossp/yahoossptest/supplemental/simple-banner-gpp.json b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/simple-banner-gpp.json
similarity index 98%
rename from adapters/yahoossp/yahoossptest/supplemental/simple-banner-gpp.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/simple-banner-gpp.json
index 88f97d11..81c89f55 100644
--- a/adapters/yahoossp/yahoossptest/supplemental/simple-banner-gpp.json
+++ b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/simple-banner-gpp.json
@@ -87,7 +87,7 @@
           "id": "test-request-id",
           "seatbid": [
             {
-              "seat": "yahoossp",
+              "seat": "yahooAdvertising",
               "bid": [{
                 "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
                 "impid": "test-imp-id",
diff --git a/adapters/yahoossp/yahoossptest/supplemental/simple-banner-ignore-width-when-height-missing.json b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/simple-banner-ignore-width-when-height-missing.json
similarity index 98%
rename from adapters/yahoossp/yahoossptest/supplemental/simple-banner-ignore-width-when-height-missing.json
rename to adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/simple-banner-ignore-width-when-height-missing.json
index 16e64c61..353d5e29 100644
--- a/adapters/yahoossp/yahoossptest/supplemental/simple-banner-ignore-width-when-height-missing.json
+++ b/adapters/yahooAdvertising/yahooAdvertisingtest/supplemental/simple-banner-ignore-width-when-height-missing.json
@@ -78,7 +78,7 @@
           "id": "test-request-id",
           "seatbid": [
             {
-              "seat": "yahoossp",
+              "seat": "yahooAdvertising",
               "bid": [{
                 "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
                 "impid": "test-imp-id",
diff --git a/config/compression_test.go b/config/compression_test.go
new file mode 100644
index 00000000..cd9048cd
--- /dev/null
+++ b/config/compression_test.go
@@ -0,0 +1,47 @@
+package config
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/util/httputil"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestReqCompressionCfgIsSupported(t *testing.T) {
+	testCases := []struct {
+		description     string
+		cfg             CompressionInfo
+		contentEncoding httputil.ContentEncoding
+		wantSupported   bool
+	}{
+		{
+			description: "Compression type not supported",
+			cfg: CompressionInfo{
+				GZIP: true,
+			},
+			contentEncoding: httputil.ContentEncoding("invalid"),
+			wantSupported:   false,
+		},
+		{
+			description: "Compression type supported",
+			cfg: CompressionInfo{
+				GZIP: true,
+			},
+			contentEncoding: httputil.ContentEncodingGZIP,
+			wantSupported:   true,
+		},
+		{
+			description: "Compression not enabled",
+			cfg: CompressionInfo{
+				GZIP: false,
+			},
+			contentEncoding: httputil.ContentEncodingGZIP,
+			wantSupported:   false,
+		},
+	}
+
+	for _, test := range testCases {
+		got := test.cfg.IsSupported(test.contentEncoding)
+		assert.Equal(t, got, test.wantSupported, test.description)
+	}
+}
diff --git a/config/config_test.go b/config/config_test.go
index 64f4f8a0..402f9ada 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -179,6 +179,11 @@ func TestDefaults(t *testing.T) {
 	//Assert the price floor default values
 	cmpBools(t, "price_floors.enabled", false, cfg.PriceFloors.Enabled)
 
+	// Assert compression related defaults
+	cmpBools(t, "enable_gzip", false, cfg.EnableGzip)
+	cmpBools(t, "compression.request.enable_gzip", false, cfg.Compression.Request.GZIP)
+	cmpBools(t, "compression.response.enable_gzip", false, cfg.Compression.Response.GZIP)
+
 	cmpBools(t, "account_defaults.price_floors.enabled", false, cfg.AccountDefaults.PriceFloors.Enabled)
 	cmpInts(t, "account_defaults.price_floors.enforce_floors_rate", 100, cfg.AccountDefaults.PriceFloors.EnforceFloorsRate)
 	cmpBools(t, "account_defaults.price_floors.adjust_for_bid_adjustment", true, cfg.AccountDefaults.PriceFloors.AdjustForBidAdjustment)
@@ -378,6 +383,12 @@ external_url: http://prebid-server.prebid.org/
 host: prebid-server.prebid.org
 port: 1234
 admin_port: 5678
+enable_gzip: false
+compression:
+    request:
+        enable_gzip: true
+    response:
+        enable_gzip: false
 garbage_collector_threshold: 1
 datacenter: "1"
 auction_timeouts_ms:
@@ -572,6 +583,11 @@ func TestFullConfig(t *testing.T) {
 	cmpBools(t, "account_defaults.events_enabled", *cfg.AccountDefaults.EventsEnabled, true)
 	cmpNils(t, "account_defaults.events.enabled", cfg.AccountDefaults.Events.Enabled)
 
+	// Assert compression related defaults
+	cmpBools(t, "enable_gzip", false, cfg.EnableGzip)
+	cmpBools(t, "compression.request.enable_gzip", true, cfg.Compression.Request.GZIP)
+	cmpBools(t, "compression.response.enable_gzip", false, cfg.Compression.Response.GZIP)
+
 	//Assert the NonStandardPublishers was correctly unmarshalled
 	assert.Equal(t, []string{"pub1", "pub2"}, cfg.GDPR.NonStandardPublishers, "gdpr.non_standard_publishers")
 	assert.Equal(t, map[string]struct{}{"pub1": {}, "pub2": {}}, cfg.GDPR.NonStandardPublisherMap, "gdpr.non_standard_publishers Hash Map")
@@ -2547,7 +2563,8 @@ func TestMigrateConfigDatabaseQueryParams(t *testing.T) {
 
 	v := viper.New()
 	v.SetConfigType("yaml")
-	v.ReadConfig(bytes.NewBuffer(config))
+	err := v.ReadConfig(bytes.NewBuffer(config))
+	assert.NoError(t, err)
 
 	migrateConfigDatabaseConnection(v)
 
@@ -2570,6 +2587,74 @@ func TestMigrateConfigDatabaseQueryParams(t *testing.T) {
 	assert.Equal(t, want_queries.poll_for_updates_amp_query, v.GetString("stored_responses.database.poll_for_updates.amp_query"))
 }
 
+func TestMigrateConfigCompression(t *testing.T) {
+	testCases := []struct {
+		desc                string
+		config              []byte
+		wantEnableGZIP      bool
+		wantReqGZIPEnabled  bool
+		wantRespGZIPEnabled bool
+	}{
+
+		{
+			desc:                "New config and old config not set",
+			config:              []byte{},
+			wantEnableGZIP:      false,
+			wantReqGZIPEnabled:  false,
+			wantRespGZIPEnabled: false,
+		},
+		{
+			desc: "Old config set, new config not set",
+			config: []byte(`
+                    enable_gzip: true
+                    `),
+			wantEnableGZIP:      true,
+			wantRespGZIPEnabled: true,
+			wantReqGZIPEnabled:  false,
+		},
+		{
+			desc: "Old config not set, new config set",
+			config: []byte(`
+                    compression:
+                        response:
+                            enable_gzip: true
+                        request:
+                            enable_gzip: false
+                    `),
+			wantEnableGZIP:      false,
+			wantRespGZIPEnabled: true,
+			wantReqGZIPEnabled:  false,
+		},
+		{
+			desc: "Old config set and new config set",
+			config: []byte(`
+                    enable_gzip: true
+                    compression:
+                        response:
+                            enable_gzip: false
+                        request:
+                            enable_gzip: true
+                    `),
+			wantEnableGZIP:      true,
+			wantRespGZIPEnabled: false,
+			wantReqGZIPEnabled:  true,
+		},
+	}
+
+	for _, test := range testCases {
+		v := viper.New()
+		v.SetConfigType("yaml")
+		err := v.ReadConfig(bytes.NewBuffer(test.config))
+		assert.NoError(t, err)
+
+		migrateConfigCompression(v)
+
+		assert.Equal(t, test.wantEnableGZIP, v.GetBool("enable_gzip"), test.desc)
+		assert.Equal(t, test.wantReqGZIPEnabled, v.GetBool("compression.request.enable_gzip"), test.desc)
+		assert.Equal(t, test.wantRespGZIPEnabled, v.GetBool("compression.response.enable_gzip"), test.desc)
+	}
+}
+
 func TestIsConfigInfoPresent(t *testing.T) {
 	configPrefix1Field2Only := []byte(`
       prefix1:
diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go
index 8eb80672..9533ec62 100644
--- a/endpoints/openrtb2/amp_auction_test.go
+++ b/endpoints/openrtb2/amp_auction_test.go
@@ -1720,7 +1720,7 @@ func TestBuildAmpObject(t *testing.T) {
 					},
 					AT:   1,
 					TMax: 500,
-					Ext:  json.RawMessage(`{"prebid":{"cache":{"bids":{}},"channel":{"name":"amp","version":""},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":20,"increment":0.1}]},"includewinners":true,"includebidderkeys":true}}}`),
+					Ext:  json.RawMessage(`{"prebid":{"cache":{"bids":{}},"channel":{"name":"amp","version":""},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":20,"increment":0.1}]},"mediatypepricegranularity":{},"includewinners":true,"includebidderkeys":true}}}`),
 				},
 				AuctionResponse: &openrtb2.BidResponse{
 					SeatBid: []openrtb2.SeatBid{{
@@ -1774,7 +1774,7 @@ func TestBuildAmpObject(t *testing.T) {
 					},
 					AT:   1,
 					TMax: 500,
-					Ext:  json.RawMessage(`{"prebid":{"cache":{"bids":{}},"channel":{"name":"amp","version":""},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":20,"increment":0.1}]},"includewinners":true,"includebidderkeys":true}}}`),
+					Ext:  json.RawMessage(`{"prebid":{"cache":{"bids":{}},"channel":{"name":"amp","version":""},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":20,"increment":0.1}]},"mediatypepricegranularity":{},"includewinners":true,"includebidderkeys":true}}}`),
 				},
 				AuctionResponse: &openrtb2.BidResponse{
 					SeatBid: []openrtb2.SeatBid{{
@@ -2108,30 +2108,30 @@ func TestValidAmpResponseWhenRequestRejected(t *testing.T) {
 		{
 			description: "Assert correct AmpResponse when request rejected at entrypoint stage",
 			file:        "sample-requests/hooks/amp_entrypoint_reject.json",
-			planBuilder: mockPlanBuilder{entrypointPlan: makePlan[hookstage.Entrypoint](mockRejectionHook{nbr})},
+			planBuilder: mockPlanBuilder{entrypointPlan: makePlan[hookstage.Entrypoint](mockRejectionHook{nbr, nil})},
 		},
 		{
 			// raw_auction stage not executed for AMP endpoint, so we expect full response
 			description: "Assert correct AmpResponse when request rejected at raw_auction stage",
 			file:        "sample-requests/amp/valid-supplementary/aliased-buyeruids.json",
-			planBuilder: mockPlanBuilder{rawAuctionPlan: makePlan[hookstage.RawAuctionRequest](mockRejectionHook{nbr})},
+			planBuilder: mockPlanBuilder{rawAuctionPlan: makePlan[hookstage.RawAuctionRequest](mockRejectionHook{nbr, nil})},
 		},
 		{
 			description: "Assert correct AmpResponse when request rejected at processed_auction stage",
 			file:        "sample-requests/hooks/amp_processed_auction_request_reject.json",
-			planBuilder: mockPlanBuilder{processedAuctionPlan: makePlan[hookstage.ProcessedAuctionRequest](mockRejectionHook{nbr})},
+			planBuilder: mockPlanBuilder{processedAuctionPlan: makePlan[hookstage.ProcessedAuctionRequest](mockRejectionHook{nbr, nil})},
 		},
 		{
 			// bidder_request stage rejects only bidder, so we expect bidder rejection warning added
 			description: "Assert correct AmpResponse when request rejected at bidder-request stage",
 			file:        "sample-requests/hooks/amp_bidder_reject.json",
-			planBuilder: mockPlanBuilder{bidderRequestPlan: makePlan[hookstage.BidderRequest](mockRejectionHook{nbr})},
+			planBuilder: mockPlanBuilder{bidderRequestPlan: makePlan[hookstage.BidderRequest](mockRejectionHook{nbr, nil})},
 		},
 		{
 			// raw_bidder_response stage rejects only bidder, so we expect bidder rejection warning added
 			description: "Assert correct AmpResponse when request rejected at raw_bidder_response stage",
 			file:        "sample-requests/hooks/amp_bidder_response_reject.json",
-			planBuilder: mockPlanBuilder{rawBidderResponsePlan: makePlan[hookstage.RawBidderResponse](mockRejectionHook{nbr})},
+			planBuilder: mockPlanBuilder{rawBidderResponsePlan: makePlan[hookstage.RawBidderResponse](mockRejectionHook{nbr, nil})},
 		},
 		{
 			// no debug information should be added for raw_auction stage because it's not executed for amp endpoint
diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go
index 544a46d0..6be85a99 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -2,6 +2,7 @@ package openrtb2
 
 import (
 	"bytes"
+	"compress/gzip"
 	"context"
 	"encoding/json"
 	"errors"
@@ -1863,60 +1864,172 @@ func TestValidateTargeting(t *testing.T) {
 			expectedError: nil,
 		},
 		{
-			name: "price granularity empty",
+			name: "price granularity ranges out of order",
 			givenTargeting: &openrtb_ext.ExtRequestTargeting{
-				IncludeWinners:   ptrutil.ToPtr(true),
-				PriceGranularity: &openrtb_ext.PriceGranularity{},
+				IncludeWinners: ptrutil.ToPtr(true),
+				PriceGranularity: &openrtb_ext.PriceGranularity{
+					Precision: ptrutil.ToPtr(2),
+					Ranges: []openrtb_ext.GranularityRange{
+						{Min: 1.0, Max: 2.0, Increment: 0.2},
+						{Min: 0.0, Max: 1.0, Increment: 0.5},
+					},
+				},
 			},
-			expectedError: errors.New("Price granularity error: precision is required"),
+			expectedError: errors.New(`Price granularity error: range list must be ordered with increasing "max"`),
 		},
 		{
-			name: "price granularity negative",
+			name: "media type price granularity video correct",
 			givenTargeting: &openrtb_ext.ExtRequestTargeting{
 				IncludeWinners: ptrutil.ToPtr(true),
-				PriceGranularity: &openrtb_ext.PriceGranularity{
-					Precision: ptrutil.ToPtr(-1),
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Video: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(2),
+						Ranges: []openrtb_ext.GranularityRange{
+							{Min: 0.0, Max: 10.0, Increment: 1},
+						},
+					},
 				},
 			},
-			expectedError: errors.New("Price granularity error: precision must be non-negative"),
+			expectedError: nil,
 		},
 		{
-			name: "price granularity greater than max",
+			name: "media type price granularity banner correct",
 			givenTargeting: &openrtb_ext.ExtRequestTargeting{
 				IncludeWinners: ptrutil.ToPtr(true),
-				PriceGranularity: &openrtb_ext.PriceGranularity{
-					Precision: ptrutil.ToPtr(openrtb_ext.MaxDecimalFigures + 1),
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Banner: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(2),
+						Ranges: []openrtb_ext.GranularityRange{
+							{Min: 0.0, Max: 10.0, Increment: 1},
+						},
+					},
 				},
 			},
-			expectedError: errors.New("Price granularity error: precision of more than 15 significant figures is not supported"),
+			expectedError: nil,
 		},
 		{
-			name: "price granularity ranges out of order",
+			name: "media type price granularity native correct",
 			givenTargeting: &openrtb_ext.ExtRequestTargeting{
 				IncludeWinners: ptrutil.ToPtr(true),
-				PriceGranularity: &openrtb_ext.PriceGranularity{
-					Precision: ptrutil.ToPtr(2),
-					Ranges: []openrtb_ext.GranularityRange{
-						{Min: 1.0, Max: 2.0, Increment: 0.2},
-						{Min: 0.0, Max: 1.0, Increment: 0.5},
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Native: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(2),
+						Ranges: []openrtb_ext.GranularityRange{
+							{Min: 0.0, Max: 20.0, Increment: 1},
+						},
 					},
 				},
 			},
-			expectedError: errors.New(`Price granularity error: range list must be ordered with increasing "max"`),
+			expectedError: nil,
 		},
 		{
-			name: "price granularity negative increment",
+			name: "media type price granularity video and banner correct",
 			givenTargeting: &openrtb_ext.ExtRequestTargeting{
 				IncludeWinners: ptrutil.ToPtr(true),
-				PriceGranularity: &openrtb_ext.PriceGranularity{
-					Precision: ptrutil.ToPtr(2),
-					Ranges: []openrtb_ext.GranularityRange{
-						{Min: 0.0, Max: 1.0, Increment: -0.1},
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Banner: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(2),
+						Ranges: []openrtb_ext.GranularityRange{
+							{Min: 0.0, Max: 10.0, Increment: 1},
+						},
+					},
+					Video: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(2),
+						Ranges: []openrtb_ext.GranularityRange{
+							{Min: 0.0, Max: 10.0, Increment: 1},
+						},
+					},
+				},
+			},
+			expectedError: nil,
+		},
+		{
+			name: "media type price granularity video incorrect",
+			givenTargeting: &openrtb_ext.ExtRequestTargeting{
+				IncludeWinners: ptrutil.ToPtr(true),
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Video: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(2),
+						Ranges: []openrtb_ext.GranularityRange{
+							{Min: 0.0, Max: 10.0, Increment: -1},
+						},
 					},
 				},
 			},
 			expectedError: errors.New("Price granularity error: increment must be a nonzero positive number"),
 		},
+		{
+			name: "media type price granularity banner incorrect",
+			givenTargeting: &openrtb_ext.ExtRequestTargeting{
+				IncludeWinners: ptrutil.ToPtr(true),
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Banner: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(2),
+						Ranges: []openrtb_ext.GranularityRange{
+							{Min: 0.0, Max: 0.0, Increment: 1},
+						},
+					},
+				},
+			},
+			expectedError: errors.New("Price granularity error: range list must be ordered with increasing \"max\""),
+		},
+		{
+			name: "media type price granularity native incorrect",
+			givenTargeting: &openrtb_ext.ExtRequestTargeting{
+				IncludeWinners: ptrutil.ToPtr(true),
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Native: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(2),
+						Ranges: []openrtb_ext.GranularityRange{
+							{Min: 0.0, Max: 0.0, Increment: 1},
+						},
+					},
+				},
+			},
+			expectedError: errors.New("Price granularity error: range list must be ordered with increasing \"max\""),
+		},
+		{
+			name: "media type price granularity video correct and banner incorrect",
+			givenTargeting: &openrtb_ext.ExtRequestTargeting{
+				IncludeWinners: ptrutil.ToPtr(true),
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Banner: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(2),
+						Ranges: []openrtb_ext.GranularityRange{
+							{Min: 0.0, Max: 10.0, Increment: -1},
+						},
+					},
+					Video: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(2),
+						Ranges: []openrtb_ext.GranularityRange{
+							{Min: 0.0, Max: 0.0, Increment: 1},
+						},
+					},
+				},
+			},
+			expectedError: errors.New("Price granularity error: range list must be ordered with increasing \"max\""),
+		},
+		{
+			name: "media type price granularity native incorrect and banner correct",
+			givenTargeting: &openrtb_ext.ExtRequestTargeting{
+				IncludeWinners: ptrutil.ToPtr(true),
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Native: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(2),
+						Ranges: []openrtb_ext.GranularityRange{
+							{Min: 0.0, Max: 10.0, Increment: -1},
+						},
+					},
+					Video: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(2),
+						Ranges: []openrtb_ext.GranularityRange{
+							{Min: 0.0, Max: 0.0, Increment: 1},
+						},
+					},
+				},
+			},
+			expectedError: errors.New("Price granularity error: range list must be ordered with increasing \"max\""),
+		},
 	}
 
 	for _, tc := range testCases {
@@ -1926,6 +2039,80 @@ func TestValidateTargeting(t *testing.T) {
 	}
 }
 
+func TestValidatePriceGranularity(t *testing.T) {
+	testCases := []struct {
+		description           string
+		givenPriceGranularity *openrtb_ext.PriceGranularity
+		expectedError         error
+	}{
+		{
+			description: "Precision is nil",
+			givenPriceGranularity: &openrtb_ext.PriceGranularity{
+				Precision: nil,
+			},
+			expectedError: errors.New("Price granularity error: precision is required"),
+		},
+		{
+			description: "Precision is negative",
+			givenPriceGranularity: &openrtb_ext.PriceGranularity{
+				Precision: ptrutil.ToPtr(-1),
+			},
+			expectedError: errors.New("Price granularity error: precision must be non-negative"),
+		},
+		{
+			description: "Precision is too big",
+			givenPriceGranularity: &openrtb_ext.PriceGranularity{
+				Precision: ptrutil.ToPtr(20),
+			},
+			expectedError: errors.New("Price granularity error: precision of more than 15 significant figures is not supported"),
+		},
+		{
+			description: "price granularity ranges out of order",
+			givenPriceGranularity: &openrtb_ext.PriceGranularity{
+				Precision: ptrutil.ToPtr(2),
+				Ranges: []openrtb_ext.GranularityRange{
+					{Min: 1.0, Max: 2.0, Increment: 0.2},
+					{Min: 0.0, Max: 1.0, Increment: 0.5},
+				},
+			},
+			expectedError: errors.New(`Price granularity error: range list must be ordered with increasing "max"`),
+		},
+		{
+			description: "price granularity negative increment",
+			givenPriceGranularity: &openrtb_ext.PriceGranularity{
+				Precision: ptrutil.ToPtr(2),
+				Ranges: []openrtb_ext.GranularityRange{
+					{Min: 0.0, Max: 1.0, Increment: -0.1},
+				},
+			},
+			expectedError: errors.New("Price granularity error: increment must be a nonzero positive number"),
+		},
+		{
+			description: "price granularity correct",
+			givenPriceGranularity: &openrtb_ext.PriceGranularity{
+				Precision: ptrutil.ToPtr(2),
+				Ranges: []openrtb_ext.GranularityRange{
+					{Min: 0.0, Max: 10.0, Increment: 1},
+				},
+			},
+			expectedError: nil,
+		},
+		{
+			description: "price granularity with correct precision and ranges not specified",
+			givenPriceGranularity: &openrtb_ext.PriceGranularity{
+				Precision: ptrutil.ToPtr(2),
+			},
+			expectedError: nil,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			assert.Equal(t, tc.expectedError, validatePriceGranularity(tc.givenPriceGranularity))
+		})
+	}
+}
+
 func TestValidateOrFillChannel(t *testing.T) {
 	testCases := []struct {
 		description           string
@@ -3709,6 +3896,105 @@ func TestParseRequestParseImpInfoError(t *testing.T) {
 	assert.Contains(t, errL[0].Error(), "echovideoattrs of type bool", "Incorrect error message")
 }
 
+func TestParseGzipedRequest(t *testing.T) {
+	testCases :=
+		[]struct {
+			desc           string
+			reqContentEnc  string
+			maxReqSize     int64
+			compressionCfg config.Compression
+			expectedErr    string
+		}{
+			{
+				desc:           "Gzip compression enabled, request size exceeds max request size",
+				reqContentEnc:  "gzip",
+				maxReqSize:     10,
+				compressionCfg: config.Compression{Request: config.CompressionInfo{GZIP: true}},
+				expectedErr:    "request size exceeded max size of 10 bytes.",
+			},
+			{
+				desc:           "Gzip compression enabled, request size is within max request size",
+				reqContentEnc:  "gzip",
+				maxReqSize:     2000,
+				compressionCfg: config.Compression{Request: config.CompressionInfo{GZIP: true}},
+				expectedErr:    "",
+			},
+			{
+				desc:           "Gzip compression enabled, request size is within max request size, content-encoding value not in lower case",
+				reqContentEnc:  "GZIP",
+				maxReqSize:     2000,
+				compressionCfg: config.Compression{Request: config.CompressionInfo{GZIP: true}},
+				expectedErr:    "",
+			},
+			{
+				desc:           "Request is Gzip compressed, but Gzip compression is disabled",
+				reqContentEnc:  "gzip",
+				compressionCfg: config.Compression{Request: config.CompressionInfo{GZIP: false}},
+				expectedErr:    "Content-Encoding of type gzip is not supported",
+			},
+			{
+				desc:           "Request is not Gzip compressed, but Gzip compression is enabled",
+				reqContentEnc:  "",
+				maxReqSize:     2000,
+				compressionCfg: config.Compression{Request: config.CompressionInfo{GZIP: true}},
+				expectedErr:    "",
+			},
+		}
+
+	reqBody := []byte(validRequest(t, "site.json"))
+	deps := &endpointDeps{
+		fakeUUIDGenerator{},
+		&warningsCheckExchange{},
+		mockBidderParamValidator{},
+		&mockStoredReqFetcher{},
+		empty_fetcher.EmptyFetcher{},
+		empty_fetcher.EmptyFetcher{},
+		&config.Configuration{MaxRequestSize: int64(50), Compression: config.Compression{Request: config.CompressionInfo{GZIP: false}}},
+		&metricsConfig.NilMetricsEngine{},
+		analyticsConf.NewPBSAnalytics(&config.Analytics{}),
+		map[string]string{},
+		false,
+		[]byte{},
+		openrtb_ext.BuildBidderMap(),
+		nil,
+		nil,
+		hardcodedResponseIPValidator{response: true},
+		empty_fetcher.EmptyFetcher{},
+		hooks.EmptyPlanBuilder{},
+	}
+
+	hookExecutor := hookexecution.NewHookExecutor(deps.hookExecutionPlanBuilder, hookexecution.EndpointAuction, deps.metricsEngine)
+	for _, test := range testCases {
+		var req *http.Request
+		deps.cfg.MaxRequestSize = test.maxReqSize
+		deps.cfg.Compression = test.compressionCfg
+		if test.reqContentEnc == "gzip" {
+			var compressed bytes.Buffer
+			gw := gzip.NewWriter(&compressed)
+			_, err := gw.Write(reqBody)
+			assert.NoError(t, err, "Error writing gzip compressed request body", test.desc)
+			assert.NoError(t, gw.Close(), "Error closing gzip writer", test.desc)
+
+			req = httptest.NewRequest("POST", "/openrtb2/auction", bytes.NewReader(compressed.Bytes()))
+			req.Header.Set("Content-Encoding", "gzip")
+		} else {
+			req = httptest.NewRequest("POST", "/openrtb2/auction", bytes.NewReader(reqBody))
+		}
+		resReq, impExtInfoMap, _, _, _, _, errL := deps.parseRequest(req, &metrics.Labels{}, hookExecutor)
+
+		if test.expectedErr == "" {
+			assert.Nil(t, errL, "Error list should be nil", test.desc)
+			assert.NotNil(t, resReq, "Result request should not be nil", test.desc)
+			assert.NotNil(t, impExtInfoMap, "Impression info map should not be nil", test.desc)
+		} else {
+			assert.Nil(t, resReq, "Result request should be nil due to incorrect imp", test.desc)
+			assert.Nil(t, impExtInfoMap, "Impression info map should be nil due to incorrect imp", test.desc)
+			assert.Len(t, errL, 1, "One error should be returned", test.desc)
+			assert.Contains(t, errL[0].Error(), test.expectedErr, "Incorrect error message", test.desc)
+		}
+	}
+}
+
 func TestValidateNativeContextTypes(t *testing.T) {
 	impIndex := 4
 
@@ -5084,28 +5370,33 @@ func TestValidResponseAfterExecutingStages(t *testing.T) {
 		{
 			description: "Assert correct BidResponse when request rejected at entrypoint stage",
 			file:        "sample-requests/hooks/auction_entrypoint_reject.json",
-			planBuilder: mockPlanBuilder{entrypointPlan: makePlan[hookstage.Entrypoint](mockRejectionHook{nbr})},
+			planBuilder: mockPlanBuilder{entrypointPlan: makePlan[hookstage.Entrypoint](mockRejectionHook{nbr, nil})},
 		},
 		{
 			description: "Assert correct BidResponse when request rejected at raw-auction stage",
 			file:        "sample-requests/hooks/auction_raw_auction_request_reject.json",
-			planBuilder: mockPlanBuilder{rawAuctionPlan: makePlan[hookstage.RawAuctionRequest](mockRejectionHook{nbr})},
+			planBuilder: mockPlanBuilder{rawAuctionPlan: makePlan[hookstage.RawAuctionRequest](mockRejectionHook{nbr, nil})},
 		},
 		{
 			description: "Assert correct BidResponse when request rejected at processed-auction stage",
 			file:        "sample-requests/hooks/auction_processed_auction_request_reject.json",
-			planBuilder: mockPlanBuilder{processedAuctionPlan: makePlan[hookstage.ProcessedAuctionRequest](mockRejectionHook{nbr})},
+			planBuilder: mockPlanBuilder{processedAuctionPlan: makePlan[hookstage.ProcessedAuctionRequest](mockRejectionHook{nbr, nil})},
 		},
 		{
 			// bidder-request stage doesn't reject whole request, so we do not expect NBR code in response
 			description: "Assert correct BidResponse when request rejected at bidder-request stage",
 			file:        "sample-requests/hooks/auction_bidder_reject.json",
-			planBuilder: mockPlanBuilder{bidderRequestPlan: makePlan[hookstage.BidderRequest](mockRejectionHook{nbr})},
+			planBuilder: mockPlanBuilder{bidderRequestPlan: makePlan[hookstage.BidderRequest](mockRejectionHook{nbr, nil})},
 		},
 		{
 			description: "Assert correct BidResponse when request rejected at raw-bidder-response stage",
 			file:        "sample-requests/hooks/auction_bidder_response_reject.json",
-			planBuilder: mockPlanBuilder{rawBidderResponsePlan: makePlan[hookstage.RawBidderResponse](mockRejectionHook{nbr})},
+			planBuilder: mockPlanBuilder{rawBidderResponsePlan: makePlan[hookstage.RawBidderResponse](mockRejectionHook{nbr, nil})},
+		},
+		{
+			description: "Assert correct BidResponse when request rejected with error from hook",
+			file:        "sample-requests/hooks/auction_reject_with_error.json",
+			planBuilder: mockPlanBuilder{entrypointPlan: makePlan[hookstage.Entrypoint](mockRejectionHook{nbr, errors.New("dummy")})},
 		},
 		{
 			description: "Assert correct BidResponse with debug information from modules added to ext.prebid.modules",
diff --git a/endpoints/openrtb2/test_utils.go b/endpoints/openrtb2/test_utils.go
index 09c6bd39..6dfd9ab6 100644
--- a/endpoints/openrtb2/test_utils.go
+++ b/endpoints/openrtb2/test_utils.go
@@ -1468,6 +1468,7 @@ func makePlan[H any](hook H) hooks.Plan[H] {
 
 type mockRejectionHook struct {
 	nbr int
+	err error
 }
 
 func (m mockRejectionHook) HandleEntrypointHook(
@@ -1475,7 +1476,7 @@ func (m mockRejectionHook) HandleEntrypointHook(
 	_ hookstage.ModuleInvocationContext,
 	_ hookstage.EntrypointPayload,
 ) (hookstage.HookResult[hookstage.EntrypointPayload], error) {
-	return hookstage.HookResult[hookstage.EntrypointPayload]{Reject: true, NbrCode: m.nbr}, nil
+	return hookstage.HookResult[hookstage.EntrypointPayload]{Reject: true, NbrCode: m.nbr}, m.err
 }
 
 func (m mockRejectionHook) HandleRawAuctionHook(
@@ -1483,7 +1484,7 @@ func (m mockRejectionHook) HandleRawAuctionHook(
 	_ hookstage.ModuleInvocationContext,
 	_ hookstage.RawAuctionRequestPayload,
 ) (hookstage.HookResult[hookstage.RawAuctionRequestPayload], error) {
-	return hookstage.HookResult[hookstage.RawAuctionRequestPayload]{Reject: true, NbrCode: m.nbr}, nil
+	return hookstage.HookResult[hookstage.RawAuctionRequestPayload]{Reject: true, NbrCode: m.nbr}, m.err
 }
 
 func (m mockRejectionHook) HandleProcessedAuctionHook(
@@ -1491,7 +1492,7 @@ func (m mockRejectionHook) HandleProcessedAuctionHook(
 	_ hookstage.ModuleInvocationContext,
 	_ hookstage.ProcessedAuctionRequestPayload,
 ) (hookstage.HookResult[hookstage.ProcessedAuctionRequestPayload], error) {
-	return hookstage.HookResult[hookstage.ProcessedAuctionRequestPayload]{Reject: true, NbrCode: m.nbr}, nil
+	return hookstage.HookResult[hookstage.ProcessedAuctionRequestPayload]{Reject: true, NbrCode: m.nbr}, m.err
 }
 
 func (m mockRejectionHook) HandleBidderRequestHook(
@@ -1505,7 +1506,7 @@ func (m mockRejectionHook) HandleBidderRequestHook(
 		result.NbrCode = m.nbr
 	}
 
-	return result, nil
+	return result, m.err
 }
 
 func (m mockRejectionHook) HandleRawBidderResponseHook(
diff --git a/endpoints/openrtb2/video_auction_test.go b/endpoints/openrtb2/video_auction_test.go
index b75a7b99..ee0e75e4 100644
--- a/endpoints/openrtb2/video_auction_test.go
+++ b/endpoints/openrtb2/video_auction_test.go
@@ -153,7 +153,7 @@ func TestCreateBidExtensionTargeting(t *testing.T) {
 	require.NotNil(t, ex.lastRequest, "The request never made it into the Exchange.")
 
 	// assert targeting set to default
-	expectedRequestExt := `{"prebid":{"cache":{"vastxml":{}},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":20,"increment":0.1}]},"includebidderkeys":true,"includewinners":true,"includebrandcategory":{"primaryadserver":1,"publisher":"","withcategory":true}}}}`
+	expectedRequestExt := `{"prebid":{"cache":{"vastxml":{}},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":20,"increment":0.1}]},"mediatypepricegranularity":{},"includebidderkeys":true,"includewinners":true,"includebrandcategory":{"primaryadserver":1,"publisher":"","withcategory":true}}}}`
 	assert.JSONEq(t, expectedRequestExt, string(ex.lastRequest.Ext))
 }
 
diff --git a/exchange/adapter_util_test.go b/exchange/adapter_util_test.go
index 4a6f468e..43cefeec 100644
--- a/exchange/adapter_util_test.go
+++ b/exchange/adapter_util_test.go
@@ -210,9 +210,10 @@ func TestGetDisabledBiddersErrorMessages(t *testing.T) {
 				"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
 				"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
 				"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahooAdvertising" in your configuration.`,
 				"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
 				"oftmedia":       `Bidder "oftmedia" is no longer available in Prebid Server. Please update your configuration.`,
+				"groupm":         `Bidder "groupm" is no longer available in Prebid Server. Please update your configuration.`,
 			},
 		},
 		{
@@ -222,9 +223,10 @@ func TestGetDisabledBiddersErrorMessages(t *testing.T) {
 				"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
 				"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
 				"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahooAdvertising" in your configuration.`,
 				"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
 				"oftmedia":       `Bidder "oftmedia" is no longer available in Prebid Server. Please update your configuration.`,
+				"groupm":         `Bidder "groupm" is no longer available in Prebid Server. Please update your configuration.`,
 			},
 		},
 		{
@@ -234,10 +236,11 @@ func TestGetDisabledBiddersErrorMessages(t *testing.T) {
 				"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
 				"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
 				"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahooAdvertising" in your configuration.`,
 				"appnexus":       `Bidder "appnexus" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`,
 				"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
 				"oftmedia":       `Bidder "oftmedia" is no longer available in Prebid Server. Please update your configuration.`,
+				"groupm":         `Bidder "groupm" is no longer available in Prebid Server. Please update your configuration.`,
 			},
 		},
 		{
@@ -247,10 +250,11 @@ func TestGetDisabledBiddersErrorMessages(t *testing.T) {
 				"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
 				"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
 				"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahooAdvertising" in your configuration.`,
 				"appnexus":       `Bidder "appnexus" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`,
 				"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
 				"oftmedia":       `Bidder "oftmedia" is no longer available in Prebid Server. Please update your configuration.`,
+				"groupm":         `Bidder "groupm" is no longer available in Prebid Server. Please update your configuration.`,
 			},
 		},
 	}
diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go
index 4e94a18f..87d04185 100644
--- a/exchange/bidder_test.go
+++ b/exchange/bidder_test.go
@@ -2725,7 +2725,7 @@ func TestExtraBidWithBidAdjustments(t *testing.T) {
 	}
 	bidAdjustments := map[string]float64{
 		string(openrtb_ext.BidderPubmatic): 2,
-		string(openrtb_ext.BidderGroupm):   3,
+		"groupm":                           3,
 	}
 
 	bidReqOptions := bidRequestOptions{
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 7789a841..141defc8 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -4346,7 +4346,7 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
 				},
 				liveAdapters: []openrtb_ext.BidderName{openrtb_ext.BidderName("appnexus")},
 			},
-			errorMessage: "invalid BidType: incorrect",
+			errorMessage: "Failed to parse bid mediatype for impression \"impression-id\", invalid BidType: incorrect",
 		},
 		{
 			desc: "Single imp with multiple bids in stored response one bidder",
diff --git a/exchange/exchangetest/mediatypepricegranularity-banner-video-native.json b/exchange/exchangetest/mediatypepricegranularity-banner-video-native.json
new file mode 100644
index 00000000..7d119b23
--- /dev/null
+++ b/exchange/exchangetest/mediatypepricegranularity-banner-video-native.json
@@ -0,0 +1,286 @@
+{
+    "incomingRequest": {
+        "ortbRequest": {
+            "id": "some-request-id",
+            "site": {
+                "page": "test.somepage.com"
+            },
+            "imp": [
+                {
+                    "id": "my-imp-id",
+                    "video": {
+                        "mimes": [
+                            "video/mp4"
+                        ]
+                    },
+                    "ext": {
+                        "prebid": {
+                            "bidder": {
+                                "appnexus": {
+                                    "placementId": 1
+                                }
+                            }
+                        }
+                    }
+                },
+                {
+                    "id": "imp-id-2",
+                    "video": {
+                        "mimes": [
+                            "video/mp4"
+                        ]
+                    },
+                    "ext": {
+                        "prebid": {
+                            "bidder": {
+                                "appnexus": {
+                                    "placementId": 1
+                                }
+                            }
+                        }
+                    }
+                },
+                {
+                    "id": "imp-id-3",
+                    "video": {
+                        "mimes": [
+                            "video/mp4"
+                        ]
+                    },
+                    "ext": {
+                        "prebid": {
+                            "bidder": {
+                                "appnexus": {
+                                    "placementId": 1
+                                }
+                            }
+                        }
+                    }
+                }
+            ],
+            "ext": {
+                "prebid": {
+                    "targeting": {
+                        "includebrandcategory": {
+                            "primaryadserver": 1,
+                            "publisher": "",
+                            "withcategory": true
+                        },
+                        "pricegranularity": {
+                            "precision": 2,
+                            "ranges": [
+                                {
+                                    "min": 0,
+                                    "max": 20,
+                                    "increment": 2
+                                }
+                            ]
+                        },
+                        "mediatypepricegranularity": {
+                            "banner": {
+                                "precision": 3,
+                                "ranges": [
+                                    {
+                                        "max": 20,
+                                        "increment": 4.5
+                                    }
+                                ]
+                            },
+                            "video": {
+                                "precision": 4,
+                                "ranges": [
+                                    {
+                                        "min": 10,
+                                        "max": 30,
+                                        "increment": 1.5
+                                    }
+                                ]
+                            },
+                            "native": {
+                                "precision": 5,
+                                "ranges": [
+                                    {
+                                        "max": 30,
+                                        "increment": 1.8
+                                    }
+                                ]
+                            }
+                        },
+                        "includewinners": true,
+                        "includebidderkeys": true,
+                        "appendbiddernames": true
+                    }
+                }
+            }
+        },
+        "usersyncs": {
+            "appnexus": "123"
+        }
+    },
+    "outgoingRequests": {
+        "appnexus": {
+            "mockResponse": {
+                "pbsSeatBids": [
+                    {
+                        "pbsBids": [
+                            {
+                                "ortbBid": {
+                                    "id": "apn-bid",
+                                    "impid": "my-imp-id",
+                                    "price": 15,
+                                    "w": 200,
+                                    "h": 250,
+                                    "crid": "creative-1",
+                                    "cat": [
+                                        "IAB1-1"
+                                    ],
+                                    "mtype": 1
+                                },
+                                "bidType": "banner"
+                            },
+                            {
+                                "ortbBid": {
+                                    "id": "apn-other-bid",
+                                    "impid": "imp-id-2",
+                                    "price": 18,
+                                    "w": 300,
+                                    "h": 500,
+                                    "crid": "creative-3",
+                                    "cat": [
+                                        "IAB1-2"
+                                    ],
+                                    "mtype": 2
+                                },
+                                "bidType": "video"
+                            },
+                            {
+                                "ortbBid": {
+                                    "id": "apn-native-bid",
+                                    "impid": "imp-id-3",
+                                    "price": 29,
+                                    "w": 300,
+                                    "h": 500,
+                                    "crid": "creative-3",
+                                    "cat": [
+                                        "IAB1-4"
+                                    ],
+                                    "mtype": 4
+                                },
+                                "bidType": "native"
+                            }
+                        ],
+                        "seat": "appnexus"
+                    }
+                ]
+            }
+        }
+    },
+    "response": {
+        "bids": {
+            "id": "some-request-id",
+            "seatbid": [
+                {
+                    "seat": "appnexus",
+                    "bid": [
+                        {
+                            "id": "apn-bid",
+                            "impid": "my-imp-id",
+                            "price": 15,
+                            "w": 200,
+                            "h": 250,
+                            "crid": "creative-1",
+                            "cat": [
+                                "IAB1-1"
+                            ],
+                            "mtype": 1,
+                            "ext": {
+                                "origbidcpm": 15,
+                                "prebid": {
+                                    "type": "banner",
+                                    "targeting": {
+                                        "hb_bidder": "appnexus",
+                                        "hb_bidder_appnexus": "appnexus",
+                                        "hb_cache_host": "www.pbcserver.com",
+                                        "hb_cache_host_appnex": "www.pbcserver.com",
+                                        "hb_cache_path": "/pbcache/endpoint",
+                                        "hb_cache_path_appnex": "/pbcache/endpoint",
+                                        "hb_pb": "13.500",
+                                        "hb_pb_appnexus": "13.500",
+                                        "hb_pb_cat_dur": "13.500_VideoGames_0s_appnexus",
+                                        "hb_pb_cat_dur_appnex": "13.500_VideoGames_0s_appnexus",
+                                        "hb_size": "200x250",
+                                        "hb_size_appnexus": "200x250"
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "cat": [
+                                "IAB1-2"
+                            ],
+                            "crid": "creative-3",
+                            "mtype": 2,
+                            "ext": {
+                                "origbidcpm": 18,
+                                "prebid": {
+                                    "targeting": {
+                                        "hb_bidder": "appnexus",
+                                        "hb_bidder_appnexus": "appnexus",
+                                        "hb_cache_host": "www.pbcserver.com",
+                                        "hb_cache_host_appnex": "www.pbcserver.com",
+                                        "hb_cache_path": "/pbcache/endpoint",
+                                        "hb_cache_path_appnex": "/pbcache/endpoint",
+                                        "hb_pb": "17.5000",
+                                        "hb_pb_appnexus": "17.5000",
+                                        "hb_pb_cat_dur": "17.5000_HomeDecor_0s_appnexus",
+                                        "hb_pb_cat_dur_appnex": "17.5000_HomeDecor_0s_appnexus",
+                                        "hb_size": "300x500",
+                                        "hb_size_appnexus": "300x500"
+                                    },
+                                    "type": "video"
+                                }
+                            },
+                            "h": 500,
+                            "id": "apn-other-bid",
+                            "impid": "imp-id-2",
+                            "price": 18,
+                            "w": 300
+                        },
+                        {
+                            "cat": [
+                                "IAB1-4"
+                            ],
+                            "crid": "creative-3",
+                            "mtype": 4,
+                            "ext": {
+                                "origbidcpm": 29,
+                                "prebid": {
+                                    "targeting": {
+                                        "hb_bidder": "appnexus",
+                                        "hb_bidder_appnexus": "appnexus",
+                                        "hb_cache_host": "www.pbcserver.com",
+                                        "hb_cache_host_appnex": "www.pbcserver.com",
+                                        "hb_cache_path": "/pbcache/endpoint",
+                                        "hb_cache_path_appnex": "/pbcache/endpoint",
+                                        "hb_pb": "28.80000",
+                                        "hb_pb_appnexus": "28.80000",
+                                        "hb_pb_cat_dur": "28.80000_Sports_0s_appnexus",
+                                        "hb_pb_cat_dur_appnex": "28.80000_Sports_0s_appnexus",
+                                        "hb_size": "300x500",
+                                        "hb_size_appnexus": "300x500"
+                                    },
+                                    "type": "native"
+                                }
+                            },
+                            "h": 500,
+                            "id": "apn-native-bid",
+                            "impid": "imp-id-3",
+                            "price": 29,
+                            "w": 300
+                        }
+                    ]
+                }
+            ]
+        }
+    }
+}
\ No newline at end of file
diff --git a/exchange/exchangetest/mediatypepricegranularity-native.json b/exchange/exchangetest/mediatypepricegranularity-native.json
new file mode 100644
index 00000000..57a318e1
--- /dev/null
+++ b/exchange/exchangetest/mediatypepricegranularity-native.json
@@ -0,0 +1,222 @@
+{
+    "incomingRequest": {
+        "ortbRequest": {
+            "id": "some-request-id",
+            "site": {
+                "page": "test.somepage.com"
+            },
+            "imp": [
+                {
+                    "id": "my-imp-id",
+                    "video": {
+                        "mimes": [
+                            "video/mp4"
+                        ]
+                    },
+                    "ext": {
+                        "prebid": {
+                            "bidder": {
+                                "appnexus": {
+                                    "placementId": 1
+                                }
+                            }
+                        }
+                    }
+                },
+                {
+                    "id": "imp-id-2",
+                    "video": {
+                        "mimes": [
+                            "video/mp4"
+                        ]
+                    },
+                    "ext": {
+                        "prebid": {
+                            "bidder": {
+                                "appnexus": {
+                                    "placementId": 1
+                                }
+                            }
+                        }
+                    }
+                }
+            ],
+            "ext": {
+                "prebid": {
+                    "targeting": {
+                        "includebrandcategory": {
+                            "primaryadserver": 1,
+                            "publisher": "",
+                            "withcategory": true
+                        },
+                        "pricegranularity": {
+                            "precision": 2,
+                            "ranges": [
+                                {
+                                    "min": 0,
+                                    "max": 20,
+                                    "increment": 2
+                                }
+                            ]
+                        },
+                        "mediatypepricegranularity": {
+                            "banner": {
+                                "precision": 3,
+                                "ranges": [
+                                    {
+                                        "max": 20,
+                                        "increment": 4.5
+                                    }
+                                ]
+                            },
+                            "video": {
+                                "precision": 4,
+                                "ranges": [
+                                    {
+                                        "min": 10,
+                                        "max": 30,
+                                        "increment": 1.5
+                                    }
+                                ]
+                            },
+                            "native": {
+                                "precision": 5,
+                                "ranges": [
+                                    {
+                                        "max": 30,
+                                        "increment": 1.8
+                                    }
+                                ]
+                            }
+                        },
+                        "includewinners": true,
+                        "includebidderkeys": true,
+                        "appendbiddernames": true
+                    }
+                }
+            }
+        },
+        "usersyncs": {
+            "appnexus": "123"
+        }
+    },
+    "outgoingRequests": {
+        "appnexus": {
+            "mockResponse": {
+                "pbsSeatBids": [
+                    {
+                        "pbsBids": [
+                            {
+                                "ortbBid": {
+                                    "id": "apn-bid",
+                                    "impid": "my-imp-id",
+                                    "price": 24,
+                                    "w": 200,
+                                    "h": 250,
+                                    "crid": "creative-1",
+                                    "cat": [
+                                        "IAB1-1"
+                                    ],
+                                    "mtype": 4
+                                },
+                                "bidType": "native"
+                            },
+                            {
+                                "ortbBid": {
+                                    "id": "apn-other-bid",
+                                    "impid": "imp-id-2",
+                                    "price": 29,
+                                    "w": 300,
+                                    "h": 500,
+                                    "crid": "creative-3",
+                                    "cat": [
+                                        "IAB1-2"
+                                    ],
+                                    "mtype": 4
+                                },
+                                "bidType": "native"
+                            }
+                        ],
+                        "seat": "appnexus"
+                    }
+                ]
+            }
+        }
+    },
+    "response": {
+        "bids": {
+            "id": "some-request-id",
+            "seatbid": [
+                {
+                    "seat": "appnexus",
+                    "bid": [
+                        {
+                            "id": "apn-bid",
+                            "impid": "my-imp-id",
+                            "price": 24,
+                            "w": 200,
+                            "h": 250,
+                            "crid": "creative-1",
+                            "cat": [
+                                "IAB1-1"
+                            ],
+                            "mtype": 4,
+                            "ext": {
+                                "origbidcpm": 24,
+                                "prebid": {
+                                    "type": "native",
+                                    "targeting": {
+                                        "hb_bidder": "appnexus",
+                                        "hb_bidder_appnexus": "appnexus",
+                                        "hb_cache_host": "www.pbcserver.com",
+                                        "hb_cache_host_appnex": "www.pbcserver.com",
+                                        "hb_cache_path": "/pbcache/endpoint",
+                                        "hb_cache_path_appnex": "/pbcache/endpoint",
+                                        "hb_pb": "23.40000",
+                                        "hb_pb_appnexus": "23.40000",
+                                        "hb_pb_cat_dur": "23.40000_VideoGames_0s_appnexus",
+                                        "hb_pb_cat_dur_appnex": "23.40000_VideoGames_0s_appnexus",
+                                        "hb_size": "200x250",
+                                        "hb_size_appnexus": "200x250"
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "cat": [
+                                "IAB1-2"
+                            ],
+                            "crid": "creative-3",
+                            "mtype": 4,
+                            "ext": {
+                                "origbidcpm": 29,
+                                "prebid": {
+                                    "targeting": {
+                                        "hb_bidder": "appnexus",
+                                        "hb_bidder_appnexus": "appnexus",
+                                        "hb_cache_host": "www.pbcserver.com",
+                                        "hb_cache_host_appnex": "www.pbcserver.com",
+                                        "hb_cache_path": "/pbcache/endpoint",
+                                        "hb_cache_path_appnex": "/pbcache/endpoint",
+                                        "hb_pb": "28.80000",
+                                        "hb_pb_appnexus": "28.80000",
+                                        "hb_pb_cat_dur": "28.80000_HomeDecor_0s_appnexus",
+                                        "hb_pb_cat_dur_appnex": "28.80000_HomeDecor_0s_appnexus",
+                                        "hb_size": "300x500",
+                                        "hb_size_appnexus": "300x500"
+                                    },
+                                    "type": "native"
+                                }
+                            },
+                            "h": 500,
+                            "id": "apn-other-bid",
+                            "impid": "imp-id-2",
+                            "price": 29,
+                            "w": 300
+                        }
+                    ]
+                }
+            ]
+        }
+    }
+}
\ No newline at end of file
diff --git a/exchange/price_granularity_test.go b/exchange/price_granularity_test.go
index 50e83778..4f9337aa 100644
--- a/exchange/price_granularity_test.go
+++ b/exchange/price_granularity_test.go
@@ -1,9 +1,11 @@
 package exchange
 
 import (
+	"encoding/json"
 	"math"
 	"testing"
 
+	"github.com/prebid/openrtb/v19/openrtb2"
 	"github.com/prebid/prebid-server/openrtb_ext"
 	"github.com/prebid/prebid-server/util/ptrutil"
 	"github.com/stretchr/testify/assert"
@@ -51,112 +53,149 @@ func TestGetPriceBucketString(t *testing.T) {
 	// Define test cases
 	type aTest struct {
 		granularityId       string
-		granularity         openrtb_ext.PriceGranularity
+		targetData          targetData
 		expectedPriceBucket string
 	}
 	testGroups := []struct {
 		groupDesc string
-		cpm       float64
+		bid       openrtb2.Bid
 		testCases []aTest
 	}{
 		{
 			groupDesc: "cpm below the max in every price bucket",
-			cpm:       1.87,
+			bid:       openrtb2.Bid{Price: 1.87},
 			testCases: []aTest{
-				{"low", low, "1.50"},
-				{"medium", medium, "1.80"},
-				{"high", high, "1.87"},
-				{"auto", auto, "1.85"},
-				{"dense", dense, "1.87"},
-				{"custom1", custom1, "1.86"},
-				{"custom2", custom2, "1.50"},
+				{"low", targetData{priceGranularity: low}, "1.50"},
+				{"medium", targetData{priceGranularity: medium}, "1.80"},
+				{"high", targetData{priceGranularity: high}, "1.87"},
+				{"auto", targetData{priceGranularity: auto}, "1.85"},
+				{"dense", targetData{priceGranularity: dense}, "1.87"},
+				{"custom1", targetData{priceGranularity: custom1}, "1.86"},
+				{"custom2", targetData{priceGranularity: custom2}, "1.50"},
 			},
 		},
 		{
 			groupDesc: "cpm above the max in low price bucket",
-			cpm:       5.72,
+			bid:       openrtb2.Bid{Price: 5.72},
 			testCases: []aTest{
-				{"low", low, "5.00"},
-				{"medium", medium, "5.70"},
-				{"high", high, "5.72"},
-				{"auto", auto, "5.70"},
-				{"dense", dense, "5.70"},
-				{"custom1", custom1, "5.70"},
-				{"custom2", custom2, "5.10"},
+				{"low", targetData{priceGranularity: low}, "5.00"},
+				{"medium", targetData{priceGranularity: medium}, "5.70"},
+				{"high", targetData{priceGranularity: high}, "5.72"},
+				{"auto", targetData{priceGranularity: auto}, "5.70"},
+				{"dense", targetData{priceGranularity: dense}, "5.70"},
+				{"custom1", targetData{priceGranularity: custom1}, "5.70"},
+				{"custom2", targetData{priceGranularity: custom2}, "5.10"},
+			},
+		},
+		{
+			groupDesc: "media type price granularity for bid type video",
+			bid:       openrtb2.Bid{Price: 5.0, MType: openrtb2.MarkupVideo},
+			testCases: []aTest{
+				{"medium", targetData{priceGranularity: medium}, "5.00"},
+				{"video-custom2", targetData{priceGranularity: medium, mediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{Video: &custom2}}, "3.90"},
+				{"banner-custom2", targetData{priceGranularity: medium, mediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{Banner: &custom2}}, "5.00"},
+			},
+		},
+		{
+			groupDesc: "media type price granularity for bid type banner",
+			bid:       openrtb2.Bid{Price: 5.0, MType: openrtb2.MarkupBanner},
+			testCases: []aTest{
+				{"medium", targetData{priceGranularity: medium}, "5.00"},
+				{"video-custom2", targetData{priceGranularity: medium, mediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{Video: &custom2}}, "5.00"},
+				{"banner-custom2", targetData{priceGranularity: medium, mediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{Banner: &custom2}}, "3.90"},
+			},
+		},
+		{
+			groupDesc: "media type price granularity for bid type native",
+			bid:       openrtb2.Bid{Price: 5.0, MType: openrtb2.MarkupNative},
+			testCases: []aTest{
+				{"medium", targetData{priceGranularity: medium}, "5.00"},
+				{"video-custom2", targetData{priceGranularity: medium, mediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{Video: &custom2}}, "5.00"},
+				{"native-custom2", targetData{priceGranularity: medium, mediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{Native: &custom2}}, "3.90"},
+			},
+		},
+		{
+			groupDesc: "media type price granularity set but bid type incorrect",
+			bid:       openrtb2.Bid{Price: 5.0, Ext: json.RawMessage(`{`)},
+			testCases: []aTest{
+				{"medium", targetData{priceGranularity: medium}, "5.00"},
+				{"video-custom2", targetData{priceGranularity: medium, mediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{Video: &custom2}}, "5.00"},
+				{"banner-custom2", targetData{priceGranularity: medium, mediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{Banner: &custom2}}, "5.00"},
+				{"native-custom2", targetData{priceGranularity: medium, mediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{Native: &custom2}}, "5.00"},
 			},
 		},
 		{
 			groupDesc: "cpm equal the max for custom granularity",
-			cpm:       10,
+			bid:       openrtb2.Bid{Price: 10},
 			testCases: []aTest{
-				{"custom1", custom1, "10.00"},
-				{"custom2", custom2, "9.90"},
+				{"custom1", targetData{priceGranularity: custom1}, "10.00"},
+				{"custom2", targetData{priceGranularity: custom2}, "9.90"},
 			},
 		},
 		{
 			groupDesc: "Precision value corner cases",
-			cpm:       1.876,
+			bid:       openrtb2.Bid{Price: 1.876},
 			testCases: []aTest{
 				{
 					"Negative precision defaults to number of digits already in CPM float",
-					openrtb_ext.PriceGranularity{Precision: ptrutil.ToPtr(-1), Ranges: []openrtb_ext.GranularityRange{{Max: 5, Increment: 0.05}}},
+					targetData{priceGranularity: openrtb_ext.PriceGranularity{Precision: ptrutil.ToPtr(-1), Ranges: []openrtb_ext.GranularityRange{{Max: 5, Increment: 0.05}}}},
 					"1.85",
 				},
 				{
 					"Precision value equals zero, we expect to round up to the nearest integer",
-					openrtb_ext.PriceGranularity{Precision: ptrutil.ToPtr(0), Ranges: []openrtb_ext.GranularityRange{{Max: 5, Increment: 0.05}}},
+					targetData{priceGranularity: openrtb_ext.PriceGranularity{Precision: ptrutil.ToPtr(0), Ranges: []openrtb_ext.GranularityRange{{Max: 5, Increment: 0.05}}}},
 					"2",
 				},
 				{
 					"Largest precision value PBS supports 15",
-					openrtb_ext.PriceGranularity{Precision: ptrutil.ToPtr(15), Ranges: []openrtb_ext.GranularityRange{{Max: 5, Increment: 0.05}}},
+					targetData{priceGranularity: openrtb_ext.PriceGranularity{Precision: ptrutil.ToPtr(15), Ranges: []openrtb_ext.GranularityRange{{Max: 5, Increment: 0.05}}}},
 					"1.850000000000000",
 				},
 			},
 		},
 		{
 			groupDesc: "Increment value corner cases",
-			cpm:       1.876,
+			bid:       openrtb2.Bid{Price: 1.876},
 			testCases: []aTest{
 				{
 					"Negative increment, return empty string",
-					openrtb_ext.PriceGranularity{Precision: ptrutil.ToPtr(2), Ranges: []openrtb_ext.GranularityRange{{Max: 5, Increment: -0.05}}},
+					targetData{priceGranularity: openrtb_ext.PriceGranularity{Precision: ptrutil.ToPtr(2), Ranges: []openrtb_ext.GranularityRange{{Max: 5, Increment: -0.05}}}},
 					"",
 				},
 				{
 					"Zero increment, return empty string",
-					openrtb_ext.PriceGranularity{Precision: ptrutil.ToPtr(2), Ranges: []openrtb_ext.GranularityRange{{Max: 5}}},
+					targetData{priceGranularity: openrtb_ext.PriceGranularity{Precision: ptrutil.ToPtr(2), Ranges: []openrtb_ext.GranularityRange{{Max: 5}}}},
 					"",
 				},
 				{
 					"Increment value is greater than CPM itself, return zero float value",
-					openrtb_ext.PriceGranularity{Precision: ptrutil.ToPtr(2), Ranges: []openrtb_ext.GranularityRange{{Max: 5, Increment: 1.877}}},
+					targetData{priceGranularity: openrtb_ext.PriceGranularity{Precision: ptrutil.ToPtr(2), Ranges: []openrtb_ext.GranularityRange{{Max: 5, Increment: 1.877}}}},
 					"0.00",
 				},
 			},
 		},
 		{
 			groupDesc: "Negative Cpm, return empty string since it does not belong into any range",
-			cpm:       -1.876,
-			testCases: []aTest{{"low", low, ""}},
+			bid:       openrtb2.Bid{Price: -1.876},
+			testCases: []aTest{{"low", targetData{priceGranularity: low}, ""}},
 		},
 		{
 			groupDesc: "Zero value Cpm, return the same, only in string format",
-			cpm:       0,
-			testCases: []aTest{{"low", low, "0.00"}},
+			bid:       openrtb2.Bid{Price: 0},
+			testCases: []aTest{{"low", targetData{priceGranularity: low}, "0.00"}},
 		},
 		{
 			groupDesc: "Large Cpm, return bucket Max",
-			cpm:       math.MaxFloat64,
-			testCases: []aTest{{"low", low, "5.00"}},
+			bid:       openrtb2.Bid{Price: math.MaxFloat64},
+			testCases: []aTest{{"low", targetData{priceGranularity: low}, "5.00"}},
 		},
 	}
 
 	for _, testGroup := range testGroups {
 		for i, test := range testGroup.testCases {
 			var priceBucket string
-			assert.NotPanics(t, func() { priceBucket = GetPriceBucket(testGroup.cpm, test.granularity) }, "Group: %s Granularity: %d", testGroup.groupDesc, i)
-			assert.Equal(t, test.expectedPriceBucket, priceBucket, "Group: %s Granularity: %s :: Expected %s, got %s from %f", testGroup.groupDesc, test.granularityId, test.expectedPriceBucket, priceBucket, testGroup.cpm)
+			assert.NotPanics(t, func() { priceBucket = GetPriceBucket(testGroup.bid, test.targetData) }, "Group: %s Granularity: %d", testGroup.groupDesc, i)
+			assert.Equal(t, test.expectedPriceBucket, priceBucket, "Group: %s Granularity: %s :: Expected %s, got %s from %f", testGroup.groupDesc, test.granularityId, test.expectedPriceBucket, priceBucket, testGroup.bid.Price)
 		}
 	}
 }
diff --git a/exchange/targeting_test.go b/exchange/targeting_test.go
index f1f5df42..a5f49689 100644
--- a/exchange/targeting_test.go
+++ b/exchange/targeting_test.go
@@ -914,7 +914,7 @@ func TestSetTargeting(t *testing.T) {
 	for _, test := range TargetingTests {
 		auc := &test.Auction
 		// Set rounded prices from the auction data
-		auc.setRoundedPrices(test.TargetData.priceGranularity)
+		auc.setRoundedPrices(test.TargetData)
 		winningBids := make(map[string]*entities.PbsOrtbBid)
 		// Set winning bids from the auction data
 		for imp, bidsByBidder := range auc.winningBidsByBidder {
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index 56ba0e1d..6fe0e55f 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -2294,6 +2294,7 @@ func TestCleanOpenRTBRequestsWithOpenRTBDowngrade(t *testing.T) {
 	bidReq.Regs.GPPSID = []int8{6}
 	bidReq.User.ID = ""
 	bidReq.User.BuyerUID = ""
+	bidReq.User.Yob = 0
 
 	downgradedRegs := *bidReq.Regs
 	downgradedUser := *bidReq.User
@@ -3863,7 +3864,7 @@ func Test_isBidderInExtAlternateBidderCodes(t *testing.T) {
 			name: "adapter defined in alternatebiddercodes but currentMultiBidBidder not in AllowedBidders list",
 			args: args{
 				adapter:               string(openrtb_ext.BidderPubmatic),
-				currentMultiBidBidder: string(openrtb_ext.BidderGroupm),
+				currentMultiBidBidder: "groupm",
 				adapterABC: &openrtb_ext.ExtAlternateBidderCodes{
 					Bidders: map[string]openrtb_ext.ExtAdapterAlternateBidderCodes{
 						string(openrtb_ext.BidderPubmatic): {
@@ -3878,11 +3879,11 @@ func Test_isBidderInExtAlternateBidderCodes(t *testing.T) {
 			name: "adapter defined in alternatebiddercodes with currentMultiBidBidder mentioned in AllowedBidders list",
 			args: args{
 				adapter:               string(openrtb_ext.BidderPubmatic),
-				currentMultiBidBidder: string(openrtb_ext.BidderGroupm),
+				currentMultiBidBidder: "groupm",
 				adapterABC: &openrtb_ext.ExtAlternateBidderCodes{
 					Bidders: map[string]openrtb_ext.ExtAdapterAlternateBidderCodes{
 						string(openrtb_ext.BidderPubmatic): {
-							AllowedBidderCodes: []string{string(openrtb_ext.BidderGroupm)},
+							AllowedBidderCodes: []string{"groupm"},
 						},
 					},
 				},
@@ -3893,7 +3894,7 @@ func Test_isBidderInExtAlternateBidderCodes(t *testing.T) {
 			name: "adapter defined in alternatebiddercodes with AllowedBidders list as *",
 			args: args{
 				adapter:               string(openrtb_ext.BidderPubmatic),
-				currentMultiBidBidder: string(openrtb_ext.BidderGroupm),
+				currentMultiBidBidder: "groupm",
 				adapterABC: &openrtb_ext.ExtAlternateBidderCodes{
 					Bidders: map[string]openrtb_ext.ExtAdapterAlternateBidderCodes{
 						string(openrtb_ext.BidderPubmatic): {
@@ -4004,7 +4005,7 @@ func Test_buildRequestExtMultiBid(t *testing.T) {
 				adapter: string(openrtb_ext.BidderPubmatic),
 				reqMultiBid: []*openrtb_ext.ExtMultiBid{
 					{
-						Bidder:  string(openrtb_ext.BidderGroupm),
+						Bidder:  "groupm",
 						MaxBids: ptrutil.ToPtr(3),
 					},
 					{
@@ -4019,14 +4020,14 @@ func Test_buildRequestExtMultiBid(t *testing.T) {
 				adapterABC: &openrtb_ext.ExtAlternateBidderCodes{
 					Bidders: map[string]openrtb_ext.ExtAdapterAlternateBidderCodes{
 						string(openrtb_ext.BidderPubmatic): {
-							AllowedBidderCodes: []string{string(openrtb_ext.BidderGroupm)},
+							AllowedBidderCodes: []string{"groupm"},
 						},
 					},
 				},
 			},
 			want: []*openrtb_ext.ExtMultiBid{
 				{
-					Bidder:  string(openrtb_ext.BidderGroupm),
+					Bidder:  "groupm",
 					MaxBids: ptrutil.ToPtr(3),
 				},
 				{
@@ -4041,7 +4042,7 @@ func Test_buildRequestExtMultiBid(t *testing.T) {
 				adapter: string(openrtb_ext.BidderAppnexus),
 				reqMultiBid: []*openrtb_ext.ExtMultiBid{
 					{
-						Bidder:  string(openrtb_ext.BidderGroupm),
+						Bidder:  "groupm",
 						MaxBids: ptrutil.ToPtr(3),
 					},
 					{
@@ -4056,14 +4057,14 @@ func Test_buildRequestExtMultiBid(t *testing.T) {
 				adapterABC: &openrtb_ext.ExtAlternateBidderCodes{
 					Bidders: map[string]openrtb_ext.ExtAdapterAlternateBidderCodes{
 						string(openrtb_ext.BidderAppnexus): {
-							AllowedBidderCodes: []string{string(openrtb_ext.BidderGroupm)},
+							AllowedBidderCodes: []string{"groupm"},
 						},
 					},
 				},
 			},
 			want: []*openrtb_ext.ExtMultiBid{
 				{
-					Bidder:  string(openrtb_ext.BidderGroupm),
+					Bidder:  "groupm",
 					MaxBids: ptrutil.ToPtr(3),
 				},
 				{
@@ -4078,7 +4079,7 @@ func Test_buildRequestExtMultiBid(t *testing.T) {
 				adapter: string(openrtb_ext.BidderPubmatic),
 				reqMultiBid: []*openrtb_ext.ExtMultiBid{
 					{
-						Bidder:  string(openrtb_ext.BidderGroupm),
+						Bidder:  "groupm",
 						MaxBids: ptrutil.ToPtr(3),
 					},
 					{
@@ -4100,7 +4101,7 @@ func Test_buildRequestExtMultiBid(t *testing.T) {
 			},
 			want: []*openrtb_ext.ExtMultiBid{
 				{
-					Bidder:  string(openrtb_ext.BidderGroupm),
+					Bidder:  "groupm",
 					MaxBids: ptrutil.ToPtr(3),
 				},
 				{
@@ -4123,7 +4124,7 @@ func Test_buildRequestExtMultiBid(t *testing.T) {
 				adapter: string(openrtb_ext.BidderAppnexus),
 				reqMultiBid: []*openrtb_ext.ExtMultiBid{
 					{
-						Bidder:  string(openrtb_ext.BidderGroupm),
+						Bidder:  "groupm",
 						MaxBids: ptrutil.ToPtr(3),
 					},
 					{
@@ -4145,7 +4146,7 @@ func Test_buildRequestExtMultiBid(t *testing.T) {
 			},
 			want: []*openrtb_ext.ExtMultiBid{
 				{
-					Bidder:  string(openrtb_ext.BidderGroupm),
+					Bidder:  "groupm",
 					MaxBids: ptrutil.ToPtr(3),
 				},
 				{
@@ -4170,3 +4171,105 @@ func Test_buildRequestExtMultiBid(t *testing.T) {
 		})
 	}
 }
+
+func TestGetPrebidMediaTypeForBid(t *testing.T) {
+	tests := []struct {
+		description     string
+		inputBid        openrtb2.Bid
+		expectedBidType openrtb_ext.BidType
+		expectedError   string
+	}{
+		{
+			description:     "Valid bid ext with bid type native",
+			inputBid:        openrtb2.Bid{ID: "bidId", ImpID: "impId", Ext: json.RawMessage(`{"prebid": {"type": "native"}}`)},
+			expectedBidType: openrtb_ext.BidTypeNative,
+		},
+		{
+			description:   "Valid bid ext with non-existing bid type",
+			inputBid:      openrtb2.Bid{ID: "bidId", ImpID: "impId", Ext: json.RawMessage(`{"prebid": {"type": "unknown"}}`)},
+			expectedError: "Failed to parse bid mediatype for impression \"impId\", invalid BidType: unknown",
+		},
+		{
+			description:   "Invalid bid ext",
+			inputBid:      openrtb2.Bid{ID: "bidId", ImpID: "impId", Ext: json.RawMessage(`[true`)},
+			expectedError: "Failed to parse bid mediatype for impression \"impId\", unexpected end of JSON input",
+		},
+		{
+			description:   "Bid ext is nil",
+			inputBid:      openrtb2.Bid{ID: "bidId", ImpID: "impId", Ext: nil},
+			expectedError: "Failed to parse bid mediatype for impression \"impId\"",
+		},
+		{
+			description:   "Empty bid ext",
+			inputBid:      openrtb2.Bid{ID: "bidId", ImpID: "impId", Ext: json.RawMessage(`{}`)},
+			expectedError: "Failed to parse bid mediatype for impression \"impId\"",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.description, func(t *testing.T) {
+			bidType, err := getPrebidMediaTypeForBid(tt.inputBid)
+			if len(tt.expectedError) == 0 {
+				assert.Equal(t, tt.expectedBidType, bidType)
+			} else {
+				assert.Equal(t, tt.expectedError, err.Error())
+			}
+
+		})
+	}
+}
+
+func TestGetMediaTypeForBid(t *testing.T) {
+	tests := []struct {
+		description     string
+		inputBid        openrtb2.Bid
+		expectedBidType openrtb_ext.BidType
+		expectedError   string
+	}{
+		{
+			description:     "Valid bid ext with bid type native",
+			inputBid:        openrtb2.Bid{ID: "bidId", ImpID: "impId", Ext: json.RawMessage(`{"prebid": {"type": "native"}}`)},
+			expectedBidType: openrtb_ext.BidTypeNative,
+		},
+		{
+			description:   "invalid bid ext",
+			inputBid:      openrtb2.Bid{ID: "bidId", ImpID: "impId", Ext: json.RawMessage(`{"prebid"`)},
+			expectedError: "Failed to parse bid mediatype for impression \"impId\", unexpected end of JSON input",
+		},
+		{
+			description:     "Valid bid ext with mtype native",
+			inputBid:        openrtb2.Bid{ID: "bidId", ImpID: "impId", MType: openrtb2.MarkupNative},
+			expectedBidType: openrtb_ext.BidTypeNative,
+		},
+		{
+			description:     "Valid bid ext with mtype banner",
+			inputBid:        openrtb2.Bid{ID: "bidId", ImpID: "impId", MType: openrtb2.MarkupBanner},
+			expectedBidType: openrtb_ext.BidTypeBanner,
+		},
+		{
+			description:     "Valid bid ext with mtype video",
+			inputBid:        openrtb2.Bid{ID: "bidId", ImpID: "impId", MType: openrtb2.MarkupVideo},
+			expectedBidType: openrtb_ext.BidTypeVideo,
+		},
+		{
+			description:     "Valid bid ext with mtype audio",
+			inputBid:        openrtb2.Bid{ID: "bidId", ImpID: "impId", MType: openrtb2.MarkupAudio},
+			expectedBidType: openrtb_ext.BidTypeAudio,
+		},
+		{
+			description:   "Valid bid ext with mtype unknown",
+			inputBid:      openrtb2.Bid{ID: "bidId", ImpID: "impId", MType: 8},
+			expectedError: "Failed to parse bid mType for impression \"impId\"",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.description, func(t *testing.T) {
+			bidType, err := getMediaTypeForBid(tt.inputBid)
+			if len(tt.expectedError) == 0 {
+				assert.Equal(t, tt.expectedBidType, bidType)
+			} else {
+				assert.Equal(t, tt.expectedError, err.Error())
+			}
+
+		})
+	}
+}
diff --git a/ortb/default_test.go b/ortb/default_test.go
index 0ea35f6e..04eeeebd 100644
--- a/ortb/default_test.go
+++ b/ortb/default_test.go
@@ -36,7 +36,7 @@ func TestSetDefaults(t *testing.T) {
 		{
 			name:            "targeting", // tests integration with setDefaultsTargeting
 			givenRequest:    openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"targeting":{}}}`)},
-			expectedRequest: openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":20,"increment":0.1}]},"includewinners":true,"includebidderkeys":true}}}`)},
+			expectedRequest: openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":20,"increment":0.1}]},"mediatypepricegranularity":{},"includewinners":true,"includebidderkeys":true}}}`)},
 		},
 		{
 			name:            "imp", // tests integration with setDefaultsImp
@@ -152,6 +152,40 @@ func TestSetDefaultsTargeting(t *testing.T) {
 			},
 			expectedModified: true,
 		},
+		{
+			name: "populated-ranges-nil-mediatypepricegranularity-video-banner-native",
+			givenTargeting: &openrtb_ext.ExtRequestTargeting{
+				PriceGranularity: &openrtb_ext.PriceGranularity{
+					Precision: ptrutil.ToPtr(4),
+					Ranges:    nil,
+				},
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Video: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(4),
+						Ranges:    nil,
+					},
+					Banner: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(4),
+						Ranges:    nil,
+					},
+					Native: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(4),
+						Ranges:    nil,
+					},
+				},
+			},
+			expectedTargeting: &openrtb_ext.ExtRequestTargeting{
+				PriceGranularity: &defaultGranularity,
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Video:  &defaultGranularity,
+					Banner: &defaultGranularity,
+					Native: &defaultGranularity,
+				},
+				IncludeWinners:    ptrutil.ToPtr(DefaultTargetingIncludeWinners),
+				IncludeBidderKeys: ptrutil.ToPtr(DefaultTargetingIncludeBidderKeys),
+			},
+			expectedModified: true,
+		},
 		{
 			name: "populated-ranges-empty",
 			givenTargeting: &openrtb_ext.ExtRequestTargeting{
@@ -167,6 +201,40 @@ func TestSetDefaultsTargeting(t *testing.T) {
 			},
 			expectedModified: true,
 		},
+		{
+			name: "populated-ranges-empty-mediatypepricegranularity-video-banner-native",
+			givenTargeting: &openrtb_ext.ExtRequestTargeting{
+				PriceGranularity: &openrtb_ext.PriceGranularity{
+					Precision: ptrutil.ToPtr(4),
+					Ranges:    []openrtb_ext.GranularityRange{},
+				},
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Video: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(4),
+						Ranges:    []openrtb_ext.GranularityRange{},
+					},
+					Banner: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(4),
+						Ranges:    []openrtb_ext.GranularityRange{},
+					},
+					Native: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(4),
+						Ranges:    []openrtb_ext.GranularityRange{},
+					},
+				},
+			},
+			expectedTargeting: &openrtb_ext.ExtRequestTargeting{
+				PriceGranularity: &defaultGranularity,
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Video:  &defaultGranularity,
+					Banner: &defaultGranularity,
+					Native: &defaultGranularity,
+				},
+				IncludeWinners:    ptrutil.ToPtr(DefaultTargetingIncludeWinners),
+				IncludeBidderKeys: ptrutil.ToPtr(DefaultTargetingIncludeBidderKeys),
+			},
+			expectedModified: true,
+		},
 		{
 			name: "populated-full", // no defaults set
 			givenTargeting: &openrtb_ext.ExtRequestTargeting{
@@ -187,6 +255,51 @@ func TestSetDefaultsTargeting(t *testing.T) {
 			},
 			expectedModified: false,
 		},
+		{
+			name: "populated-full-mediatypepricegranularity-video-banner", // no defaults set
+			givenTargeting: &openrtb_ext.ExtRequestTargeting{
+				PriceGranularity: &openrtb_ext.PriceGranularity{
+					Precision: ptrutil.ToPtr(4),
+					Ranges:    []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}},
+				},
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Video: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(4),
+						Ranges:    []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}},
+					},
+					Banner: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(4),
+						Ranges:    []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}},
+					},
+					Native: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(4),
+						Ranges:    []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}},
+					},
+				},
+				IncludeWinners:    ptrutil.ToPtr(false),
+				IncludeBidderKeys: ptrutil.ToPtr(false),
+			},
+			expectedTargeting: &openrtb_ext.ExtRequestTargeting{
+				PriceGranularity: &openrtb_ext.PriceGranularity{
+					Precision: ptrutil.ToPtr(4),
+					Ranges:    []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}},
+				},
+				MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{
+					Video: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(4),
+						Ranges:    []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}},
+					Banner: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(4),
+						Ranges:    []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}},
+					Native: &openrtb_ext.PriceGranularity{
+						Precision: ptrutil.ToPtr(4),
+						Ranges:    []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}},
+				},
+				IncludeWinners:    ptrutil.ToPtr(false),
+				IncludeBidderKeys: ptrutil.ToPtr(false),
+			},
+			expectedModified: false,
+		},
 		{
 			name: "setDefaultsPriceGranularity-integration",
 			givenTargeting: &openrtb_ext.ExtRequestTargeting{
@@ -277,9 +390,9 @@ func TestSetDefaultsPriceGranularity(t *testing.T) {
 
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
-			actualModified := setDefaultsPriceGranularity(test.givenGranularity)
+			pg, actualModified := setDefaultsPriceGranularity(test.givenGranularity)
 			assert.Equal(t, test.expectedModified, actualModified)
-			assert.Equal(t, test.expectedGranularity, test.givenGranularity)
+			assert.Equal(t, test.expectedGranularity, pg)
 		})
 	}
 }
diff --git a/privacy/enforcement_test.go b/privacy/enforcement_test.go
index 5902a913..a9d7ca92 100644
--- a/privacy/enforcement_test.go
+++ b/privacy/enforcement_test.go
@@ -95,7 +95,7 @@ func TestApply(t *testing.T) {
 			expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
 			expectedDeviceGeo:  ScrubStrategyGeoReducedPrecision,
-			expectedUser:       ScrubStrategyUserID,
+			expectedUser:       ScrubStrategyUserIDAndDemographic,
 			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
 		},
 		{
@@ -127,7 +127,7 @@ func TestApply(t *testing.T) {
 			expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
 			expectedDeviceGeo:  ScrubStrategyGeoReducedPrecision,
-			expectedUser:       ScrubStrategyUserID,
+			expectedUser:       ScrubStrategyUserIDAndDemographic,
 			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
 		},
 		{
@@ -143,7 +143,7 @@ func TestApply(t *testing.T) {
 			expectedDeviceIPv4: ScrubStrategyIPV4None,
 			expectedDeviceIPv6: ScrubStrategyIPV6None,
 			expectedDeviceGeo:  ScrubStrategyGeoNone,
-			expectedUser:       ScrubStrategyUserID,
+			expectedUser:       ScrubStrategyUserIDAndDemographic,
 			expectedUserGeo:    ScrubStrategyGeoNone,
 		},
 		{
@@ -175,7 +175,7 @@ func TestApply(t *testing.T) {
 			expectedDeviceIPv4: ScrubStrategyIPV4Lowest8,
 			expectedDeviceIPv6: ScrubStrategyIPV6Lowest16,
 			expectedDeviceGeo:  ScrubStrategyGeoReducedPrecision,
-			expectedUser:       ScrubStrategyUserID,
+			expectedUser:       ScrubStrategyUserIDAndDemographic,
 			expectedUserGeo:    ScrubStrategyGeoReducedPrecision,
 		},
 		{
diff --git a/privacy/scrubber_test.go b/privacy/scrubber_test.go
index d8f2fdd8..7b4afac2 100644
--- a/privacy/scrubber_test.go
+++ b/privacy/scrubber_test.go
@@ -269,57 +269,6 @@ func TestScrubUser(t *testing.T) {
 			scrubUser: ScrubStrategyUserIDAndDemographic,
 			scrubGeo:  ScrubStrategyGeoNone,
 		},
-		{
-			description: "User ID & Geo Full",
-			expected: &openrtb2.User{
-				ID:       "",
-				BuyerUID: "",
-				Yob:      42,
-				Gender:   "anyGender",
-				Ext:      json.RawMessage(`{}`),
-				Geo:      &openrtb2.Geo{},
-			},
-			scrubUser: ScrubStrategyUserID,
-			scrubGeo:  ScrubStrategyGeoFull,
-		},
-		{
-			description: "User ID & Geo Reduced",
-			expected: &openrtb2.User{
-				ID:       "",
-				BuyerUID: "",
-				Yob:      42,
-				Gender:   "anyGender",
-				Ext:      json.RawMessage(`{}`),
-				Geo: &openrtb2.Geo{
-					Lat:   123.46,
-					Lon:   678.89,
-					Metro: "some metro",
-					City:  "some city",
-					ZIP:   "some zip",
-				},
-			},
-			scrubUser: ScrubStrategyUserID,
-			scrubGeo:  ScrubStrategyGeoReducedPrecision,
-		},
-		{
-			description: "User ID & Geo None",
-			expected: &openrtb2.User{
-				ID:       "",
-				BuyerUID: "",
-				Yob:      42,
-				Gender:   "anyGender",
-				Ext:      json.RawMessage(`{}`),
-				Geo: &openrtb2.Geo{
-					Lat:   123.456,
-					Lon:   678.89,
-					Metro: "some metro",
-					City:  "some city",
-					ZIP:   "some zip",
-				},
-			},
-			scrubUser: ScrubStrategyUserID,
-			scrubGeo:  ScrubStrategyGeoNone,
-		},
 		{
 			description: "User None & Geo Full",
 			expected: &openrtb2.User{
diff --git a/usersync/cookie_test.go b/usersync/cookie_test.go
index 8efa3b74..ee5062ea 100644
--- a/usersync/cookie_test.go
+++ b/usersync/cookie_test.go
@@ -14,27 +14,24 @@ import (
 
 func TestOptOutCookie(t *testing.T) {
 	cookie := &Cookie{
-		uids:     map[string]uidWithExpiry{"appnexus": {UID: "test"}},
-		optOut:   true,
-		birthday: timestamp(),
+		uids:   map[string]uidWithExpiry{"appnexus": {UID: "test"}},
+		optOut: true,
 	}
 	ensureConsistency(t, cookie)
 }
 
 func TestEmptyOptOutCookie(t *testing.T) {
 	cookie := &Cookie{
-		uids:     make(map[string]uidWithExpiry),
-		optOut:   true,
-		birthday: timestamp(),
+		uids:   make(map[string]uidWithExpiry),
+		optOut: true,
 	}
 	ensureConsistency(t, cookie)
 }
 
 func TestEmptyCookie(t *testing.T) {
 	cookie := &Cookie{
-		uids:     make(map[string]uidWithExpiry),
-		optOut:   false,
-		birthday: timestamp(),
+		uids:   make(map[string]uidWithExpiry),
+		optOut: false,
 	}
 	ensureConsistency(t, cookie)
 }
@@ -68,8 +65,7 @@ func TestRejectAudienceNetworkCookie(t *testing.T) {
 		uids: map[string]uidWithExpiry{
 			"audienceNetwork": newTempId("0", 10),
 		},
-		optOut:   false,
-		birthday: timestamp(),
+		optOut: false,
 	}
 	parsed := ParseCookie(raw.ToHTTPCookie(90 * 24 * time.Hour))
 	if parsed.HasLiveSync("audienceNetwork") {
@@ -97,9 +93,8 @@ func TestOptOutReset(t *testing.T) {
 
 func TestOptIn(t *testing.T) {
 	cookie := &Cookie{
-		uids:     make(map[string]uidWithExpiry),
-		optOut:   true,
-		birthday: timestamp(),
+		uids:   make(map[string]uidWithExpiry),
+		optOut: true,
 	}
 
 	cookie.SetOptOut(false)
@@ -129,11 +124,9 @@ func TestParseCorruptedCookieJSON(t *testing.T) {
 }
 
 func TestParseNilSyncMap(t *testing.T) {
-	cookieJSON := "{\"bday\":123,\"optout\":true}"
-	cookieData := base64.URLEncoding.EncodeToString([]byte(cookieJSON))
 	raw := http.Cookie{
 		Name:  uidCookieName,
-		Value: cookieData,
+		Value: "",
 	}
 	parsed := ParseCookie(&raw)
 	ensureEmptyMap(t, parsed)
@@ -167,8 +160,7 @@ func TestParseCookieFromRequestOptOut(t *testing.T) {
 			"foo": newTempId("fooID", 1),
 			"bar": newTempId("barID", 2),
 		},
-		optOut:   false,
-		birthday: timestamp(),
+		optOut: false,
 	}).ToHTTPCookie(24 * time.Hour)
 
 	testCases := []struct {
@@ -321,8 +313,7 @@ func TestTrimCookiesClosestExpirationDates(t *testing.T) {
 			"k6": newTempId("12345678901234567890123456789012345678901234567890", 3),
 			"k7": newTempId("abcdefghijklmnopqrstuvwxyz", 2),
 		},
-		optOut:   false,
-		birthday: timestamp(),
+		optOut: false,
 	}
 
 	type aTest struct {
@@ -332,8 +323,8 @@ func TestTrimCookiesClosestExpirationDates(t *testing.T) {
 	testCases := []aTest{
 		{maxCookieSize: 2000, expKeys: []string{"k1", "k2", "k3", "k4", "k5", "k6", "k7"}}, //1 don't trim, set
 		{maxCookieSize: 0, expKeys: []string{"k1", "k2", "k3", "k4", "k5", "k6", "k7"}},    //2 unlimited size: don't trim, set
-		{maxCookieSize: 800, expKeys: []string{"k1", "k5", "k4", "k3"}},                    //3 trim to size and set
-		{maxCookieSize: 500, expKeys: []string{"k1", "k3"}},                                //4 trim to size and set
+		{maxCookieSize: 800, expKeys: []string{"k1", "k5", "k4", "k3", "k6"}},              //3 trim to size and set
+		{maxCookieSize: 500, expKeys: []string{"k1", "k4", "k3"}},                          //4 trim to size and set
 		{maxCookieSize: 200, expKeys: []string{}},                                          //5 insufficient size, trim to zero length and set
 		{maxCookieSize: -100, expKeys: []string{}},                                         //6 invalid size, trim to zero length and set
 	}
@@ -436,8 +427,7 @@ func newSampleCookie() *Cookie {
 			"adnxs":   newTempId("123", 10),
 			"rubicon": newTempId("456", 10),
 		},
-		optOut:   false,
-		birthday: timestamp(),
+		optOut: false,
 	}
 }