Repository: prebid/prebid-server
Pull request #1893 (2021-06-17 03:20:54)

GDPR: host-level per-purpose vendor exceptions config
- Add per-purpose vendor exception host-level config
- Convert vendor exception arrays to maps on startup for fast lookup
- Create convenience method in permissions object on instantiation so we can easily iterate over purpose configs
- Activities are allowed if a vendor is listed as an exception as long as there aren't any publisher restrictions completely disallowing the vendor
- If a bidder is listed as a vendor exception for at least one enabled purpose, don't strip IDs
- Rename `PurposeDetail` config struct to `Purpose`


Patch:
diff --git a/adapters/axonix/axonix.go b/adapters/axonix/axonix.go
new file mode 100644
index 00000000..d3016235
--- /dev/null
+++ b/adapters/axonix/axonix.go
@@ -0,0 +1,116 @@
+package axonix
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+type adapter struct {
+	URI string
+}
+
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &adapter{
+		URI: config.Endpoint,
+	}
+	return bidder, nil
+}
+
+func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	var errors []error
+
+	var bidderExt adapters.ExtImpBidder
+	if err := json.Unmarshal(request.Imp[0].Ext, &bidderExt); err != nil {
+		errors = append(errors, &errortypes.BadInput{
+			Message: err.Error(),
+		})
+
+		return nil, errors
+	}
+
+	var axonixExt openrtb_ext.ExtImpAxonix
+	if err := json.Unmarshal(bidderExt.Bidder, &axonixExt); err != nil {
+		errors = append(errors, &errortypes.BadInput{
+			Message: err.Error(),
+		})
+
+		return nil, errors
+	}
+
+	thisURI := a.URI
+	if len(thisURI) == 0 {
+		thisURI = "https://openrtb-us-east-1.axonix.com/supply/prebid-server/" + axonixExt.SupplyId
+	}
+
+	requestJSON, err := json.Marshal(request)
+	if err != nil {
+		errors = append(errors, err)
+		return nil, errors
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json")
+
+	requestData := &adapters.RequestData{
+		Method:  "POST",
+		Uri:     thisURI,
+		Body:    requestJSON,
+		Headers: headers,
+	}
+
+	return []*adapters.RequestData{requestData}, nil
+}
+
+func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	if responseData.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if responseData.StatusCode != http.StatusOK {
+		err := &errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Unexpected status code: %d.", responseData.StatusCode),
+		}
+		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
+	for _, seatBid := range response.SeatBid {
+		for _, bid := range seatBid.Bid {
+			bid := bid
+			b := &adapters.TypedBid{
+				Bid:     &bid,
+				BidType: getMediaType(bid.ImpID, request.Imp),
+			}
+			bidResponse.Bids = append(bidResponse.Bids, b)
+		}
+	}
+
+	return bidResponse, nil
+}
+
+func getMediaType(impId string, imps []openrtb2.Imp) openrtb_ext.BidType {
+	for _, imp := range imps {
+		if imp.ID == impId {
+			if imp.Native != nil {
+				return openrtb_ext.BidTypeNative
+			} else if imp.Video != nil {
+				return openrtb_ext.BidTypeVideo
+			}
+			return openrtb_ext.BidTypeBanner
+		}
+	}
+	return openrtb_ext.BidTypeBanner
+}
diff --git a/adapters/bidder.go b/adapters/bidder.go
index 2e5ec83c..b7bde4bc 100644
--- a/adapters/bidder.go
+++ b/adapters/bidder.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/mxmCherry/openrtb/v15/openrtb2"
 	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/currency"
 	"github.com/prebid/prebid-server/metrics"
 	"github.com/prebid/prebid-server/openrtb_ext"
 )
@@ -138,6 +139,25 @@ func (r *RequestData) SetBasicAuth(username string, password string) {
 type ExtraRequestInfo struct {
 	PbsEntryPoint              metrics.RequestType
 	GlobalPrivacyControlHeader string
+	currencyConversions        currency.Conversions
+}
+
+func NewExtraRequestInfo(c currency.Conversions) ExtraRequestInfo {
+	return ExtraRequestInfo{
+		currencyConversions: c,
+	}
+}
+
+// ConvertCurrency converts a given amount from one currency to another, or returns:
+//  - Error if the `from` or `to` arguments are malformed or unknown ISO-4217 codes.
+//  - ConversionNotFoundError if the conversion mapping is unknown to Prebid Server
+//    and not provided in the bid request.
+func (r ExtraRequestInfo) ConvertCurrency(value float64, from, to string) (float64, error) {
+	if rate, err := r.currencyConversions.GetRate(from, to); err == nil {
+		return value * rate, nil
+	} else {
+		return 0, err
+	}
 }
 
 type Builder func(openrtb_ext.BidderName, config.Adapter) (Bidder, error)
diff --git a/adapters/bidmyadz/bidmyadz.go b/adapters/bidmyadz/bidmyadz.go
new file mode 100644
index 00000000..829d57e6
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadz.go
@@ -0,0 +1,157 @@
+package bidmyadz
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"net/http"
+)
+
+type adapter struct {
+	endpoint string
+}
+
+type bidExt struct {
+	MediaType string `json:"mediaType"`
+}
+
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &adapter{
+		endpoint: config.Endpoint,
+	}
+	return bidder, nil
+}
+
+func (a *adapter) MakeRequests(
+	openRTBRequest *openrtb2.BidRequest,
+	reqInfo *adapters.ExtraRequestInfo,
+) (
+	requestsToBidder []*adapters.RequestData,
+	errs []error,
+) {
+
+	var errors []error
+
+	if len(openRTBRequest.Imp) > 1 {
+		errors = append(errors, &errortypes.BadInput{
+			Message: "Bidder does not support multi impression",
+		})
+	}
+
+	if openRTBRequest.Device.IP == "" && openRTBRequest.Device.IPv6 == "" {
+		errors = append(errors, &errortypes.BadInput{
+			Message: "IP/IPv6 is a required field",
+		})
+	}
+
+	if openRTBRequest.Device.UA == "" {
+		errors = append(errors, &errortypes.BadInput{
+			Message: "User-Agent is a required field",
+		})
+	}
+
+	if len(errors) != 0 {
+		return nil, errors
+	}
+
+	reqJSON, err := json.Marshal(openRTBRequest)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	headers.Add("X-Openrtb-Version", "2.5")
+
+	return []*adapters.RequestData{{
+		Method:  http.MethodPost,
+		Body:    reqJSON,
+		Uri:     a.endpoint,
+		Headers: headers,
+	}}, nil
+}
+
+func (a *adapter) MakeBids(
+	openRTBRequest *openrtb2.BidRequest,
+	requestToBidder *adapters.RequestData,
+	bidderRawResponse *adapters.ResponseData,
+) (
+	bidderResponse *adapters.BidderResponse,
+	errs []error,
+) {
+	if bidderRawResponse.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if bidderRawResponse.StatusCode == http.StatusBadRequest {
+		return nil, []error{&errortypes.BadInput{
+			Message: fmt.Sprintf("Bad Request. %s", string(bidderRawResponse.Body)),
+		}}
+	}
+
+	if bidderRawResponse.StatusCode == http.StatusServiceUnavailable {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Bidder is unavailable. Please contact your account manager.",
+		}}
+	}
+
+	if bidderRawResponse.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Something went wrong. Status Code: [ %d ] %s", bidderRawResponse.StatusCode, string(bidderRawResponse.Body)),
+		}}
+	}
+
+	responseBody := bidderRawResponse.Body
+	var bidResp openrtb2.BidResponse
+	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
+		return nil, []error{err}
+	}
+
+	if len(bidResp.SeatBid) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid",
+		}}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
+
+	bids := bidResp.SeatBid[0].Bid
+
+	if len(bids) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid.Bids",
+		}}
+	}
+
+	bid := bids[0]
+
+	var bidExt bidExt
+	var bidType openrtb_ext.BidType
+
+	if err := json.Unmarshal(bid.Ext, &bidExt); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("BidExt parsing error. %s", err.Error()),
+		}}
+	}
+
+	bidType, err := getBidType(bidExt)
+
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+		Bid:     &bid,
+		BidType: bidType,
+	})
+	return bidResponse, nil
+}
+
+func getBidType(ext bidExt) (openrtb_ext.BidType, error) {
+	return openrtb_ext.ParseBidType(ext.MediaType)
+}
diff --git a/adapters/bidmyadz/usersync.go b/adapters/bidmyadz/usersync.go
new file mode 100644
index 00000000..755a184d
--- /dev/null
+++ b/adapters/bidmyadz/usersync.go
@@ -0,0 +1,12 @@
+package bidmyadz
+
+import (
+	"text/template"
+
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/usersync"
+)
+
+func NewBidmyadzSyncer(temp *template.Template) usersync.Usersyncer {
+	return adapters.NewSyncer("bidmyadz", temp, adapters.SyncTypeRedirect)
+}
diff --git a/adapters/dmx/dmx.go b/adapters/dmx/dmx.go
index 7124d229..adcec4a3 100644
--- a/adapters/dmx/dmx.go
+++ b/adapters/dmx/dmx.go
@@ -148,7 +148,7 @@ func (adapter *DmxAdapter) MakeRequests(request *openrtb2.BidRequest, req *adapt
 		}
 		if dmxReq.User.Ext != nil {
 			if err := json.Unmarshal(dmxReq.User.Ext, &userExt); err == nil {
-				if len(userExt.Eids) > 0 || (userExt.DigiTrust != nil && userExt.DigiTrust.ID != "") {
+				if len(userExt.Eids) > 0 {
 					anyHasId = true
 				}
 			}
diff --git a/adapters/inmobi/usersync.go b/adapters/inmobi/usersync.go
new file mode 100644
index 00000000..7f022e3c
--- /dev/null
+++ b/adapters/inmobi/usersync.go
@@ -0,0 +1,12 @@
+package inmobi
+
+import (
+	"text/template"
+
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/usersync"
+)
+
+func NewInmobiSyncer(template *template.Template) usersync.Usersyncer {
+	return adapters.NewSyncer("inmobi", template, adapters.SyncTypeRedirect)
+}
diff --git a/adapters/ix/ix.go b/adapters/ix/ix.go
index 5e10138f..b251ec0f 100644
--- a/adapters/ix/ix.go
+++ b/adapters/ix/ix.go
@@ -7,7 +7,10 @@ import (
 	"fmt"
 	"io/ioutil"
 	"net/http"
+	"sort"
 
+	"github.com/mxmCherry/openrtb/v15/native1"
+	native1response "github.com/mxmCherry/openrtb/v15/native1/response"
 	"github.com/mxmCherry/openrtb/v15/openrtb2"
 	"github.com/prebid/prebid-server/adapters"
 	"github.com/prebid/prebid-server/config"
@@ -400,7 +403,7 @@ func (a *IxAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalReque
 		for _, bid := range seatBid.Bid {
 			bidType, ok := impMediaType[bid.ImpID]
 			if !ok {
-				errs = append(errs, fmt.Errorf("Unmatched impression id: %s.", bid.ImpID))
+				errs = append(errs, fmt.Errorf("unmatched impression id: %s", bid.ImpID))
 			}
 
 			var bidExtVideo *openrtb_ext.ExtBidPrebidVideo
@@ -417,6 +420,28 @@ func (a *IxAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalReque
 				}
 			}
 
+			var bidNative1v1 *Native11Wrapper
+			if bidType == openrtb_ext.BidTypeNative {
+				err := json.Unmarshal([]byte(bid.AdM), &bidNative1v1)
+				if err == nil && len(bidNative1v1.Native.EventTrackers) > 0 {
+					mergeNativeImpTrackers(&bidNative1v1.Native)
+					if json, err := json.Marshal(bidNative1v1); err == nil {
+						bid.AdM = string(json)
+					}
+				}
+			}
+
+			var bidNative1v2 *native1response.Response
+			if bidType == openrtb_ext.BidTypeNative {
+				err := json.Unmarshal([]byte(bid.AdM), &bidNative1v2)
+				if err == nil && len(bidNative1v2.EventTrackers) > 0 {
+					mergeNativeImpTrackers(bidNative1v2)
+					if json, err := json.Marshal(bidNative1v2); err == nil {
+						bid.AdM = string(json)
+					}
+				}
+			}
+
 			bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{
 				Bid:      &bid,
 				BidType:  bidType,
@@ -444,3 +469,33 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters
 	}
 	return bidder, nil
 }
+
+// native 1.2 to 1.1 tracker compatibility handling
+
+type Native11Wrapper struct {
+	Native native1response.Response `json:"native,omitempty"`
+}
+
+func mergeNativeImpTrackers(bidNative *native1response.Response) {
+
+	// create unique list of imp pixels urls from `imptrackers` and `eventtrackers`
+	uniqueImpPixels := map[string]struct{}{}
+	for _, v := range bidNative.ImpTrackers {
+		uniqueImpPixels[v] = struct{}{}
+	}
+
+	for _, v := range bidNative.EventTrackers {
+		if v.Event == native1.EventTypeImpression && v.Method == native1.EventTrackingMethodImage {
+			uniqueImpPixels[v.URL] = struct{}{}
+		}
+	}
+
+	// rewrite `imptrackers` with new deduped list of imp pixels
+	bidNative.ImpTrackers = make([]string, 0)
+	for k := range uniqueImpPixels {
+		bidNative.ImpTrackers = append(bidNative.ImpTrackers, k)
+	}
+
+	// sort so tests pass correctly
+	sort.Strings(bidNative.ImpTrackers)
+}
diff --git a/adapters/outbrain/outbrain.go b/adapters/outbrain/outbrain.go
index 282a6d53..6b121cb4 100644
--- a/adapters/outbrain/outbrain.go
+++ b/adapters/outbrain/outbrain.go
@@ -43,8 +43,10 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte
 			errs = append(errs, err)
 			continue
 		}
-		imp.TagID = outbrainExt.TagId
-		reqCopy.Imp[i] = imp
+		if outbrainExt.TagId != "" {
+			imp.TagID = outbrainExt.TagId
+			reqCopy.Imp[i] = imp
+		}
 	}
 
 	publisher := &openrtb2.Publisher{
diff --git a/adapters/rubicon/rubicon.go b/adapters/rubicon/rubicon.go
index 89d69522..84200431 100644
--- a/adapters/rubicon/rubicon.go
+++ b/adapters/rubicon/rubicon.go
@@ -91,21 +91,21 @@ type rubiconExtUserTpID struct {
 	UID    string `json:"uid"`
 }
 
-type rubiconUserDataExt struct {
-	TaxonomyName string `json:"taxonomyname"`
+type rubiconDataExt struct {
+	SegTax int `json:"segtax"`
 }
 
 type rubiconUserExt struct {
-	Consent     string                        `json:"consent,omitempty"`
-	DigiTrust   *openrtb_ext.ExtUserDigiTrust `json:"digitrust"`
-	Eids        []openrtb_ext.ExtUserEid      `json:"eids,omitempty"`
-	TpID        []rubiconExtUserTpID          `json:"tpid,omitempty"`
-	RP          rubiconUserExtRP              `json:"rp"`
-	LiverampIdl string                        `json:"liveramp_idl,omitempty"`
+	Consent     string                   `json:"consent,omitempty"`
+	Eids        []openrtb_ext.ExtUserEid `json:"eids,omitempty"`
+	TpID        []rubiconExtUserTpID     `json:"tpid,omitempty"`
+	RP          rubiconUserExtRP         `json:"rp"`
+	LiverampIdl string                   `json:"liveramp_idl,omitempty"`
 }
 
 type rubiconSiteExtRP struct {
-	SiteID int `json:"site_id"`
+	SiteID int             `json:"site_id"`
+	Target json.RawMessage `json:"target,omitempty"`
 }
 
 type rubiconSiteExt struct {
@@ -750,14 +750,19 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 			continue
 		}
 
+		resolvedBidFloor, resolvedBidFloorCur := resolveBidFloorAttributes(thisImp.BidFloor, thisImp.BidFloorCur)
+		thisImp.BidFloorCur = resolvedBidFloorCur
+		thisImp.BidFloor = resolvedBidFloor
+
 		if request.User != nil {
 			userCopy := *request.User
-			userExtRP := rubiconUserExt{RP: rubiconUserExtRP{Target: rubiconExt.Visitor}}
 
-			if err := updateUserExtWithIabAttribute(&userExtRP, userCopy.Data); err != nil {
+			target, err := updateExtWithIabAttribute(rubiconExt.Visitor, userCopy.Data, []int{4})
+			if err != nil {
 				errs = append(errs, err)
 				continue
 			}
+			userExtRP := rubiconUserExt{RP: rubiconUserExtRP{Target: target}}
 
 			if request.User.Ext != nil {
 				var userExt *openrtb_ext.ExtUser
@@ -768,9 +773,6 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 					continue
 				}
 				userExtRP.Consent = userExt.Consent
-				if userExt.DigiTrust != nil {
-					userExtRP.DigiTrust = userExt.DigiTrust
-				}
 				userExtRP.Eids = userExt.Eids
 
 				// set user.ext.tpid
@@ -845,19 +847,32 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 			thisImp.Video = nil
 		}
 
-		siteExt := rubiconSiteExt{RP: rubiconSiteExtRP{SiteID: rubiconExt.SiteId}}
 		pubExt := rubiconPubExt{RP: rubiconPubExtRP{AccountID: rubiconExt.AccountId}}
 
 		if request.Site != nil {
 			siteCopy := *request.Site
-			siteCopy.Ext, err = json.Marshal(&siteExt)
+			siteExtRP := rubiconSiteExt{RP: rubiconSiteExtRP{SiteID: rubiconExt.SiteId}}
+			if siteCopy.Content != nil {
+				target, err := updateExtWithIabAttribute(nil, siteCopy.Content.Data, []int{1, 2})
+				if err != nil {
+					errs = append(errs, err)
+					continue
+				}
+				siteExtRP.RP.Target = target
+			}
+
+			siteCopy.Ext, err = json.Marshal(&siteExtRP)
+			if err != nil {
+				errs = append(errs, err)
+				continue
+			}
+
 			siteCopy.Publisher = &openrtb2.Publisher{}
 			siteCopy.Publisher.Ext, err = json.Marshal(&pubExt)
 			rubiconRequest.Site = &siteCopy
-		}
-		if request.App != nil {
+		} else {
 			appCopy := *request.App
-			appCopy.Ext, err = json.Marshal(&siteExt)
+			appCopy.Ext, err = json.Marshal(rubiconSiteExt{RP: rubiconSiteExtRP{SiteID: rubiconExt.SiteId}})
 			appCopy.Publisher = &openrtb2.Publisher{}
 			appCopy.Publisher.Ext, err = json.Marshal(&pubExt)
 			rubiconRequest.App = &appCopy
@@ -893,41 +908,67 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 	return requestData, errs
 }
 
-func updateUserExtWithIabAttribute(userExtRP *rubiconUserExt, data []openrtb2.Data) error {
-	var segmentIdsToCopy = make([]string, 0)
+// Will be replaced after https://github.com/prebid/prebid-server/issues/1482 resolution
+func resolveBidFloorAttributes(bidFloor float64, bidFloorCur string) (float64, string) {
+	if bidFloor > 0 {
+		if strings.ToUpper(bidFloorCur) == "EUR" {
+			return bidFloor * 1.2, "USD"
+		}
+	}
+
+	return bidFloor, bidFloorCur
+}
+
+func updateExtWithIabAttribute(target json.RawMessage, data []openrtb2.Data, segTaxes []int) (json.RawMessage, error) {
+	var segmentIdsToCopy = getSegmentIdsToCopy(data, segTaxes)
+	if len(segmentIdsToCopy) == 0 {
+		return target, nil
+	}
+
+	extRPTarget := make(map[string]interface{})
+
+	if target != nil {
+		if err := json.Unmarshal(target, &extRPTarget); err != nil {
+			return nil, &errortypes.BadInput{Message: err.Error()}
+		}
+	}
+
+	extRPTarget["iab"] = segmentIdsToCopy
+
+	jsonTarget, err := json.Marshal(&extRPTarget)
+	if err != nil {
+		return nil, &errortypes.BadInput{Message: err.Error()}
+	}
+	return jsonTarget, nil
+}
+
+func getSegmentIdsToCopy(data []openrtb2.Data, segTaxValues []int) []string {
+	var segmentIdsToCopy = make([]string, 0, len(data))
 
 	for _, dataRecord := range data {
 		if dataRecord.Ext != nil {
-			var dataExtObject rubiconUserDataExt
+			var dataExtObject rubiconDataExt
 			err := json.Unmarshal(dataRecord.Ext, &dataExtObject)
 			if err != nil {
 				continue
 			}
-			if strings.EqualFold(dataExtObject.TaxonomyName, "iab") {
+			if contains(segTaxValues, dataExtObject.SegTax) {
 				for _, segment := range dataRecord.Segment {
 					segmentIdsToCopy = append(segmentIdsToCopy, segment.ID)
 				}
 			}
 		}
 	}
+	return segmentIdsToCopy
+}
 
-	userExtRPTarget := make(map[string]interface{})
-
-	if userExtRP.RP.Target != nil {
-		if err := json.Unmarshal(userExtRP.RP.Target, &userExtRPTarget); err != nil {
-			return &errortypes.BadInput{Message: err.Error()}
+func contains(s []int, e int) bool {
+	for _, a := range s {
+		if a == e {
+			return true
 		}
 	}
-
-	userExtRPTarget["iab"] = segmentIdsToCopy
-
-	if target, err := json.Marshal(&userExtRPTarget); err != nil {
-		return &errortypes.BadInput{Message: err.Error()}
-	} else {
-		userExtRP.RP.Target = target
-	}
-
-	return nil
+	return false
 }
 
 func getTpIdsAndSegments(eids []openrtb_ext.ExtUserEid) (mappedRubiconUidsParam, []error) {
diff --git a/adapters/sa_lunamedia/salunamedia.go b/adapters/sa_lunamedia/salunamedia.go
new file mode 100644
index 00000000..ea6e12b0
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamedia.go
@@ -0,0 +1,132 @@
+package salunamedia
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"net/http"
+)
+
+type adapter struct {
+	endpoint string
+}
+
+type bidExt struct {
+	MediaType string `json:"mediaType"`
+}
+
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &adapter{
+		endpoint: config.Endpoint,
+	}
+	return bidder, nil
+}
+
+func (a *adapter) MakeRequests(
+	openRTBRequest *openrtb2.BidRequest,
+	reqInfo *adapters.ExtraRequestInfo,
+) (
+	requestsToBidder []*adapters.RequestData,
+	errs []error,
+) {
+
+	reqJSON, err := json.Marshal(openRTBRequest)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+
+	return []*adapters.RequestData{{
+		Method:  http.MethodPost,
+		Body:    reqJSON,
+		Uri:     a.endpoint,
+		Headers: headers,
+	}}, nil
+}
+
+func (a *adapter) MakeBids(
+	openRTBRequest *openrtb2.BidRequest,
+	requestToBidder *adapters.RequestData,
+	bidderRawResponse *adapters.ResponseData,
+) (
+	bidderResponse *adapters.BidderResponse,
+	errs []error,
+) {
+	if bidderRawResponse.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if bidderRawResponse.StatusCode == http.StatusBadRequest {
+		return nil, []error{&errortypes.BadInput{
+			Message: fmt.Sprintf("Bad Request. %s", string(bidderRawResponse.Body)),
+		}}
+	}
+
+	if bidderRawResponse.StatusCode == http.StatusServiceUnavailable {
+		return nil, []error{&errortypes.BadInput{
+			Message: "Bidder unavailable. Please contact the bidder support.",
+		}}
+	}
+
+	if bidderRawResponse.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Status Code: [ %d ] %s", bidderRawResponse.StatusCode, string(bidderRawResponse.Body)),
+		}}
+	}
+
+	responseBody := bidderRawResponse.Body
+	var bidResp openrtb2.BidResponse
+	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
+		return nil, []error{err}
+	}
+
+	if len(bidResp.SeatBid) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid",
+		}}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
+
+	bids := bidResp.SeatBid[0].Bid
+
+	if len(bids) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid.Bids",
+		}}
+	}
+
+	bid := bids[0]
+
+	var bidExt bidExt
+	var bidType openrtb_ext.BidType
+
+	if err := json.Unmarshal(bid.Ext, &bidExt); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Missing BidExt",
+		}}
+	}
+
+	bidType, err := getBidType(bidExt)
+
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+		Bid:     &bid,
+		BidType: bidType,
+	})
+	return bidResponse, nil
+}
+
+func getBidType(ext bidExt) (openrtb_ext.BidType, error) {
+	return openrtb_ext.ParseBidType(ext.MediaType)
+}
diff --git a/adapters/sa_lunamedia/usersync.go b/adapters/sa_lunamedia/usersync.go
new file mode 100644
index 00000000..f78b7944
--- /dev/null
+++ b/adapters/sa_lunamedia/usersync.go
@@ -0,0 +1,12 @@
+package salunamedia
+
+import (
+	"text/template"
+
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/usersync"
+)
+
+func NewSaLunamediaSyncer(temp *template.Template) usersync.Usersyncer {
+	return adapters.NewSyncer("salunamedia", temp, adapters.SyncTypeRedirect)
+}
diff --git a/config/config.go b/config/config.go
index 58bb40a5..96e3c1f1 100644
--- a/config/config.go
+++ b/config/config.go
@@ -240,20 +240,30 @@ func (t *GDPRTimeouts) ActiveTimeout() time.Duration {
 
 // TCF2 defines the TCF2 specific configurations for GDPR
 type TCF2 struct {
-	Enabled             bool                `mapstructure:"enabled"`
-	Purpose1            PurposeDetail       `mapstructure:"purpose1"`
-	Purpose2            PurposeDetail       `mapstructure:"purpose2"`
-	Purpose7            PurposeDetail       `mapstructure:"purpose7"`
-	SpecialPurpose1     PurposeDetail       `mapstructure:"special_purpose1"`
-	PurposeOneTreatment PurposeOneTreatment `mapstructure:"purpose_one_treatment"`
+	Enabled             bool                    `mapstructure:"enabled"`
+	Purpose1            TCF2Purpose             `mapstructure:"purpose1"`
+	Purpose2            TCF2Purpose             `mapstructure:"purpose2"`
+	Purpose3            TCF2Purpose             `mapstructure:"purpose3"`
+	Purpose4            TCF2Purpose             `mapstructure:"purpose4"`
+	Purpose5            TCF2Purpose             `mapstructure:"purpose5"`
+	Purpose6            TCF2Purpose             `mapstructure:"purpose6"`
+	Purpose7            TCF2Purpose             `mapstructure:"purpose7"`
+	Purpose8            TCF2Purpose             `mapstructure:"purpose8"`
+	Purpose9            TCF2Purpose             `mapstructure:"purpose9"`
+	Purpose10           TCF2Purpose             `mapstructure:"purpose10"`
+	SpecialPurpose1     TCF2Purpose             `mapstructure:"special_purpose1"`
+	PurposeOneTreatment TCF2PurposeOneTreatment `mapstructure:"purpose_one_treatment"`
 }
 
 // Making a purpose struct so purpose specific details can be added later.
-type PurposeDetail struct {
+type TCF2Purpose struct {
 	Enabled bool `mapstructure:"enabled"`
+	// Array of vendor exceptions that is used to create the hash table VendorExceptionMap so vendor names can be instantly accessed
+	VendorExceptions   []openrtb_ext.BidderName `mapstructure:"vendor_exceptions"`
+	VendorExceptionMap map[openrtb_ext.BidderName]struct{}
 }
 
-type PurposeOneTreatment struct {
+type TCF2PurposeOneTreatment struct {
 	Enabled       bool `mapstructure:"enabled"`
 	AccessAllowed bool `mapstructure:"access_allowed"`
 }
@@ -503,6 +513,30 @@ func New(v *viper.Viper) (*Configuration, error) {
 		c.GDPR.NonStandardPublisherMap[c.GDPR.EEACountries[i]] = s
 	}
 
+	// To look for a purpose's vendor exceptions in O(1) time, for each purpose we fill this hash table located in the
+	// VendorExceptions field of the GDPR.TCF2.PurposeX struct defined in this file
+	purposeConfigs := []*TCF2Purpose{
+		&c.GDPR.TCF2.Purpose1,
+		&c.GDPR.TCF2.Purpose2,
+		&c.GDPR.TCF2.Purpose3,
+		&c.GDPR.TCF2.Purpose4,
+		&c.GDPR.TCF2.Purpose5,
+		&c.GDPR.TCF2.Purpose6,
+		&c.GDPR.TCF2.Purpose7,
+		&c.GDPR.TCF2.Purpose8,
+		&c.GDPR.TCF2.Purpose9,
+		&c.GDPR.TCF2.Purpose10,
+		&c.GDPR.TCF2.SpecialPurpose1,
+	}
+	for c := 0; c < len(purposeConfigs); c++ {
+		purposeConfigs[c].VendorExceptionMap = make(map[openrtb_ext.BidderName]struct{})
+
+		for v := 0; v < len(purposeConfigs[c].VendorExceptions); v++ {
+			bidderName := purposeConfigs[c].VendorExceptions[v]
+			purposeConfigs[c].VendorExceptionMap[bidderName] = struct{}{}
+		}
+	}
+
 	// To look for a request's app_id in O(1) time, we fill this hash table located in the
 	// the BlacklistedApps field of the Configuration struct defined in this file
 	c.BlacklistedAppMap = make(map[string]bool)
@@ -587,6 +621,7 @@ func (cfg *Configuration) setDerivedDefaults() {
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAvocet, "https://ads.avct.cloud/getuid?&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Davocet%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7B%7BUUID%7D%7D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeachfront, "https://sync.bfmio.com/sync_s2s?gdpr={{.GDPR}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeachfront%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5Bio_cid%5D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeintoo, "https://ib.beintoo.com/um?ssp=pbs&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeintoo%26uid%3D%24UID")
+	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBidmyadz, "https://cookie-sync.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&red="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbidmyadz%26uid%3D%5BUID%5D%26us_privacy%3D{{.USPrivacy}}%26gdpr_consent%3D{{.GDPRConsent}}%26gdpr%3D{{.GDPR}}")
 	// openrtb_ext.BidderBidsCube doesn't have a good default.
 	// openrtb_ext.BidderBmtm doesn't have a good default.
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBrightroll, "https://pr-bh.ybp.yahoo.com/sync/appnexusprebidserver/?gdpr={{.GDPR}}&euconsent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbrightroll%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
@@ -610,6 +645,7 @@ func (cfg *Configuration) setDerivedDefaults() {
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderGrid, "https://x.bidswitch.net/check_uuid/"+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dgrid%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BBSW_UUID%7D?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderGumGum, "https://rtb.gumgum.com/usync/prbds2s?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&r="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dgumgum%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderImprovedigital, "https://ad.360yield.com/server_match?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&r="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dimprovedigital%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7BPUB_USER_ID%7D")
+	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderInMobi, "https://id5-sync.com/i/495/0.gif?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&callback="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dinmobi%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7BID5UID%7D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderIx, "https://ssum.casalemedia.com/usermatchredir?s=194962&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&cb="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dix%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D")
 	// openrtb_ext.BidderInvibes doesn't have a good default.
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderJixie, "https://id.jixie.io/api/sync?pid=&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Djixie%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%25%25JXUID%25%25")
@@ -617,6 +653,7 @@ func (cfg *Configuration) setDerivedDefaults() {
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderLockerDome, "https://lockerdome.com/usync/prebidserver?pid="+cfg.Adapters["lockerdome"].PlatformID+"&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dlockerdome%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7B%7Buid%7D%7D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderLogicad, "https://cr-p31.ladsp.jp/cookiesender/31?r=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ru="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dlogicad%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderLunaMedia, "https://api.lunamedia.io/xp/user-sync?redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dlunamedia%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
+	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSaLunaMedia, "https://cookie.lmgssp.com/pserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsa_lunamedia%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5BUID%5D")
 	// openrtb_ext.BidderMadvertise doesn't have a good default.
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderMarsmedia, "https://dmp.rtbsrv.com/dmp/profiles/cm?p_id=179&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dmarsmedia%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUUID%7D")
 	// openrtb_ext.BidderMediafuse doesn't have a good default.
@@ -837,11 +874,13 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.audiencenetwork.disabled", true)
 	v.SetDefault("adapters.audiencenetwork.endpoint", "https://an.facebook.com/placementbid.ortb")
 	v.SetDefault("adapters.avocet.disabled", true)
+	v.SetDefault("adapters.axonix.disabled", true)
 	v.SetDefault("adapters.beachfront.endpoint", "https://display.bfmio.com/prebid_display")
 	v.SetDefault("adapters.beachfront.extra_info", "{\"video_endpoint\":\"https://reachms.bfmio.com/bid.json?exchange_id\"}")
 	v.SetDefault("adapters.beintoo.endpoint", "https://ib.beintoo.com/um")
 	v.SetDefault("adapters.between.endpoint", "http://{{.Host}}.betweendigital.com/openrtb_bid?sspId={{.PublisherID}}")
 	v.SetDefault("adapters.bidmachine.endpoint", "https://{{.Host}}.bidmachine.io")
+	v.SetDefault("adapters.bidmyadz.endpoint", "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc")
 	v.SetDefault("adapters.bidscube.endpoint", "http://supply.bidscube.com/?c=o&m=rtb")
 	v.SetDefault("adapters.bmtm.endpoint", "https://one.elitebidder.com/api/pbs")
 	v.SetDefault("adapters.brightroll.endpoint", "http://east-bid.ybp.yahoo.com/bid/appnexuspbs")
@@ -878,6 +917,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.lockerdome.endpoint", "https://lockerdome.com/ladbid/prebidserver/openrtb2")
 	v.SetDefault("adapters.logicad.endpoint", "https://pbs.ladsp.com/adrequest/prebidserver")
 	v.SetDefault("adapters.lunamedia.endpoint", "http://api.lunamedia.io/xp/get?pubid={{.PublisherID}}")
+	v.SetDefault("adapters.sa_lunamedia.endpoint", "http://balancer.lmgssp.com/pserver")
 	v.SetDefault("adapters.madvertise.endpoint", "https://mobile.mng-ads.com/bidrequest{{.ZoneID}}")
 	v.SetDefault("adapters.marsmedia.endpoint", "https://bid306.rtbsrv.com/bidder/?bid=f3xtet")
 	v.SetDefault("adapters.mediafuse.endpoint", "http://ghb.hbmp.mediafuse.com/pbs/ortb")
@@ -951,9 +991,26 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("gdpr.tcf2.enabled", true)
 	v.SetDefault("gdpr.tcf2.purpose1.enabled", true)
 	v.SetDefault("gdpr.tcf2.purpose2.enabled", true)
+	v.SetDefault("gdpr.tcf2.purpose3.enabled", true)
 	v.SetDefault("gdpr.tcf2.purpose4.enabled", true)
+	v.SetDefault("gdpr.tcf2.purpose5.enabled", true)
+	v.SetDefault("gdpr.tcf2.purpose6.enabled", true)
 	v.SetDefault("gdpr.tcf2.purpose7.enabled", true)
+	v.SetDefault("gdpr.tcf2.purpose8.enabled", true)
+	v.SetDefault("gdpr.tcf2.purpose9.enabled", true)
+	v.SetDefault("gdpr.tcf2.purpose10.enabled", true)
+	v.SetDefault("gdpr.tcf2.purpose1.vendor_exceptions", []openrtb_ext.BidderName{})
+	v.SetDefault("gdpr.tcf2.purpose2.vendor_exceptions", []openrtb_ext.BidderName{})
+	v.SetDefault("gdpr.tcf2.purpose3.vendor_exceptions", []openrtb_ext.BidderName{})
+	v.SetDefault("gdpr.tcf2.purpose4.vendor_exceptions", []openrtb_ext.BidderName{})
+	v.SetDefault("gdpr.tcf2.purpose5.vendor_exceptions", []openrtb_ext.BidderName{})
+	v.SetDefault("gdpr.tcf2.purpose6.vendor_exceptions", []openrtb_ext.BidderName{})
+	v.SetDefault("gdpr.tcf2.purpose7.vendor_exceptions", []openrtb_ext.BidderName{})
+	v.SetDefault("gdpr.tcf2.purpose8.vendor_exceptions", []openrtb_ext.BidderName{})
+	v.SetDefault("gdpr.tcf2.purpose9.vendor_exceptions", []openrtb_ext.BidderName{})
+	v.SetDefault("gdpr.tcf2.purpose10.vendor_exceptions", []openrtb_ext.BidderName{})
 	v.SetDefault("gdpr.tcf2.special_purpose1.enabled", true)
+	v.SetDefault("gdpr.tcf2.special_purpose1.vendor_exceptions", []openrtb_ext.BidderName{})
 	v.SetDefault("gdpr.amp_exception", false)
 	v.SetDefault("gdpr.eea_countries", []string{"ALA", "AUT", "BEL", "BGR", "HRV", "CYP", "CZE", "DNK", "EST",
 		"FIN", "FRA", "GUF", "DEU", "GIB", "GRC", "GLP", "GGY", "HUN", "ISL", "IRL", "IMN", "ITA", "JEY", "LVA",
diff --git a/currency/aggregate_conversions.go b/currency/aggregate_conversions.go
index 53c5ebff..a15404fe 100644
--- a/currency/aggregate_conversions.go
+++ b/currency/aggregate_conversions.go
@@ -23,7 +23,7 @@ func (re *AggregateConversions) GetRate(from string, to string) (float64, error)
 	rate, err := re.customRates.GetRate(from, to)
 	if err == nil {
 		return rate, nil
-	} else if _, isMissingRateErr := err.(ConversionRateNotFound); !isMissingRateErr {
+	} else if _, isMissingRateErr := err.(ConversionNotFoundError); !isMissingRateErr {
 		// other error, return the error
 		return 0, err
 	}
diff --git a/currency/constant_rates.go b/currency/constant_rates.go
index dde317d8..ccc5c24d 100644
--- a/currency/constant_rates.go
+++ b/currency/constant_rates.go
@@ -27,7 +27,7 @@ func (r *ConstantRates) GetRate(from string, to string) (float64, error) {
 	}
 
 	if fromUnit.String() != toUnit.String() {
-		return 0, ConversionRateNotFound{fromUnit.String(), toUnit.String()}
+		return 0, ConversionNotFoundError{FromCur: fromUnit.String(), ToCur: toUnit.String()}
 	}
 
 	return 1, nil
diff --git a/currency/errors.go b/currency/errors.go
index d764c15b..bb4c42aa 100644
--- a/currency/errors.go
+++ b/currency/errors.go
@@ -2,12 +2,12 @@ package currency
 
 import "fmt"
 
-// ConversionRateNotFound is thrown by the currency.Conversions GetRate(from string, to string) method
+// ConversionNotFoundError is thrown by the currency.Conversions GetRate(from string, to string) method
 // when the conversion rate between the two currencies, nor its reciprocal, can be found.
-type ConversionRateNotFound struct {
+type ConversionNotFoundError struct {
 	FromCur, ToCur string
 }
 
-func (err ConversionRateNotFound) Error() string {
+func (err ConversionNotFoundError) Error() string {
 	return fmt.Sprintf("Currency conversion rate not found: '%s' => '%s'", err.FromCur, err.ToCur)
 }
diff --git a/currency/rates.go b/currency/rates.go
index 62914c4b..b9cb0201 100644
--- a/currency/rates.go
+++ b/currency/rates.go
@@ -47,9 +47,9 @@ func (r *Rates) UnmarshalJSON(b []byte) error {
 // GetRate returns the conversion rate between two currencies or:
 //  - An error if one of the currency strings is not well-formed
 //  - An error if any of the currency strings is not a recognized currency code.
-//  - A MissingConversionRate error in case the conversion rate between the two
+//  - A ConversionNotFoundError in case the conversion rate between the two
 //    given currencies is not in the currencies rates map
-func (r *Rates) GetRate(from string, to string) (float64, error) {
+func (r *Rates) GetRate(from, to string) (float64, error) {
 	var err error
 	fromUnit, err := currency.ParseISO(from)
 	if err != nil {
@@ -70,7 +70,7 @@ func (r *Rates) GetRate(from string, to string) (float64, error) {
 			// In case we have an entry TO -> FROM
 			return 1 / conversion, nil
 		}
-		return 0, ConversionRateNotFound{fromUnit.String(), toUnit.String()}
+		return 0, ConversionNotFoundError{FromCur: fromUnit.String(), ToCur: toUnit.String()}
 	}
 	return 0, errors.New("rates are nil")
 }
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index d8a7fa68..c9f2bbdb 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -1124,13 +1124,9 @@ func (deps *endpointDeps) validateUser(user *openrtb2.User, aliases map[string]s
 	}
 
 	if user.Ext != nil {
-		// Creating ExtUser object to check if DigiTrust is valid
+		// Creating ExtUser object
 		var userExt openrtb_ext.ExtUser
 		if err := json.Unmarshal(user.Ext, &userExt); err == nil {
-			if userExt.DigiTrust != nil && userExt.DigiTrust.Pref != 0 {
-				// DigiTrust is not valid. Return error.
-				return errors.New("request.user contains a digitrust object that is not valid.")
-			}
 			// Check if the buyeruids are valid
 			if userExt.Prebid != nil {
 				if len(userExt.Prebid.BuyerUIDs) < 1 {
diff --git a/endpoints/openrtb2/sample-requests/invalid-whole/digitrust.json b/endpoints/openrtb2/sample-requests/invalid-whole/digitrust.json
deleted file mode 100644
index 1fb7169f..00000000
--- a/endpoints/openrtb2/sample-requests/invalid-whole/digitrust.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
-  "description": "Invalid digitrust object in user extension",
-  "mockBidRequest": {
-    "id": "request-with-invalid-digitrust-obj",
-    "site": {
-      "page": "test.somepage.com"
-    },
-    "imp": [
-      {
-        "id": "my-imp-id",
-        "banner": {
-          "format": [
-            {
-              "w": 300,
-              "h": 600
-            }
-          ]
-        },
-        "pmp": {
-          "deals": [
-            {
-              "id": "some-deal-id"
-            }
-          ]
-        },
-        "ext": {
-          "appnexus": {
-            "placementId": 12883451
-          }
-        }
-      }
-    ],
-    "user": {
-      "yob": 1989,
-      "ext": {
-        "digitrust": {
-          "id": "sample-digitrust-id",
-          "keyv": 1,
-          "pref": 1
-        }
-      }
-    }
-  },
-  "expectedReturnCode": 400,
-  "expectedErrorMessage": "Invalid request: request.user contains a digitrust object that is not valid.\n"
-}
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/supplementary/digitrust.json b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/digitrust.json
deleted file mode 100644
index 5cd07074..00000000
--- a/endpoints/openrtb2/sample-requests/valid-whole/supplementary/digitrust.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-  "description": "Well formed amp request with digitrust extension that should run properly",
-  "mockBidRequest": {
-    "id": "request-with-valid-digitrust-obj",
-    "site": {
-      "page": "test.somepage.com"
-    },
-    "imp": [
-      {
-        "id": "my-imp-id",
-        "banner": {
-          "format": [
-            {
-              "w": 300,
-              "h": 600
-            }
-          ]
-        },
-        "pmp": {
-          "deals": [
-            {
-              "id": "some-deal-id"
-            }
-          ]
-        },
-        "ext": {
-          "appnexus": {
-            "placementId": 12883451
-          }
-        }
-      }
-    ],
-    "user": {
-      "yob": 1989,
-      "ext": {
-        "digitrust": {
-          "id": "sample-digitrust-id",
-          "keyv": 1,
-          "pref": 0
-        }
-      }
-    }
-  },
-  "expectedBidResponse": {
-      "id":"request-with-valid-digitrust-obj",
-      "bidid":"test bid id",
-      "nbr":0
-  },
-  "expectedReturnCode": 200
-}
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 1fdb7c24..9adc9ebc 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -29,10 +29,12 @@ import (
 	"github.com/prebid/prebid-server/adapters/appnexus"
 	"github.com/prebid/prebid-server/adapters/audienceNetwork"
 	"github.com/prebid/prebid-server/adapters/avocet"
+	"github.com/prebid/prebid-server/adapters/axonix"
 	"github.com/prebid/prebid-server/adapters/beachfront"
 	"github.com/prebid/prebid-server/adapters/beintoo"
 	"github.com/prebid/prebid-server/adapters/between"
 	"github.com/prebid/prebid-server/adapters/bidmachine"
+	"github.com/prebid/prebid-server/adapters/bidmyadz"
 	"github.com/prebid/prebid-server/adapters/bidscube"
 	"github.com/prebid/prebid-server/adapters/bmtm"
 	"github.com/prebid/prebid-server/adapters/brightroll"
@@ -88,6 +90,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/rhythmone"
 	"github.com/prebid/prebid-server/adapters/rtbhouse"
 	"github.com/prebid/prebid-server/adapters/rubicon"
+	"github.com/prebid/prebid-server/adapters/sa_lunamedia"
 	"github.com/prebid/prebid-server/adapters/sharethrough"
 	"github.com/prebid/prebid-server/adapters/silvermob"
 	"github.com/prebid/prebid-server/adapters/smaato"
@@ -150,10 +153,12 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderAppnexus:          appnexus.Builder,
 		openrtb_ext.BidderAudienceNetwork:   audienceNetwork.Builder,
 		openrtb_ext.BidderAvocet:            avocet.Builder,
+		openrtb_ext.BidderAxonix:            axonix.Builder,
 		openrtb_ext.BidderBeachfront:        beachfront.Builder,
 		openrtb_ext.BidderBeintoo:           beintoo.Builder,
 		openrtb_ext.BidderBetween:           between.Builder,
 		openrtb_ext.BidderBidmachine:        bidmachine.Builder,
+		openrtb_ext.BidderBidmyadz:          bidmyadz.Builder,
 		openrtb_ext.BidderBidsCube:          bidscube.Builder,
 		openrtb_ext.BidderBmtm:              bmtm.Builder,
 		openrtb_ext.BidderBrightroll:        brightroll.Builder,
@@ -189,6 +194,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderLockerDome:        lockerdome.Builder,
 		openrtb_ext.BidderLogicad:           logicad.Builder,
 		openrtb_ext.BidderLunaMedia:         lunamedia.Builder,
+		openrtb_ext.BidderSaLunaMedia:       salunamedia.Builder,
 		openrtb_ext.BidderMadvertise:        madvertise.Builder,
 		openrtb_ext.BidderMarsmedia:         marsmedia.Builder,
 		openrtb_ext.BidderMediafuse:         adtelligent.Builder,
diff --git a/exchange/exchange.go b/exchange/exchange.go
index e96aadbc..6aaafcd1 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -449,7 +449,7 @@ func (e *exchange) getAllBids(
 			if givenAdjustment, ok := bidAdjustments[string(bidderRequest.BidderName)]; ok {
 				adjustmentFactor = givenAdjustment
 			}
-			var reqInfo adapters.ExtraRequestInfo
+			reqInfo := adapters.NewExtraRequestInfo(conversions)
 			reqInfo.PbsEntryPoint = bidderRequest.BidderLabels.RType
 			reqInfo.GlobalPrivacyControlHeader = globalPrivacyControlHeader
 			bids, err := e.adapterMap[bidderRequest.BidderCoreName].requestBid(ctx, bidderRequest.BidRequest, bidderRequest.BidderName, adjustmentFactor, conversions, &reqInfo, accountDebugAllowed, headerDebugAllowed)
diff --git a/exchange/utils.go b/exchange/utils.go
index 3def0425..0befeacd 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -332,7 +332,7 @@ func extractBuyerUIDs(user *openrtb2.User) (map[string]string, error) {
 	userExt.Prebid = nil
 
 	// Remarshal (instead of removing) if the ext has other known fields
-	if userExt.Consent != "" || userExt.DigiTrust != nil || len(userExt.Eids) > 0 {
+	if userExt.Consent != "" || len(userExt.Eids) > 0 {
 		if newUserExtBytes, err := json.Marshal(userExt); err != nil {
 			return nil, err
 		} else {
diff --git a/gdpr/gdpr.go b/gdpr/gdpr.go
index 47d20a50..d2d282b2 100644
--- a/gdpr/gdpr.go
+++ b/gdpr/gdpr.go
@@ -5,6 +5,7 @@ import (
 	"net/http"
 	"strconv"
 
+	"github.com/prebid/go-gdpr/consentconstants"
 	"github.com/prebid/go-gdpr/vendorlist"
 	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/errortypes"
@@ -44,9 +45,23 @@ func NewPermissions(ctx context.Context, cfg config.GDPR, vendorIDs map[openrtb_
 		gdprDefaultValue = SignalNo
 	}
 
+	purposeConfigs := map[consentconstants.Purpose]config.TCF2Purpose{
+		1:  cfg.TCF2.Purpose1,
+		2:  cfg.TCF2.Purpose2,
+		3:  cfg.TCF2.Purpose3,
+		4:  cfg.TCF2.Purpose4,
+		5:  cfg.TCF2.Purpose5,
+		6:  cfg.TCF2.Purpose6,
+		7:  cfg.TCF2.Purpose7,
+		8:  cfg.TCF2.Purpose8,
+		9:  cfg.TCF2.Purpose9,
+		10: cfg.TCF2.Purpose10,
+	}
+
 	permissionsImpl := &permissionsImpl{
 		cfg:              cfg,
 		gdprDefaultValue: gdprDefaultValue,
+		purposeConfigs:   purposeConfigs,
 		vendorIDs:        vendorIDs,
 		fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){
 			tcf2SpecVersion: newVendorListFetcher(ctx, cfg, client, vendorListURLMaker)},
diff --git a/gdpr/impl.go b/gdpr/impl.go
index 17a1a893..ac0bfefd 100644
--- a/gdpr/impl.go
+++ b/gdpr/impl.go
@@ -30,6 +30,7 @@ const (
 type permissionsImpl struct {
 	cfg              config.GDPR
 	gdprDefaultValue Signal
+	purposeConfigs   map[consentconstants.Purpose]config.TCF2Purpose
 	vendorIDs        map[openrtb_ext.BidderName]uint16
 	fetchVendorList  map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error)
 }
@@ -41,7 +42,7 @@ func (p *permissionsImpl) HostCookiesAllowed(ctx context.Context, gdprSignal Sig
 		return true, nil
 	}
 
-	return p.allowSync(ctx, uint16(p.cfg.HostVendorID), consent)
+	return p.allowSync(ctx, uint16(p.cfg.HostVendorID), consent, false)
 }
 
 func (p *permissionsImpl) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.BidderName, gdprSignal Signal, consent string) (bool, error) {
@@ -53,7 +54,8 @@ func (p *permissionsImpl) BidderSyncAllowed(ctx context.Context, bidder openrtb_
 
 	id, ok := p.vendorIDs[bidder]
 	if ok {
-		return p.allowSync(ctx, id, consent)
+		vendorException := p.isVendorException(consentconstants.Purpose(1), bidder)
+		return p.allowSync(ctx, id, consent, vendorException)
 	}
 
 	return false, nil
@@ -80,9 +82,9 @@ func (p *permissionsImpl) AuctionActivitiesAllowed(ctx context.Context,
 	}
 
 	if id, ok := p.vendorIDs[bidder]; ok {
-		return p.allowActivities(ctx, id, consent, weakVendorEnforcement)
+		return p.allowActivities(ctx, id, bidder, consent, weakVendorEnforcement)
 	} else if weakVendorEnforcement {
-		return p.allowActivities(ctx, 0, consent, weakVendorEnforcement)
+		return p.allowActivities(ctx, 0, bidder, consent, weakVendorEnforcement)
 	}
 
 	return p.defaultVendorPermissions()
@@ -104,7 +106,7 @@ func (p *permissionsImpl) normalizeGDPR(gdprSignal Signal) Signal {
 	return SignalYes
 }
 
-func (p *permissionsImpl) allowSync(ctx context.Context, vendorID uint16, consent string) (bool, error) {
+func (p *permissionsImpl) allowSync(ctx context.Context, vendorID uint16, consent string, vendorException bool) (bool, error) {
 
 	if consent == "" {
 		return false, nil
@@ -127,10 +129,10 @@ func (p *permissionsImpl) allowSync(ctx context.Context, vendorID uint16, consen
 		err := fmt.Errorf("Unable to access TCF2 parsed consent")
 		return false, err
 	}
-	return p.checkPurpose(consentMeta, vendor, vendorID, tcf2ConsentConstants.InfoStorageAccess, false), nil
+	return p.checkPurpose(consentMeta, vendor, vendorID, tcf2ConsentConstants.InfoStorageAccess, vendorException, false), nil
 }
 
-func (p *permissionsImpl) allowActivities(ctx context.Context, vendorID uint16, consent string, weakVendorEnforcement bool) (allowBidRequest bool, passGeo bool, passID bool, err error) {
+func (p *permissionsImpl) allowActivities(ctx context.Context, vendorID uint16, bidder openrtb_ext.BidderName, consent string, weakVendorEnforcement bool) (allowBidRequest bool, passGeo bool, passID bool, err error) {
 	parsedConsent, vendor, err := p.parseVendor(ctx, vendorID, consent)
 	if err != nil {
 		return false, false, false, err
@@ -156,17 +158,20 @@ func (p *permissionsImpl) allowActivities(ctx context.Context, vendorID uint16,
 	}
 
 	if p.cfg.TCF2.SpecialPurpose1.Enabled {
-		passGeo = consentMeta.SpecialFeatureOptIn(1) && (vendor.SpecialPurpose(1) || weakVendorEnforcement)
+		vendorException := p.isSpecialPurposeVendorException(bidder)
+		passGeo = vendorException || (consentMeta.SpecialFeatureOptIn(1) && (vendor.SpecialPurpose(1) || weakVendorEnforcement))
 	} else {
 		passGeo = true
 	}
 	if p.cfg.TCF2.Purpose2.Enabled {
-		allowBidRequest = p.checkPurpose(consentMeta, vendor, vendorID, consentconstants.Purpose(2), weakVendorEnforcement)
+		vendorException := p.isVendorException(consentconstants.Purpose(2), bidder)
+		allowBidRequest = p.checkPurpose(consentMeta, vendor, vendorID, consentconstants.Purpose(2), vendorException, weakVendorEnforcement)
 	} else {
 		allowBidRequest = true
 	}
 	for i := 2; i <= 10; i++ {
-		if p.checkPurpose(consentMeta, vendor, vendorID, consentconstants.Purpose(i), weakVendorEnforcement) {
+		vendorException := p.isVendorException(consentconstants.Purpose(i), bidder)
+		if p.checkPurpose(consentMeta, vendor, vendorID, consentconstants.Purpose(i), vendorException, weakVendorEnforcement) {
 			passID = true
 			break
 		}
@@ -175,11 +180,25 @@ func (p *permissionsImpl) allowActivities(ctx context.Context, vendorID uint16,
 	return
 }
 
+func (p *permissionsImpl) isVendorException(purpose consentconstants.Purpose, bidder openrtb_ext.BidderName) (vendorException bool) {
+	if _, ok := p.purposeConfigs[purpose].VendorExceptionMap[bidder]; ok {
+		vendorException = true
+	}
+	return
+}
+
+func (p *permissionsImpl) isSpecialPurposeVendorException(bidder openrtb_ext.BidderName) (vendorException bool) {
+	if _, ok := p.cfg.TCF2.SpecialPurpose1.VendorExceptionMap[bidder]; ok {
+		vendorException = true
+	}
+	return
+}
+
 const pubRestrictNotAllowed = 0
 const pubRestrictRequireConsent = 1
 const pubRestrictRequireLegitInterest = 2
 
-func (p *permissionsImpl) checkPurpose(consent tcf2.ConsentMetadata, vendor api.Vendor, vendorID uint16, purpose consentconstants.Purpose, weakVendorEnforcement bool) bool {
+func (p *permissionsImpl) checkPurpose(consent tcf2.ConsentMetadata, vendor api.Vendor, vendorID uint16, purpose consentconstants.Purpose, vendorException, weakVendorEnforcement bool) bool {
 	if purpose == tcf2ConsentConstants.InfoStorageAccess && p.cfg.TCF2.PurposeOneTreatment.Enabled && consent.PurposeOneTreatment() {
 		return p.cfg.TCF2.PurposeOneTreatment.AccessAllowed
 	}
@@ -187,6 +206,10 @@ func (p *permissionsImpl) checkPurpose(consent tcf2.ConsentMetadata, vendor api.
 		return false
 	}
 
+	if vendorException {
+		return true
+	}
+
 	purposeAllowed := consent.PurposeAllowed(purpose) && (weakVendorEnforcement || (vendor.Purpose(purpose) && consent.VendorConsent(vendorID)))
 	legitInterest := consent.PurposeLITransparency(purpose) && (weakVendorEnforcement || (vendor.LegitimateInterest(purpose) && consent.VendorLegitInterest(vendorID)))
 
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 91ce9f0d..780b75f6 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -100,10 +100,12 @@ const (
 	BidderAppnexus          BidderName = "appnexus"
 	BidderAudienceNetwork   BidderName = "audienceNetwork"
 	BidderAvocet            BidderName = "avocet"
+	BidderAxonix            BidderName = "axonix"
 	BidderBeachfront        BidderName = "beachfront"
 	BidderBeintoo           BidderName = "beintoo"
 	BidderBetween           BidderName = "between"
 	BidderBidmachine        BidderName = "bidmachine"
+	BidderBidmyadz          BidderName = "bidmyadz"
 	BidderBidsCube          BidderName = "bidscube"
 	BidderBmtm              BidderName = "bmtm"
 	BidderBrightroll        BidderName = "brightroll"
@@ -139,6 +141,7 @@ const (
 	BidderLockerDome        BidderName = "lockerdome"
 	BidderLogicad           BidderName = "logicad"
 	BidderLunaMedia         BidderName = "lunamedia"
+	BidderSaLunaMedia       BidderName = "sa_lunamedia"
 	BidderMadvertise        BidderName = "madvertise"
 	BidderMarsmedia         BidderName = "marsmedia"
 	BidderMediafuse         BidderName = "mediafuse"
@@ -221,10 +224,12 @@ func CoreBidderNames() []BidderName {
 		BidderAppnexus,
 		BidderAudienceNetwork,
 		BidderAvocet,
+		BidderAxonix,
 		BidderBeachfront,
 		BidderBeintoo,
 		BidderBetween,
 		BidderBidmachine,
+		BidderBidmyadz,
 		BidderBidsCube,
 		BidderBmtm,
 		BidderBrightroll,
@@ -260,6 +265,7 @@ func CoreBidderNames() []BidderName {
 		BidderLockerDome,
 		BidderLogicad,
 		BidderLunaMedia,
+		BidderSaLunaMedia,
 		BidderMadvertise,
 		BidderMarsmedia,
 		BidderMediafuse,
diff --git a/openrtb_ext/imp_axonix.go b/openrtb_ext/imp_axonix.go
new file mode 100644
index 00000000..7dd9f684
--- /dev/null
+++ b/openrtb_ext/imp_axonix.go
@@ -0,0 +1,5 @@
+package openrtb_ext
+
+type ExtImpAxonix struct {
+	SupplyId string `json:"supplyId"`
+}
diff --git a/openrtb_ext/imp_sa_lunamedia.go b/openrtb_ext/imp_sa_lunamedia.go
new file mode 100644
index 00000000..cb99b0ac
--- /dev/null
+++ b/openrtb_ext/imp_sa_lunamedia.go
@@ -0,0 +1,6 @@
+package openrtb_ext
+
+type ExtImpSaLunamedia struct {
+	Key  string `json:"key"`
+	Type string `json:"type,omitempty"`
+}
diff --git a/openrtb_ext/user.go b/openrtb_ext/user.go
index b83f8233..d5e6ae67 100644
--- a/openrtb_ext/user.go
+++ b/openrtb_ext/user.go
@@ -10,11 +10,6 @@ type ExtUser struct {
 
 	Prebid *ExtUserPrebid `json:"prebid,omitempty"`
 
-	// DigiTrust breaks the typical Prebid Server convention of namespacing "global" options inside "ext.prebid.*"
-	// to match the recommendation from the broader digitrust community.
-	// For more info, see: https://github.com/digi-trust/dt-cdn/wiki/OpenRTB-extension#openrtb-2x
-	DigiTrust *ExtUserDigiTrust `json:"digitrust,omitempty"`
-
 	Eids []ExtUserEid `json:"eids,omitempty"`
 }
 
@@ -23,14 +18,6 @@ type ExtUserPrebid struct {
 	BuyerUIDs map[string]string `json:"buyeruids,omitempty"`
 }
 
-// ExtUserDigiTrust defines the contract for bidrequest.user.ext.digitrust
-// More info on DigiTrust can be found here: https://github.com/digi-trust/dt-cdn/wiki/Integration-Guide
-type ExtUserDigiTrust struct {
-	ID   string `json:"id"`   // Unique device identifier
-	KeyV int    `json:"keyv"` // Key version used to encrypt ID
-	Pref int    `json:"pref"` // User optout preference
-}
-
 // ExtUserEid defines the contract for bidrequest.user.ext.eids
 // Responsible for the Universal User ID support: establishing pseudonymous IDs for users.
 // See https://github.com/prebid/Prebid.js/issues/3900 for details.
diff --git a/privacy/scrubber.go b/privacy/scrubber.go
index edaa5bb0..e07ebd05 100644
--- a/privacy/scrubber.go
+++ b/privacy/scrubber.go
@@ -225,11 +225,8 @@ func scrubUserExtIDs(userExt json.RawMessage) json.RawMessage {
 	}
 
 	_, hasEids := userExtParsed["eids"]
-	_, hasDigitrust := userExtParsed["digitrust"]
-	if hasEids || hasDigitrust {
+	if hasEids {
 		delete(userExtParsed, "eids")
-		delete(userExtParsed, "digitrust")
-
 		result, err := json.Marshal(userExtParsed)
 		if err == nil {
 			return result
diff --git a/static/bidder-info/axonix.yaml b/static/bidder-info/axonix.yaml
new file mode 100644
index 00000000..3c73501d
--- /dev/null
+++ b/static/bidder-info/axonix.yaml
@@ -0,0 +1,15 @@
+maintainer:
+  email: support.axonix@emodoinc.com
+gvlVendorID: 678
+modifyingVastXmlAllowed: true
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - native
diff --git a/static/bidder-info/bidmyadz.yaml b/static/bidder-info/bidmyadz.yaml
new file mode 100644
index 00000000..70a995a2
--- /dev/null
+++ b/static/bidder-info/bidmyadz.yaml
@@ -0,0 +1,13 @@
+maintainer:
+  email: "contact@bidmyadz.com"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - native
\ No newline at end of file
diff --git a/static/bidder-info/inmobi.yaml b/static/bidder-info/inmobi.yaml
index 9b11640f..634c0348 100644
--- a/static/bidder-info/inmobi.yaml
+++ b/static/bidder-info/inmobi.yaml
@@ -1,5 +1,5 @@
 maintainer:
-  email: "prebid-support@inmobi.com"
+  email: "technology-irv@inmobi.com"
 gvlVendorID: 333
 capabilities:
   app:
diff --git a/static/bidder-info/sa_lunamedia.yaml b/static/bidder-info/sa_lunamedia.yaml
new file mode 100644
index 00000000..181e1fd6
--- /dev/null
+++ b/static/bidder-info/sa_lunamedia.yaml
@@ -0,0 +1,14 @@
+maintainer:
+  email: "support@lunamedia.io"
+gvlVendorID: 998
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - native
\ No newline at end of file
diff --git a/static/bidder-params/axonix.json b/static/bidder-params/axonix.json
new file mode 100644
index 00000000..7a3762ce
--- /dev/null
+++ b/static/bidder-params/axonix.json
@@ -0,0 +1,14 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Axonix Adapter Params",
+  "description": "A schema which validates params accepted by the Axonix adapter",
+  "type": "object",
+  "properties": {
+    "supplyId": {
+      "type": "string",
+      "minLength": 1,
+      "description": "Unique supply identifier"
+    }
+  },
+  "required": ["supplyId"]
+}
diff --git a/static/bidder-params/bidmyadz.json b/static/bidder-params/bidmyadz.json
new file mode 100644
index 00000000..4e7b1119
--- /dev/null
+++ b/static/bidder-params/bidmyadz.json
@@ -0,0 +1,12 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "BidMyAdz Adapter Params",
+    "description": "A schema which validates params accepted by the BidMyAdz adapter",
+    "type": "object",
+    "properties": {
+      "placementId": {
+        "type": "string"
+      }
+    },
+    "required": ["placementId"]
+  }
\ No newline at end of file
diff --git a/static/bidder-params/sa_lunamedia.json b/static/bidder-params/sa_lunamedia.json
new file mode 100644
index 00000000..51ca0909
--- /dev/null
+++ b/static/bidder-params/sa_lunamedia.json
@@ -0,0 +1,17 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "Sa_Lunamedia Adapter Params",
+    "description": "A schema which validates params accepted by the Sa_Lunamedia adapter",
+    "type": "object",
+    "properties": {
+      "key": {
+        "type": "string",
+        "description": "network or placement key"
+      },
+      "type": {
+        "type": "string",
+        "enum": ["network", "publisher"]
+      }
+    },
+    "required": ["key"]
+  }
\ No newline at end of file
diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go
index 169417e0..53472018 100644
--- a/usersync/usersyncers/syncer.go
+++ b/usersync/usersyncers/syncer.go
@@ -28,6 +28,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/beachfront"
 	"github.com/prebid/prebid-server/adapters/beintoo"
 	"github.com/prebid/prebid-server/adapters/between"
+	"github.com/prebid/prebid-server/adapters/bidmyadz"
 	"github.com/prebid/prebid-server/adapters/bmtm"
 	"github.com/prebid/prebid-server/adapters/brightroll"
 	"github.com/prebid/prebid-server/adapters/colossus"
@@ -48,6 +49,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/grid"
 	"github.com/prebid/prebid-server/adapters/gumgum"
 	"github.com/prebid/prebid-server/adapters/improvedigital"
+	"github.com/prebid/prebid-server/adapters/inmobi"
 	"github.com/prebid/prebid-server/adapters/invibes"
 	"github.com/prebid/prebid-server/adapters/ix"
 	"github.com/prebid/prebid-server/adapters/jixie"
@@ -69,6 +71,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/rhythmone"
 	"github.com/prebid/prebid-server/adapters/rtbhouse"
 	"github.com/prebid/prebid-server/adapters/rubicon"
+	"github.com/prebid/prebid-server/adapters/sa_lunamedia"
 	"github.com/prebid/prebid-server/adapters/sharethrough"
 	"github.com/prebid/prebid-server/adapters/smartadserver"
 	"github.com/prebid/prebid-server/adapters/smartrtb"
@@ -128,6 +131,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderBeintoo, beintoo.NewBeintooSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderBmtm, bmtm.NewBmtmSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderBrightroll, brightroll.NewBrightrollSyncer)
+	insertIntoMap(cfg, syncers, openrtb_ext.BidderBidmyadz, bidmyadz.NewBidmyadzSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderColossus, colossus.NewColossusSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderConnectAd, connectad.NewConnectAdSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderConsumable, consumable.NewConsumableSyncer)
@@ -147,6 +151,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderGrid, grid.NewGridSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderGumGum, gumgum.NewGumGumSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderImprovedigital, improvedigital.NewImprovedigitalSyncer)
+	insertIntoMap(cfg, syncers, openrtb_ext.BidderInMobi, inmobi.NewInmobiSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderInvibes, invibes.NewInvibesSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderIx, ix.NewIxSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderJixie, jixie.NewJixieSyncer)
@@ -154,6 +159,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderLockerDome, lockerdome.NewLockerDomeSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderLogicad, logicad.NewLogicadSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderLunaMedia, lunamedia.NewLunaMediaSyncer)
+	insertIntoMap(cfg, syncers, openrtb_ext.BidderSaLunaMedia, salunamedia.NewSaLunamediaSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderMarsmedia, marsmedia.NewMarsmediaSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderMediafuse, mediafuse.NewMediafuseSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderMgid, mgid.NewMgidSyncer)


Test patch:
diff --git a/adapters/adform/adformtest/supplemental/user-nil.json b/adapters/adform/adformtest/supplemental/user-nil.json
index 5f02fe85..96ea1dbf 100644
--- a/adapters/adform/adformtest/supplemental/user-nil.json
+++ b/adapters/adform/adformtest/supplemental/user-nil.json
@@ -31,12 +31,7 @@
     },
     "user": {
       "ext": {
-        "consent": "abc2",
-        "digitrust": {
-          "ID": "digitrustId",
-          "KeyV": 1,
-          "Pref": 0
-        }
+        "consent": "abc2"
       }
     }
   },
diff --git a/adapters/axonix/axonix_test.go b/adapters/axonix/axonix_test.go
new file mode 100644
index 00000000..6c4a3eb3
--- /dev/null
+++ b/adapters/axonix/axonix_test.go
@@ -0,0 +1,30 @@
+package axonix
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestJsonSamplesWithConfiguredURI(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderAxonix, config.Adapter{
+		Endpoint: "https://openrtb-us-east-1.axonix.com/supply/prebid-server/24cc9034-f861-47b8-a6a8-b7e0968c00b8"})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "axonixtest", bidder)
+}
+
+func TestJsonSamplesWithHardcodedURI(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderAxonix, config.Adapter{})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "axonixtest", bidder)
+}
diff --git a/adapters/axonix/axonixtest/exemplary/banner-and-video.json b/adapters/axonix/axonixtest/exemplary/banner-and-video.json
new file mode 100644
index 00000000..1755cd0e
--- /dev/null
+++ b/adapters/axonix/axonixtest/exemplary/banner-and-video.json
@@ -0,0 +1,133 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+          }
+        }
+      },
+      {
+        "id": "test-imp-video-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "bidder": {
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://openrtb-us-east-1.axonix.com/supply/prebid-server/24cc9034-f861-47b8-a6a8-b7e0968c00b8",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            },
+            {
+              "id": "test-imp-video-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "958",
+              "bid": [{
+                "id": "7706636740145184841",
+                "impid": "test-imp-video-id",
+                "price": 0.500000,
+                "adid": "29681110",
+                "adm": "some-test-ad",
+                "adomain": ["axonix.com"],
+                "cid": "958",
+                "crid": "29681110",
+                "h": 576,
+                "w": 1024
+              }]
+            }
+          ],
+          "bidid": "5778926625248726496",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [{
+        "bid": {
+          "id": "7706636740145184841",
+          "impid": "test-imp-video-id",
+          "price": 0.5,
+          "adm": "some-test-ad",
+          "adid": "29681110",
+          "adomain": ["axonix.com"],
+          "cid": "958",
+          "crid": "29681110",
+          "w": 1024,
+          "h": 576
+        },
+        "type": "video"
+      }]
+    }
+  ]
+
+}
diff --git a/adapters/axonix/axonixtest/exemplary/banner-video-native.json b/adapters/axonix/axonixtest/exemplary/banner-video-native.json
new file mode 100644
index 00000000..3944eb35
--- /dev/null
+++ b/adapters/axonix/axonixtest/exemplary/banner-video-native.json
@@ -0,0 +1,157 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+          }
+        }
+      },
+      {
+        "id": "native-imp",
+        "native": {
+          "ver": "1.1",
+          "request": "{\"ver\":\"1.1\",\"context\":1,\"contextsubtype\":11,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":500}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1,\"hmin\":1}},{\"id\":3,\"required\":0,\"data\":{\"type\":1,\"len\":200}},{\"id\":4,\"required\":0,\"data\":{\"type\":2,\"len\":15000}},{\"id\":5,\"required\":0,\"data\":{\"type\":6,\"len\":40}},{\"id\":6,\"required\":0,\"data\":{\"type\":500}}]}"
+        },
+        "ext": {
+          "bidder": {
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+          }
+        }
+      },
+      {
+        "id": "test-imp-video-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "bidder": {
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://openrtb-us-east-1.axonix.com/supply/prebid-server/24cc9034-f861-47b8-a6a8-b7e0968c00b8",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            },
+            {
+              "id": "native-imp",
+              "native": {
+                "ver": "1.1",
+                "request": "{\"ver\":\"1.1\",\"context\":1,\"contextsubtype\":11,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":500}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":1,\"hmin\":1}},{\"id\":3,\"required\":0,\"data\":{\"type\":1,\"len\":200}},{\"id\":4,\"required\":0,\"data\":{\"type\":2,\"len\":15000}},{\"id\":5,\"required\":0,\"data\":{\"type\":6,\"len\":40}},{\"id\":6,\"required\":0,\"data\":{\"type\":500}}]}"
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            },
+            {
+              "id": "test-imp-video-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "958",
+              "bid": [{
+                "id": "7706636740145184841",
+                "impid": "test-imp-video-id",
+                "price": 0.500000,
+                "adid": "29681110",
+                "adm": "some-test-ad",
+                "adomain": ["axonix.com"],
+                "cid": "958",
+                "crid": "29681110",
+                "h": 576,
+                "w": 1024
+              }]
+            }
+          ],
+          "bidid": "5778926625248726496",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [{
+        "bid": {
+          "id": "7706636740145184841",
+          "impid": "test-imp-video-id",
+          "price": 0.5,
+          "adm": "some-test-ad",
+          "adid": "29681110",
+          "adomain": ["axonix.com"],
+          "cid": "958",
+          "crid": "29681110",
+          "w": 1024,
+          "h": 576
+        },
+        "type": "video"
+      }]
+    }
+  ]
+
+}
diff --git a/adapters/axonix/axonixtest/exemplary/simple-banner.json b/adapters/axonix/axonixtest/exemplary/simple-banner.json
new file mode 100644
index 00000000..581e59b9
--- /dev/null
+++ b/adapters/axonix/axonixtest/exemplary/simple-banner.json
@@ -0,0 +1,105 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://openrtb-us-east-1.axonix.com/supply/prebid-server/24cc9034-f861-47b8-a6a8-b7e0968c00b8",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "958",
+              "bid": [{
+                "id": "7706636740145184841",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adid": "29681110",
+                "adm": "some-test-ad",
+                "adomain": ["yahoo.com"],
+                "cid": "958",
+                "crid": "29681110",
+                "h": 250,
+                "w": 300
+              }]
+            }
+          ],
+          "bidid": "5778926625248726496",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [{
+        "bid": {
+          "id": "7706636740145184841",
+          "impid": "test-imp-id",
+          "price": 0.5,
+          "adm": "some-test-ad",
+          "adid": "29681110",
+          "adomain": ["yahoo.com"],
+          "cid": "958",
+          "crid": "29681110",
+          "w": 300,
+          "h": 250
+        },
+        "type": "banner"
+      }]
+    }
+  ]
+}
diff --git a/adapters/axonix/axonixtest/exemplary/simple-video.json b/adapters/axonix/axonixtest/exemplary/simple-video.json
new file mode 100644
index 00000000..c15d7876
--- /dev/null
+++ b/adapters/axonix/axonixtest/exemplary/simple-video.json
@@ -0,0 +1,86 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext":{
+          "bidder":{
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://openrtb-us-east-1.axonix.com/supply/prebid-server/24cc9034-f861-47b8-a6a8-b7e0968c00b8",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "cur": "USD",
+          "seatbid": [
+            {
+              "seat": "axonix",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "w": 1024,
+                "h": 576
+              }]
+            }
+          ]
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [{
+        "bid": {
+          "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+          "impid": "test-imp-id",
+          "price": 0.5,
+          "adm": "some-test-ad",
+          "crid": "crid_10",
+          "w": 1024,
+          "h": 576
+        },
+        "type": "video"
+      }]
+    }
+  ]
+}
diff --git a/adapters/axonix/axonixtest/params/race/banner.json b/adapters/axonix/axonixtest/params/race/banner.json
new file mode 100644
index 00000000..7217c9c3
--- /dev/null
+++ b/adapters/axonix/axonixtest/params/race/banner.json
@@ -0,0 +1,3 @@
+{
+  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+}
diff --git a/adapters/axonix/axonixtest/params/race/video.json b/adapters/axonix/axonixtest/params/race/video.json
new file mode 100644
index 00000000..7217c9c3
--- /dev/null
+++ b/adapters/axonix/axonixtest/params/race/video.json
@@ -0,0 +1,3 @@
+{
+  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+}
diff --git a/adapters/axonix/axonixtest/supplemental/bad-response-no-body.json b/adapters/axonix/axonixtest/supplemental/bad-response-no-body.json
new file mode 100644
index 00000000..f89f40f1
--- /dev/null
+++ b/adapters/axonix/axonixtest/supplemental/bad-response-no-body.json
@@ -0,0 +1,57 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext":{
+          "bidder":{
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+           }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://openrtb-us-east-1.axonix.com/supply/prebid-server/24cc9034-f861-47b8-a6a8-b7e0968c00b8",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "unexpected end of JSON input",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/axonix/axonixtest/supplemental/status-bad-request.json b/adapters/axonix/axonixtest/supplemental/status-bad-request.json
new file mode 100644
index 00000000..d64a855e
--- /dev/null
+++ b/adapters/axonix/axonixtest/supplemental/status-bad-request.json
@@ -0,0 +1,58 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext":{
+          "bidder":{
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+           }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://openrtb-us-east-1.axonix.com/supply/prebid-server/24cc9034-f861-47b8-a6a8-b7e0968c00b8",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 400,
+        "body": {}
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 400.",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/axonix/axonixtest/supplemental/status-no-content.json b/adapters/axonix/axonixtest/supplemental/status-no-content.json
new file mode 100644
index 00000000..96dd899c
--- /dev/null
+++ b/adapters/axonix/axonixtest/supplemental/status-no-content.json
@@ -0,0 +1,53 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext":{
+          "bidder":{
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+           }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://openrtb-us-east-1.axonix.com/supply/prebid-server/24cc9034-f861-47b8-a6a8-b7e0968c00b8",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 204,
+        "body": {}
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": []
+}
diff --git a/adapters/axonix/axonixtest/supplemental/unexpected-status-code.json b/adapters/axonix/axonixtest/supplemental/unexpected-status-code.json
new file mode 100644
index 00000000..e7a7be78
--- /dev/null
+++ b/adapters/axonix/axonixtest/supplemental/unexpected-status-code.json
@@ -0,0 +1,58 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext":{
+          "bidder":{
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+           }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://openrtb-us-east-1.axonix.com/supply/prebid-server/24cc9034-f861-47b8-a6a8-b7e0968c00b8",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 500,
+        "body": {}
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 500.",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/axonix/axonixtest/supplemental/valid-extension.json b/adapters/axonix/axonixtest/supplemental/valid-extension.json
new file mode 100644
index 00000000..372f24d4
--- /dev/null
+++ b/adapters/axonix/axonixtest/supplemental/valid-extension.json
@@ -0,0 +1,86 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext":{
+          "bidder":{
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+           }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://openrtb-us-east-1.axonix.com/supply/prebid-server/24cc9034-f861-47b8-a6a8-b7e0968c00b8",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "cur": "USD",
+          "seatbid": [
+            {
+              "seat": "axonix",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "w": 1024,
+                "h": 576
+              }]
+            }
+          ]
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [{
+        "bid": {
+          "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+          "impid": "test-imp-id",
+          "price": 0.5,
+          "adm": "some-test-ad",
+          "crid": "crid_10",
+          "w": 1024,
+          "h": 576
+        },
+        "type": "video"
+      }]
+    }
+  ]
+}
diff --git a/adapters/axonix/axonixtest/supplemental/valid-with-device.json b/adapters/axonix/axonixtest/supplemental/valid-with-device.json
new file mode 100644
index 00000000..62f4ea06
--- /dev/null
+++ b/adapters/axonix/axonixtest/supplemental/valid-with-device.json
@@ -0,0 +1,93 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "device": {
+      "ip": "3.0.0.0",
+      "ua": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36"
+    },
+    "imp": [
+      {
+        "id": "test-imp-video-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "bidder": {
+            "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://openrtb-us-east-1.axonix.com/supply/prebid-server/24cc9034-f861-47b8-a6a8-b7e0968c00b8",
+        "body": {
+          "id": "test-request-id",
+          "device": {
+            "ip": "3.0.0.0",
+            "ua": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36"
+          },
+          "imp": [
+            {
+              "id": "test-imp-video-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "cur": "USD",
+          "seatbid": [
+            {
+              "seat": "axonix",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-video-id",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "w": 1024,
+                "h": 576
+              }]
+            }
+          ]
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [{
+        "bid": {
+          "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+          "impid": "test-imp-video-id",
+          "price": 0.5,
+          "adm": "some-test-ad",
+          "crid": "crid_10",
+          "w": 1024,
+          "h": 576
+        },
+        "type": "video"
+      }]
+    }
+  ]
+}
diff --git a/adapters/axonix/params_test.go b/adapters/axonix/params_test.go
new file mode 100644
index 00000000..e9c0cc5b
--- /dev/null
+++ b/adapters/axonix/params_test.go
@@ -0,0 +1,59 @@
+package axonix
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// This file actually intends to test static/bidder-params/axonix.json
+//
+// These also validate the format of the external API: request.imp[i].ext.axonix
+
+// TestValidParams makes sure that the Axonix 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 {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, validParam := range validParams {
+		if err := validator.Validate(openrtb_ext.BidderAxonix, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected Axonix params: %s", validParam)
+		}
+	}
+}
+
+// TestInvalidParams makes sure that the Axonix 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 {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, invalidParam := range invalidParams {
+		if err := validator.Validate(openrtb_ext.BidderAxonix, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"supplyId": "24cc9034-f861-47b8-a6a8-b7e0968c00b8"}`,
+	`{"supplyId": "test"}`,
+}
+
+var invalidParams = []string{
+	`{"supplyId": 100}`,
+	`{"supplyId": false}`,
+	`{"supplyId": true}`,
+	`{"supplyId": 123}`,
+	``,
+	`null`,
+	`true`,
+	`9`,
+	`1.2`,
+	`[]`,
+	`{}`,
+}
diff --git a/adapters/bidder_test.go b/adapters/bidder_test.go
new file mode 100644
index 00000000..f0b833ce
--- /dev/null
+++ b/adapters/bidder_test.go
@@ -0,0 +1,63 @@
+package adapters
+
+import (
+	"errors"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+)
+
+func TestExtraRequestInfoConvertCurrency(t *testing.T) {
+	var (
+		givenValue float64 = 2
+		givenFrom  string  = "AAA"
+		givenTo    string  = "BBB"
+	)
+
+	testCases := []struct {
+		description   string
+		setMock       func(m *mock.Mock)
+		expectedValue float64
+		expectedError error
+	}{
+		{
+			description:   "Success",
+			setMock:       func(m *mock.Mock) { m.On("GetRate", "AAA", "BBB").Return(2.5, nil) },
+			expectedValue: 5,
+			expectedError: nil,
+		},
+		{
+			description:   "Error",
+			setMock:       func(m *mock.Mock) { m.On("GetRate", "AAA", "BBB").Return(2.5, errors.New("some error")) },
+			expectedValue: 0,
+			expectedError: errors.New("some error"),
+		},
+	}
+
+	for _, test := range testCases {
+		mockConversions := &mockConversions{}
+		test.setMock(&mockConversions.Mock)
+
+		extraRequestInfo := NewExtraRequestInfo(mockConversions)
+		result, err := extraRequestInfo.ConvertCurrency(givenValue, givenFrom, givenTo)
+
+		mockConversions.AssertExpectations(t)
+		assert.Equal(t, test.expectedValue, result, test.description+":result")
+		assert.Equal(t, test.expectedError, err, test.description+":err")
+	}
+}
+
+type mockConversions struct {
+	mock.Mock
+}
+
+func (m mockConversions) GetRate(from string, to string) (float64, error) {
+	args := m.Called(from, to)
+	return args.Get(0).(float64), args.Error(1)
+}
+
+func (m mockConversions) GetRates() *map[string]map[string]float64 {
+	args := m.Called()
+	return args.Get(0).(*map[string]map[string]float64)
+}
diff --git a/adapters/bidmyadz/bidmyadz_test.go b/adapters/bidmyadz/bidmyadz_test.go
new file mode 100644
index 00000000..b0de6a02
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadz_test.go
@@ -0,0 +1,18 @@
+package bidmyadz
+
+import (
+	"github.com/stretchr/testify/assert"
+	"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.BidderBidmyadz, config.Adapter{
+		Endpoint: "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc"})
+
+	assert.NoError(t, buildErr)
+	adapterstest.RunJSONBidderTest(t, "bidmyadztest", bidder)
+}
diff --git a/adapters/bidmyadz/bidmyadztest/exemplary/banner.json b/adapters/bidmyadz/bidmyadztest/exemplary/banner.json
new file mode 100644
index 00000000..460291bc
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/exemplary/banner.json
@@ -0,0 +1,146 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "1"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "d910ceef496ff2d746176506e296f4b3_z53356_a126365",
+          "bidid": "880184da7ec02b1f42802acb46b63b3c",
+          "seatbid": [{
+            "bid": [{
+              "id": "6ca51ef38eb42820d27503ee96b634b5",
+              "impid": "126365",
+              "price": 0.1,
+              "nurl": "http://test.com/nurl",
+              "burl": "http://test.com/burl",
+              "adm": "<ADM>",
+              "adomain": ["test.com"],
+              "cat": ["IAB1"],
+              "cid": "1",
+              "crid": "1",
+              "w": 300,
+              "h": 250,
+              "ext": {
+                "mediaType": "banner"
+              }
+            }],
+            "seat": "1"
+          }],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "6ca51ef38eb42820d27503ee96b634b5",
+            "impid": "126365",
+            "price": 0.1,
+            "nurl": "http://test.com/nurl",
+            "burl": "http://test.com/burl",
+            "adm": "<ADM>",
+            "adomain": ["test.com"],
+            "cat": ["IAB1"],
+            "cid": "1",
+            "crid": "1",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "mediaType": "banner"
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/exemplary/native.json b/adapters/bidmyadz/bidmyadztest/exemplary/native.json
new file mode 100644
index 00000000..98480260
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/exemplary/native.json
@@ -0,0 +1,141 @@
+{
+  "mockBidRequest": {
+    "id": "111",
+    "tmax": 150,
+    "at": 1,
+    "device": {
+      "dnt": 0,
+      "devicetype": 2,
+      "ip": "71.106.52.124",
+      "ua": "Mozilla/5.0 (X11; Linux x86_64; Ubuntu 14.04.2 LTS) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.0 Maxthon/1.0.5.3 Safari/537.36"
+    },
+    "user": {
+      "id": "user-id"
+    },
+    "site": {
+      "id": "native",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "1"
+      }
+    },
+    "cur": [
+      "USD"
+    ],
+    "imp": [{
+      "id": "1",
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "instl": 0,
+      "secure": 1,
+      "native": {
+        "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":15}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":300,\"hmin\":300,\"type\":3}}, {\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}",
+        "ver": "1.1"
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tnative"
+        }
+      }
+    }]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+      "body": {
+        "id": "111",
+        "tmax": 150,
+        "at": 1,
+        "device": {
+          "dnt": 0,
+          "devicetype": 2,
+          "ip": "71.106.52.124",
+          "ua": "Mozilla/5.0 (X11; Linux x86_64; Ubuntu 14.04.2 LTS) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.0 Maxthon/1.0.5.3 Safari/537.36"
+        },
+        "user": {
+          "id": "user-id"
+        },
+        "site": {
+          "id": "native",
+          "domain": "test.com",
+          "cat": ["IAB1"],
+          "page": "https://test.com",
+          "publisher": {
+            "id": "1"
+          }
+        },
+        "cur": [
+          "USD"
+        ],
+        "imp": [{
+          "id": "1",
+          "bidfloor": 0.01,
+          "bidfloorcur": "USD",
+          "secure": 1,
+          "native": {
+            "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":15}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":300,\"hmin\":300,\"type\":3}}, {\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}",
+            "ver": "1.1"
+          },
+          "ext": {
+            "bidder": {
+              "placementId": "tnative"
+            }
+          }
+        }]
+      }
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": {
+        "id": "a1580f2f-be6d-11eb-a150-d094662c1c35",
+        "bidid": "359da97d0384d8a14767029c18fd840d",
+        "seatbid": [{
+          "bid": [{
+            "id": "1",
+            "impid": "1",
+            "price": 0.1,
+            "nurl": "http://test.com/nurl",
+            "burl": "http://test.com/burl",
+            "adm": "{native-ads}",
+            "adomain": ["test.com"],
+            "cat": ["IAB1"],
+            "cid": "1",
+            "crid": "2",
+            "w": 0,
+            "h": 0,
+            "ext": {
+              "mediaType": "native"
+            }
+          }],
+          "seat": "1"
+        }],
+        "cur": "USD"
+      }
+    }
+  }],
+
+  "expectedBidResponses": [{
+    "currency": "USD",
+    "bids": [{
+      "bid": {
+        "id": "1",
+        "impid": "1",
+        "price": 0.1,
+        "nurl": "http://test.com/nurl",
+        "burl": "http://test.com/burl",
+        "adm": "{native-ads}",
+        "adomain": ["test.com"],
+        "cat": ["IAB1"],
+        "cid": "1",
+        "crid": "2",
+        "ext": {
+          "mediaType": "native"
+        }
+      },
+      "type": "native"
+    }]
+  }]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/exemplary/video.json b/adapters/bidmyadz/bidmyadztest/exemplary/video.json
new file mode 100644
index 00000000..92c42f83
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/exemplary/video.json
@@ -0,0 +1,160 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "video": {
+        "mimes": ["video/mp4", "video/ogg", "video/webm"],
+        "minduration": 5,
+        "maxduration": 60,
+        "protocols": [2, 3, 5, 6, 7, 8],
+        "w": 300,
+        "h": 250,
+        "linearity": 1,
+        "playbackmethod": [2]
+      },
+      "bidfloor": 0.001,
+      "bidfloorcur": "USD",
+      "secure": 1,
+      "exp": 3600,
+      "ext": {
+        "bidder": {
+          "placementId": "tvideo"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "video": {
+              "mimes": ["video/mp4", "video/ogg", "video/webm"],
+              "minduration": 5,
+              "maxduration": 60,
+              "protocols": [2, 3, 5, 6, 7, 8],
+              "w": 300,
+              "h": 250,
+              "linearity": 1,
+              "playbackmethod": [2]
+            },
+            "bidfloor": 0.001,
+            "bidfloorcur": "USD",
+            "secure": 1,
+            "exp": 3600,
+            "ext": {
+              "bidder": {
+                "placementId": "tvideo"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "1"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "d910ceef496ff2d746176506e296f4b3_z53356_a126365",
+          "bidid": "880184da7ec02b1f42802acb46b63b3c",
+          "seatbid": [{
+            "bid": [{
+              "id": "6ca51ef38eb42820d27503ee96b634b5",
+              "impid": "126365",
+              "price": 0.1,
+              "nurl": "http://test.com/nurl",
+              "burl": "http://test.com/burl",
+              "adm": "<VAST>",
+              "adomain": ["test.com"],
+              "cat": ["IAB1"],
+              "cid": "1",
+              "crid": "1",
+              "w": 300,
+              "h": 250,
+              "ext": {
+                "mediaType": "video"
+              }
+            }],
+            "seat": "1"
+          }],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "6ca51ef38eb42820d27503ee96b634b5",
+            "impid": "126365",
+            "price": 0.1,
+            "nurl": "http://test.com/nurl",
+            "burl": "http://test.com/burl",
+            "adm": "<VAST>",
+            "adomain": ["test.com"],
+            "cat": ["IAB1"],
+            "cid": "1",
+            "crid": "1",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "mediaType": "video"
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/params/race/banner.json b/adapters/bidmyadz/bidmyadztest/params/race/banner.json
new file mode 100644
index 00000000..18dce42f
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/params/race/banner.json
@@ -0,0 +1,3 @@
+{
+  "placementId": "tbanner"
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/params/race/native.json b/adapters/bidmyadz/bidmyadztest/params/race/native.json
new file mode 100644
index 00000000..0600af3a
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/params/race/native.json
@@ -0,0 +1,3 @@
+{
+  "placementId": "tnative"
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/params/race/video.json b/adapters/bidmyadz/bidmyadztest/params/race/video.json
new file mode 100644
index 00000000..85478bf2
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/params/race/video.json
@@ -0,0 +1,3 @@
+{
+  "placementId": "tvideo"
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/invalid-device-fields.json b/adapters/bidmyadz/bidmyadztest/supplemental/invalid-device-fields.json
new file mode 100644
index 00000000..d620a050
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/invalid-device-fields.json
@@ -0,0 +1,48 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "devicetype": 2
+    },
+    "user": {
+      "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "test"
+      }
+    }
+  },
+
+  "expectedMakeRequestsErrors": [{
+    "value": "IP/IPv6 is a required field",
+    "comparison": "literal"
+  }, {
+    "value": "User-Agent is a required field",
+    "comparison": "literal"
+  }]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/invalid-multi-imps.json b/adapters/bidmyadz/bidmyadztest/supplemental/invalid-multi-imps.json
new file mode 100644
index 00000000..09020fc8
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/invalid-multi-imps.json
@@ -0,0 +1,61 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }, {
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.11,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 320,
+        "h": 50
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "3234"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "test"
+      }
+    }
+  },
+
+  "expectedMakeRequestsErrors": [{
+    "value": "Bidder does not support multi impression",
+    "comparison": "literal"
+  }]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/missing-mediatype.json b/adapters/bidmyadz/bidmyadztest/supplemental/missing-mediatype.json
new file mode 100644
index 00000000..486d7324
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/missing-mediatype.json
@@ -0,0 +1,122 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "1"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "d910ceef496ff2d746176506e296f4b3_z53356_a126365",
+          "bidid": "880184da7ec02b1f42802acb46b63b3c",
+          "seatbid": [{
+            "bid": [{
+              "id": "6ca51ef38eb42820d27503ee96b634b5",
+              "impid": "126365",
+              "price": 0.1,
+              "nurl": "http://test.com/nurl",
+              "burl": "http://test.com/burl",
+              "adm": "<ADM>",
+              "adomain": ["test.com"],
+              "cat": ["IAB1"],
+              "cid": "1",
+              "crid": "1",
+              "w": 300,
+              "h": 250
+            }],
+            "seat": "1"
+          }],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "BidExt parsing error. unexpected end of JSON input",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/response-without-bids.json b/adapters/bidmyadz/bidmyadztest/supplemental/response-without-bids.json
new file mode 100644
index 00000000..fe3361f6
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/response-without-bids.json
@@ -0,0 +1,109 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "1"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "d910ceef496ff2d746176506e296f4b3_z53356_a126365",
+          "bidid": "880184da7ec02b1f42802acb46b63b3c",
+          "seatbid": [{
+            "bid": [],
+            "seat": "1"
+          }],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Empty SeatBid.Bids",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/response-without-seatbid.json b/adapters/bidmyadz/bidmyadztest/supplemental/response-without-seatbid.json
new file mode 100644
index 00000000..727e745e
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/response-without-seatbid.json
@@ -0,0 +1,106 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "1"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "d910ceef496ff2d746176506e296f4b3_z53356_a126365",
+          "bidid": "880184da7ec02b1f42802acb46b63b3c",
+          "seatbid": [],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Empty SeatBid",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/status-204.json b/adapters/bidmyadz/bidmyadztest/supplemental/status-204.json
new file mode 100644
index 00000000..05efda0e
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/status-204.json
@@ -0,0 +1,94 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "test"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "test"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 204,
+        "body": {}
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/status-400.json b/adapters/bidmyadz/bidmyadztest/supplemental/status-400.json
new file mode 100644
index 00000000..e24acdc6
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/status-400.json
@@ -0,0 +1,101 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "test"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "test"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 400,
+        "body": "Source blocked"
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bad Request. \"Source blocked\"",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/status-service-unavailable.json b/adapters/bidmyadz/bidmyadztest/supplemental/status-service-unavailable.json
new file mode 100644
index 00000000..13e22f55
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/status-service-unavailable.json
@@ -0,0 +1,100 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "test"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "test"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 503
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bidder is unavailable. Please contact your account manager.",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/status-unknown.json b/adapters/bidmyadz/bidmyadztest/supplemental/status-unknown.json
new file mode 100644
index 00000000..69b649e1
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/status-unknown.json
@@ -0,0 +1,101 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "test"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "test"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 403,
+        "body": "Forbidden"
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Something went wrong. Status Code: [ 403 ] \"Forbidden\"",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/params_test.go b/adapters/bidmyadz/params_test.go
new file mode 100644
index 00000000..857cde86
--- /dev/null
+++ b/adapters/bidmyadz/params_test.go
@@ -0,0 +1,49 @@
+package bidmyadz
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+var validParams = []string{
+	`{ "placementId": "1234" }`,
+}
+
+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.BidderBidmyadz, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected bidmyadz params: %s", validParam)
+		}
+	}
+}
+
+var invalidParams = []string{
+	`1234`,
+	``,
+	`true`,
+	`null`,
+	`[]`,
+	`{}`,
+	`{ "anyparam": "anyvalue" }`,
+	`{ "placementId": null }`,
+}
+
+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.BidderBidmyadz, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
diff --git a/adapters/bidmyadz/usersync_test.go b/adapters/bidmyadz/usersync_test.go
new file mode 100644
index 00000000..11b5fedd
--- /dev/null
+++ b/adapters/bidmyadz/usersync_test.go
@@ -0,0 +1,33 @@
+package bidmyadz
+
+import (
+	"testing"
+	"text/template"
+
+	"github.com/prebid/prebid-server/privacy"
+	"github.com/prebid/prebid-server/privacy/ccpa"
+	"github.com/prebid/prebid-server/privacy/gdpr"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewBidmyadzSyncer(t *testing.T) {
+	syncURL := "https://test.com/c0f68227d14ed938c6c49f3967cbe9bc?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}"
+	syncURLTemplate := template.Must(
+		template.New("sync-template").Parse(syncURL),
+	)
+	syncer := NewBidmyadzSyncer(syncURLTemplate)
+	syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{
+		GDPR: gdpr.Policy{
+			Signal:  "0",
+			Consent: "allGdpr",
+		},
+		CCPA: ccpa.Policy{
+			Consent: "1---",
+		},
+	})
+
+	assert.NoError(t, err)
+	assert.Equal(t, "https://test.com/c0f68227d14ed938c6c49f3967cbe9bc?gdpr=0&gdpr_consent=allGdpr&ccpa=1---", syncInfo.URL)
+	assert.Equal(t, "redirect", syncInfo.Type)
+	assert.Equal(t, false, syncInfo.SupportCORS)
+}
diff --git a/adapters/dmx/dmx_test.go b/adapters/dmx/dmx_test.go
index a9f1e8bb..409290c1 100644
--- a/adapters/dmx/dmx_test.go
+++ b/adapters/dmx/dmx_test.go
@@ -643,50 +643,6 @@ func TestUserEidsOnly(t *testing.T) {
 	}
 }
 
-func TestUserDigitrustOnly(t *testing.T) {
-	var w, h int = 300, 250
-
-	var width, height int64 = int64(w), int64(h)
-
-	bidder, buildErr := Builder(openrtb_ext.BidderDmx, config.Adapter{
-		Endpoint: "https://dmx.districtm.io/b/v2"})
-
-	if buildErr != nil {
-		t.Fatalf("Builder returned unexpected error %v", buildErr)
-	}
-
-	imp1 := openrtb2.Imp{
-		ID:  "imp1",
-		Ext: json.RawMessage("{\"bidder\":{\"dmxid\": \"1007\", \"memberid\": \"123456\", \"seller_id\":\"1008\"}}"),
-		Banner: &openrtb2.Banner{
-			W: &width,
-			H: &height,
-			Format: []openrtb2.Format{
-				{W: 300, H: 250},
-			},
-		}}
-
-	inputRequest := openrtb2.BidRequest{
-		Imp: []openrtb2.Imp{imp1, imp1, imp1},
-		Site: &openrtb2.Site{
-			Publisher: &openrtb2.Publisher{
-				ID: "10007",
-			},
-		},
-		User: &openrtb2.User{Ext: json.RawMessage(`{
-            "digitrust": {
-                "id": "11111111111",
-                "keyv": 4
-            }}`)},
-		ID: "1234",
-	}
-
-	actualAdapterRequests, _ := bidder.MakeRequests(&inputRequest, &adapters.ExtraRequestInfo{})
-	if len(actualAdapterRequests) != 1 {
-		t.Errorf("should have 1 request")
-	}
-}
-
 func TestUsersEids(t *testing.T) {
 	var w, h int = 300, 250
 
@@ -725,53 +681,56 @@ func TestUsersEids(t *testing.T) {
                         "rtiPartner": "TDID"
                     }
                 }]
-            },{
+            },
+			{
                 "source": "pubcid.org",
                 "uids": [{
-                    "id":"11111111"
+                    "id": "11111111"
                 }]
             },
-            {
+			{
                 "source": "id5-sync.com",
                 "uids": [{
                     "id": "ID5-12345"
                 }]
-            },
-            {
+            },            
+			{
                 "source": "parrable.com",
                 "uids": [{
                     "id": "01.1563917337.test-eid"
                 }]
-            },{
+            },
+			{
                 "source": "identityLink",
                 "uids": [{
                     "id": "11111111"
                 }]
-            },{
+            },
+			{
                 "source": "criteo",
                 "uids": [{
                     "id": "11111111"
                 }]
-            },{
+            },
+			{
                 "source": "britepool.com",
                 "uids": [{
                     "id": "11111111"
                 }]
-            },{
+            },
+			{
                 "source": "liveintent.com",
                 "uids": [{
                     "id": "11111111"
                 }]
-            },{
+            },
+			{
                 "source": "netid.de",
                 "uids": [{
                     "id": "11111111"
                 }]
-            }],
-            "digitrust": {
-                "id": "11111111111",
-                "keyv": 4
-            }}`)},
+            }]
+            }`)},
 		ID: "1234",
 	}
 
diff --git a/adapters/ix/ixtest/exemplary/native-eventtrackers-compat-12.json b/adapters/ix/ixtest/exemplary/native-eventtrackers-compat-12.json
new file mode 100644
index 00000000..36a23998
--- /dev/null
+++ b/adapters/ix/ixtest/exemplary/native-eventtrackers-compat-12.json
@@ -0,0 +1,104 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "native": {
+                    "request": "{}",
+                    "ver": "1.1"
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpcalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "native": {
+                                "request": "{}",
+                                "ver": "1.1"
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "{\"assets\":[{\"id\":123,\"required\":1,\"title\":{\"text\":\"Learn about this awesome thing\"}},{\"id\":124,\"required\":1,\"img\":{\"url\":\"http://www.myads.com/thumbnail1.png\"}},{\"id\":128,\"required\":1,\"img\":{\"url\":\"http://www.myads.com/largethumb1.png\"}},{\"id\":126,\"required\":1,\"data\":{\"value\":\"My Brand\"}},{\"id\":127,\"required\":1,\"data\":{\"value\":\"Learn all about this awesome story of someone using my product.\"}}],\"link\":{\"url\":\"http: //i.am.a/URL\"},\"eventtrackers\":[{\"url\":\"https://example.com/imp-2.gif\",\"event\":1,\"method\":1},{\"url\":\"https://example.com/imp-3.gif\",\"event\":1,\"method\":1}],\"imptrackers\":[\"https://example.com/imp-1.gif\",\"https://example.com/imp-2.gif\"]}",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "cat": [
+                                        "IAB3-1"
+                                    ],
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adid": "29681110",
+                        "adm": "{\"assets\":[{\"id\":123,\"required\":1,\"title\":{\"text\":\"Learn about this awesome thing\"}},{\"id\":124,\"required\":1,\"img\":{\"url\":\"http://www.myads.com/thumbnail1.png\"}},{\"id\":128,\"required\":1,\"img\":{\"url\":\"http://www.myads.com/largethumb1.png\"}},{\"id\":126,\"required\":1,\"data\":{\"value\":\"My Brand\"}},{\"id\":127,\"required\":1,\"data\":{\"value\":\"Learn all about this awesome story of someone using my product.\"}}],\"link\":{\"url\":\"http: //i.am.a/URL\"},\"imptrackers\":[\"https://example.com/imp-1.gif\",\"https://example.com/imp-2.gif\",\"https://example.com/imp-3.gif\"],\"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"https://example.com/imp-2.gif\"},{\"event\":1,\"method\":1,\"url\":\"https://example.com/imp-3.gif\"}]}",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "cat": [
+                            "IAB3-1"
+                        ],
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "native"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/supplemental/bad-imp-id.json b/adapters/ix/ixtest/supplemental/bad-imp-id.json
index 0b852c85..1ca053b6 100644
--- a/adapters/ix/ixtest/supplemental/bad-imp-id.json
+++ b/adapters/ix/ixtest/supplemental/bad-imp-id.json
@@ -111,7 +111,7 @@
     ],
     "expectedMakeBidsErrors": [
         {
-            "value": "Unmatched impression id: bad-imp-id.",
+            "value": "unmatched impression id: bad-imp-id",
             "comparison": "literal"
         }
     ]
diff --git a/adapters/ix/ixtest/supplemental/native-eventtrackers-empty.json b/adapters/ix/ixtest/supplemental/native-eventtrackers-empty.json
new file mode 100644
index 00000000..4cf314e7
--- /dev/null
+++ b/adapters/ix/ixtest/supplemental/native-eventtrackers-empty.json
@@ -0,0 +1,104 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "native": {
+                    "request": "{}",
+                    "ver": "1.1"
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpcalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "native": {
+                                "request": "{}",
+                                "ver": "1.1"
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "{\"native\":{\"assets\":[{\"id\":123,\"required\":1,\"title\":{\"text\":\"Learn about this awesome thing\"}},{\"id\":124,\"required\":1,\"img\":{\"url\":\"http://www.myads.com/thumbnail1.png\"}},{\"id\":128,\"required\":1,\"img\":{\"url\":\"http://www.myads.com/largethumb1.png\"}},{\"id\":126,\"required\":1,\"data\":{\"value\":\"My Brand\"}},{\"id\":127,\"required\":1,\"data\":{\"value\":\"Learn all about this awesome story of someone using my product.\"}}],\"link\":{\"url\":\"http: //i.am.a/URL\"},\"imptrackers\":[\"https://example.com/imp-1.gif\",\"https://example.com/imp-2.gif\"],\"eventtrackers\":[]}}",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "cat": [
+                                        "IAB3-1"
+                                    ],
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adid": "29681110",
+                        "adm": "{\"native\":{\"assets\":[{\"id\":123,\"required\":1,\"title\":{\"text\":\"Learn about this awesome thing\"}},{\"id\":124,\"required\":1,\"img\":{\"url\":\"http://www.myads.com/thumbnail1.png\"}},{\"id\":128,\"required\":1,\"img\":{\"url\":\"http://www.myads.com/largethumb1.png\"}},{\"id\":126,\"required\":1,\"data\":{\"value\":\"My Brand\"}},{\"id\":127,\"required\":1,\"data\":{\"value\":\"Learn all about this awesome story of someone using my product.\"}}],\"link\":{\"url\":\"http: //i.am.a/URL\"},\"imptrackers\":[\"https://example.com/imp-1.gif\",\"https://example.com/imp-2.gif\"],\"eventtrackers\":[]}}",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "cat": [
+                            "IAB3-1"
+                        ],
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "native"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/supplemental/native-eventtrackers-missing.json b/adapters/ix/ixtest/supplemental/native-eventtrackers-missing.json
new file mode 100644
index 00000000..d8c78a5c
--- /dev/null
+++ b/adapters/ix/ixtest/supplemental/native-eventtrackers-missing.json
@@ -0,0 +1,104 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "native": {
+                    "request": "{}",
+                    "ver": "1.1"
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpcalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "native": {
+                                "request": "{}",
+                                "ver": "1.1"
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "{\"native\":{\"assets\":[{\"id\":123,\"required\":1,\"title\":{\"text\":\"Learn about this awesome thing\"}},{\"id\":124,\"required\":1,\"img\":{\"url\":\"http://www.myads.com/thumbnail1.png\"}},{\"id\":128,\"required\":1,\"img\":{\"url\":\"http://www.myads.com/largethumb1.png\"}},{\"id\":126,\"required\":1,\"data\":{\"value\":\"My Brand\"}},{\"id\":127,\"required\":1,\"data\":{\"value\":\"Learn all about this awesome story of someone using my product.\"}}],\"link\":{\"url\":\"http: //i.am.a/URL\"},\"imptrackers\":[\"https://example.com/imp-1.gif\",\"https://example.com/imp-2.gif\"]}}",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "cat": [
+                                        "IAB3-1"
+                                    ],
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adid": "29681110",
+                        "adm": "{\"native\":{\"assets\":[{\"id\":123,\"required\":1,\"title\":{\"text\":\"Learn about this awesome thing\"}},{\"id\":124,\"required\":1,\"img\":{\"url\":\"http://www.myads.com/thumbnail1.png\"}},{\"id\":128,\"required\":1,\"img\":{\"url\":\"http://www.myads.com/largethumb1.png\"}},{\"id\":126,\"required\":1,\"data\":{\"value\":\"My Brand\"}},{\"id\":127,\"required\":1,\"data\":{\"value\":\"Learn all about this awesome story of someone using my product.\"}}],\"link\":{\"url\":\"http: //i.am.a/URL\"},\"imptrackers\":[\"https://example.com/imp-1.gif\",\"https://example.com/imp-2.gif\"]}}",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "cat": [
+                            "IAB3-1"
+                        ],
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "native"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/ix/ixtest/supplemental/native-missing.json b/adapters/ix/ixtest/supplemental/native-missing.json
new file mode 100644
index 00000000..ec2108ce
--- /dev/null
+++ b/adapters/ix/ixtest/supplemental/native-missing.json
@@ -0,0 +1,104 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "native": {
+                    "request": "{}",
+                    "ver": "1.1"
+                },
+                "ext": {
+                    "bidder": {
+                        "siteId": "569749"
+                    }
+                }
+            }
+        ]
+    },
+    "httpcalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://host/endpoint",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "native": {
+                                "request": "{}",
+                                "ver": "1.1"
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "siteId": "569749"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "958",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "29681110",
+                                    "adm": "{\"native\":{}}",
+                                    "adomain": [
+                                        "https://advertiser.example.com"
+                                    ],
+                                    "cid": "958",
+                                    "crid": "29681110",
+                                    "cat": [
+                                        "IAB3-1"
+                                    ],
+                                    "ext": {
+                                        "ix": {}
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adid": "29681110",
+                        "adm": "{\"native\":{}}",
+                        "adomain": [
+                            "https://advertiser.example.com"
+                        ],
+                        "cid": "958",
+                        "crid": "29681110",
+                        "cat": [
+                            "IAB3-1"
+                        ],
+                        "ext": {
+                            "ix": {}
+                        }
+                    },
+                    "type": "native"
+                }
+            ]
+        }
+    ]
+}
diff --git a/adapters/outbrain/outbraintest/supplemental/general_params.json b/adapters/outbrain/outbraintest/supplemental/general_params.json
new file mode 100644
index 00000000..b2a547c8
--- /dev/null
+++ b/adapters/outbrain/outbraintest/supplemental/general_params.json
@@ -0,0 +1,139 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "tagid": "tag-id",
+        "ext": {
+          "bidder": {
+            "publisher": {
+              "id": "publisher-id"
+            }
+          }
+        }
+      }
+    ],
+    "bcat": ["bad-category"],
+    "badv": ["bad-advertiser"],
+    "site": {
+      "page": "http://example.com"
+    },
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36",
+      "h": 500,
+      "w": 1000
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com/bid",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  }
+                ]
+              },
+              "tagid": "tag-id",
+              "ext": {
+                "bidder": {
+                  "publisher": {
+                    "id": "publisher-id"
+                  }
+                }
+              }
+            }
+          ],
+          "bcat": ["bad-category"],
+          "badv": ["bad-advertiser"],
+          "site": {
+            "page": "http://example.com",
+            "publisher": {
+              "id": "publisher-id"
+            }
+          },
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36",
+            "h": 500,
+            "w": 1000
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "5095a742-1c27-402b-ab6f-66b1bd53383b",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test-request-id",
+                  "impid": "test-imp-id",
+                  "price": 1000,
+                  "nurl": "http://example.com/win/1000",
+                  "adm": "<div>ad</div>",
+                  "adomain": [
+                    "example.com"
+                  ],
+                  "cid": "test-cid",
+                  "crid": "test-crid",
+                  "cat": [
+                    "IAB13-4"
+                  ],
+                  "w": 300,
+                  "h": 250
+                }
+              ],
+              "seat": "acc-1876"
+            }
+          ],
+          "bidid": "43ccadf2-8b2e-11eb-b294-de4c49e99ff6",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test-request-id",
+            "impid": "test-imp-id",
+            "price": 1000,
+            "nurl": "http://example.com/win/1000",
+            "adm": "<div>ad</div>",
+            "adomain": [
+              "example.com"
+            ],
+            "cid": "test-cid",
+            "crid": "test-crid",
+            "cat": [
+              "IAB13-4"
+            ],
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/outbrain/outbraintest/supplemental/optional_params.json b/adapters/outbrain/outbraintest/supplemental/optional_params.json
index a69ceaa0..d75875e0 100644
--- a/adapters/outbrain/outbraintest/supplemental/optional_params.json
+++ b/adapters/outbrain/outbraintest/supplemental/optional_params.json
@@ -12,6 +12,7 @@
             }
           ]
         },
+        "tagid": "should-be-overwritten-tagid",
         "ext": {
           "bidder": {
             "publisher": {
@@ -26,6 +27,8 @@
         }
       }
     ],
+    "bcat": ["should-be-overwritten-bcat"],
+    "badv": ["should-be-overwritten-badv"],
     "site": {
       "page": "http://example.com"
     },
diff --git a/adapters/rubicon/rubicon_test.go b/adapters/rubicon/rubicon_test.go
index dc5b3a90..76904a42 100644
--- a/adapters/rubicon/rubicon_test.go
+++ b/adapters/rubicon/rubicon_test.go
@@ -572,6 +572,52 @@ func TestResolveVideoSizeId(t *testing.T) {
 	}
 }
 
+func TestResolveBidFloorAttributes(t *testing.T) {
+	testScenarios := []struct {
+		bidFloor            float64
+		bidFloorCur         string
+		expectedBidFloor    float64
+		expectedBidFloorCur string
+	}{
+		{
+			bidFloor:            1,
+			bidFloorCur:         "EUR",
+			expectedBidFloor:    1.2,
+			expectedBidFloorCur: "USD",
+		},
+		{
+			bidFloor:            1,
+			bidFloorCur:         "Eur",
+			expectedBidFloor:    1.2,
+			expectedBidFloorCur: "USD",
+		},
+		{
+			bidFloor:            0,
+			bidFloorCur:         "EUR",
+			expectedBidFloor:    0,
+			expectedBidFloorCur: "EUR",
+		},
+		{
+			bidFloor:            -1,
+			bidFloorCur:         "EUR",
+			expectedBidFloor:    -1,
+			expectedBidFloorCur: "EUR",
+		},
+		{
+			bidFloor:            1,
+			bidFloorCur:         "USD",
+			expectedBidFloor:    1,
+			expectedBidFloorCur: "USD",
+		},
+	}
+
+	for _, scenario := range testScenarios {
+		bidFloor, bidFloorCur := resolveBidFloorAttributes(scenario.bidFloor, scenario.bidFloorCur)
+		assert.Equal(t, scenario.expectedBidFloor, bidFloor)
+		assert.Equal(t, scenario.expectedBidFloorCur, bidFloorCur)
+	}
+}
+
 func TestNoContentResponse(t *testing.T) {
 	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		w.WriteHeader(http.StatusNoContent)
@@ -989,15 +1035,15 @@ func TestOpenRTBRequest(t *testing.T) {
 				}
 			}}`),
 		}},
+		App: &openrtb2.App{
+			ID:   "com.test",
+			Name: "testApp",
+		},
 		Device: &openrtb2.Device{
 			PxRatio: rubidata.devicePxRatio,
 		},
 		User: &openrtb2.User{
-			Ext: json.RawMessage(`{"digitrust": {
-                    "id": "some-digitrust-id",
-                    "keyv": 1,
-                    "pref": 0
-                },
+			Ext: json.RawMessage(`{
 				"eids": [{
                     "source": "pubcid",
                     "id": "2402fc76-7b39-4f0e-bfc2-060ef7693648"
@@ -1071,10 +1117,6 @@ func TestOpenRTBRequest(t *testing.T) {
 			t.Fatal("Error unmarshalling request.user.ext object.")
 		}
 
-		assert.Equal(t, "some-digitrust-id", userExt.DigiTrust.ID, "DigiTrust ID id not as expected!")
-		assert.Equal(t, 1, userExt.DigiTrust.KeyV, "DigiTrust KeyV id not as expected!")
-		assert.Equal(t, 0, userExt.DigiTrust.Pref, "DigiTrust Pref id not as expected!")
-
 		assert.NotNil(t, userExt.Eids)
 		assert.Equal(t, 1, len(userExt.Eids), "Eids values are not as expected!")
 		assert.Contains(t, userExt.Eids, openrtb_ext.ExtUserEid{Source: "pubcid", ID: "2402fc76-7b39-4f0e-bfc2-060ef7693648"})
@@ -1108,6 +1150,10 @@ func TestOpenRTBRequestWithBannerImpEvenIfImpHasVideo(t *testing.T) {
 				"visitor": {"key2" : "val2"}
 			}}`),
 		}},
+		App: &openrtb2.App{
+			ID:   "com.test",
+			Name: "testApp",
+		},
 	}
 
 	reqs, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
@@ -1157,6 +1203,10 @@ func TestOpenRTBRequestWithImpAndAdSlotIncluded(t *testing.T) {
 				}
 			}`),
 		}},
+		App: &openrtb2.App{
+			ID:   "com.test",
+			Name: "testApp",
+		},
 	}
 
 	reqs, _ := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
@@ -1212,6 +1262,10 @@ func TestOpenRTBRequestWithBadvOverflowed(t *testing.T) {
 				}
 			}`),
 		}},
+		App: &openrtb2.App{
+			ID:   "com.test",
+			Name: "testApp",
+		},
 	}
 
 	reqs, _ := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
@@ -1245,6 +1299,10 @@ func TestOpenRTBRequestWithSpecificExtUserEids(t *testing.T) {
 				"accountId": 7891
 			}}`),
 		}},
+		App: &openrtb2.App{
+			ID:   "com.test",
+			Name: "testApp",
+		},
 		User: &openrtb2.User{
 			Ext: json.RawMessage(`{"eids": [
 			{
@@ -1353,6 +1411,10 @@ func TestOpenRTBRequestWithVideoImpEvenIfImpHasBannerButAllRequiredVideoFields(t
 				"video": {"size_id": 1}
 			}}`),
 		}},
+		App: &openrtb2.App{
+			ID:   "com.test",
+			Name: "testApp",
+		},
 	}
 
 	reqs, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
@@ -1398,6 +1460,10 @@ func TestOpenRTBRequestWithVideoImpAndEnabledRewardedInventoryFlag(t *testing.T)
 				"video": {"size_id": 1}
 			}}`),
 		}},
+		App: &openrtb2.App{
+			ID:   "com.test",
+			Name: "testApp",
+		},
 	}
 
 	reqs, _ := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
diff --git a/adapters/rubicon/rubicontest/exemplary/simple-video.json b/adapters/rubicon/rubicontest/exemplary/simple-video.json
index b85c28de..11afdd50 100644
--- a/adapters/rubicon/rubicontest/exemplary/simple-video.json
+++ b/adapters/rubicon/rubicontest/exemplary/simple-video.json
@@ -9,11 +9,50 @@
       "id": "1",
       "bundle": "com.wls.testwlsapplication"
     },
+    "site": {
+      "content": {
+        "data": [
+          {
+            "ext": {
+              "segtax": 1
+            },
+            "segment": [
+              {
+                "id": "segmentId1"
+              },
+              {
+                "id": "segmentId2"
+              }
+            ]
+          },
+          {
+            "ext": {
+              "segtax": "1"
+            },
+            "segment": [
+              {
+                "id": "shouldNotBeCopied"
+              }
+            ]
+          },
+          {
+            "ext": {
+              "segtax": 2
+            },
+            "segment": [
+              {
+                "id": "segmentId3"
+              }
+            ]
+          }
+        ]
+      }
+    },
     "user": {
       "data": [
         {
           "ext": {
-            "taxonomyname": "iab"
+            "segtax": 4
           },
           "segment": [
             {
@@ -23,7 +62,7 @@
         },
         {
           "ext": {
-            "taxonomyname": "someValue"
+            "segtax": "someValue"
           },
           "segment": [
             {
@@ -33,7 +72,17 @@
         },
         {
           "ext": {
-            "taxonomyname": "IaB"
+            "segtax": "4"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": 4
           },
           "segment": [
             {
@@ -43,13 +92,13 @@
         },
         {
           "ext": {
-            "taxonomyname": [
-              "wrong iab type"
+            "segtax": [
+              4
             ]
           },
           "segment": [
             {
-              "id": "shouldNotBeCopied2"
+              "id": "shouldNotBeCopied3"
             }
           ]
         }
@@ -71,6 +120,8 @@
           "w": 1024,
           "h": 576
         },
+        "bidfloor": 1,
+        "bidfloorcur": "EuR",
         "ext": {
           "bidder": {
             "video": {
@@ -98,11 +149,69 @@
             "ip": "123.123.123.123",
             "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
           },
+          "site": {
+            "content": {
+              "data": [
+                {
+                  "ext": {
+                    "segtax": 1
+                  },
+                  "segment": [
+                    {
+                      "id": "segmentId1"
+                    },
+                    {
+                      "id": "segmentId2"
+                    }
+                  ]
+                },
+                {
+                  "ext": {
+                    "segtax": "1"
+                  },
+                  "segment": [
+                    {
+                      "id": "shouldNotBeCopied"
+                    }
+                  ]
+                },
+                {
+                  "ext": {
+                    "segtax": 2
+                  },
+                  "segment": [
+                    {
+                      "id": "segmentId3"
+                    }
+                  ]
+                }
+              ]
+            },
+            "ext": {
+              "rp": {
+                "site_id": 113932,
+                "target": {
+                  "iab": [
+                    "segmentId1",
+                    "segmentId2",
+                    "segmentId3"
+                  ]
+                }
+              }
+            },
+            "publisher": {
+              "ext": {
+                "rp": {
+                  "account_id": 1001
+                }
+              }
+            }
+          },
           "user": {
             "data": [
               {
                 "ext": {
-                  "taxonomyname": "iab"
+                  "segtax": 4
                 },
                 "segment": [
                   {
@@ -112,7 +221,7 @@
               },
               {
                 "ext": {
-                  "taxonomyname": "someValue"
+                  "segtax": "someValue"
                 },
                 "segment": [
                   {
@@ -122,7 +231,17 @@
               },
               {
                 "ext": {
-                  "taxonomyname": "IaB"
+                  "segtax": "4"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": 4
                 },
                 "segment": [
                   {
@@ -132,19 +251,18 @@
               },
               {
                 "ext": {
-                  "taxonomyname": [
-                    "wrong iab type"
+                  "segtax": [
+                    4
                   ]
                 },
                 "segment": [
                   {
-                    "id": "shouldNotBeCopied2"
+                    "id": "shouldNotBeCopied3"
                   }
                 ]
               }
             ],
             "ext": {
-              "digitrust": null,
               "rp": {
                 "target": {
                   "iab": [
@@ -157,18 +275,6 @@
           },
           "app": {
             "id": "1",
-            "ext": {
-              "rp": {
-                "site_id": 113932
-              }
-            },
-            "publisher": {
-              "ext": {
-                "rp": {
-                  "account_id": 1001
-                }
-              }
-            },
             "bundle": "com.wls.testwlsapplication"
           },
           "imp": [
@@ -192,6 +298,8 @@
                 "w": 1024,
                 "h": 576
               },
+              "bidfloor": 1.2,
+              "bidfloorcur": "USD",
               "ext": {
                 "rp": {
                   "track": {
diff --git a/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json b/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json
new file mode 100644
index 00000000..f67788a3
--- /dev/null
+++ b/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json
@@ -0,0 +1,293 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    },
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "site": {
+      "content": {
+      }
+    },
+    "user": {
+      "data": [
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "someValue"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "4"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": [
+              4
+            ]
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied3"
+            }
+          ]
+        }
+      ]
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "instl": 1,
+        "video": {
+          "placement": 3,
+          "mimes": [
+            "video/mp4"
+          ],
+          "protocols": [
+            2,
+            5
+          ],
+          "w": 1024,
+          "h": 576
+        },
+        "bidfloor": 1,
+        "bidfloorcur": "EuR",
+        "ext": {
+          "bidder": {
+            "video": {
+            },
+            "accountId": 1001,
+            "siteId": 113932,
+            "zoneId": 535510
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "uri?tk_xint=pbs-test-tracker",
+        "body": {
+          "id": "test-request-id",
+          "device": {
+            "ext": {
+              "rp": {
+                "pixelratio": 0
+              }
+            },
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          },
+          "site": {
+            "content": {
+            },
+            "ext": {
+              "rp": {
+                "site_id": 113932
+              }
+            },
+            "publisher": {
+              "ext": {
+                "rp": {
+                  "account_id": 1001
+                }
+              }
+            }
+          },
+          "user": {
+            "data": [
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "someValue"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "4"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": [
+                    4
+                  ]
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied3"
+                  }
+                ]
+              }
+            ],
+            "ext": {
+              "rp": {
+                "target": {
+                  "iab": [
+                    "idToCopy",
+                    "idToCopy2"
+                  ]
+                }
+              }
+            }
+          },
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "instl": 1,
+              "video": {
+                "placement": 3,
+                "ext": {
+                  "rp": {
+                    "size_id": 203
+                  }
+                },
+                "mimes": [
+                  "video/mp4"
+                ],
+                "protocols": [
+                  2,
+                  5
+                ],
+                "w": 1024,
+                "h": 576
+              },
+              "bidfloor": 1.2,
+              "bidfloorcur": "USD",
+              "ext": {
+                "rp": {
+                  "track": {
+                    "mint": "",
+                    "mint_version": ""
+                  },
+                  "zone_id": 535510
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test_bid_id",
+                  "impid": "test-imp-id",
+                  "price": 0.27543,
+                  "adm": "some-test-ad",
+                  "cid": "test_cid",
+                  "crid": "test_crid",
+                  "dealid": "test_dealid",
+                  "ext": {
+                    "prebid": {
+                      "type": "video"
+                    }
+                  }
+                }
+              ],
+              "seat": "adman"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "some-test-ad",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/rubicon/rubicontest/supplemental/no-site-content.json b/adapters/rubicon/rubicontest/supplemental/no-site-content.json
new file mode 100644
index 00000000..d3b8f8b7
--- /dev/null
+++ b/adapters/rubicon/rubicontest/supplemental/no-site-content.json
@@ -0,0 +1,289 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    },
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "site": {
+    },
+    "user": {
+      "data": [
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "someValue"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "4"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": [
+              4
+            ]
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied3"
+            }
+          ]
+        }
+      ]
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "instl": 1,
+        "video": {
+          "placement": 3,
+          "mimes": [
+            "video/mp4"
+          ],
+          "protocols": [
+            2,
+            5
+          ],
+          "w": 1024,
+          "h": 576
+        },
+        "bidfloor": 1,
+        "bidfloorcur": "EuR",
+        "ext": {
+          "bidder": {
+            "video": {
+            },
+            "accountId": 1001,
+            "siteId": 113932,
+            "zoneId": 535510
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "uri?tk_xint=pbs-test-tracker",
+        "body": {
+          "id": "test-request-id",
+          "device": {
+            "ext": {
+              "rp": {
+                "pixelratio": 0
+              }
+            },
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          },
+          "site": {
+            "ext": {
+              "rp": {
+                "site_id": 113932
+              }
+            },
+            "publisher": {
+              "ext": {
+                "rp": {
+                  "account_id": 1001
+                }
+              }
+            }
+          },
+          "user": {
+            "data": [
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "someValue"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "4"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": [
+                    4
+                  ]
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied3"
+                  }
+                ]
+              }
+            ],
+            "ext": {
+              "rp": {
+                "target": {
+                  "iab": [
+                    "idToCopy",
+                    "idToCopy2"
+                  ]
+                }
+              }
+            }
+          },
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "instl": 1,
+              "video": {
+                "placement": 3,
+                "ext": {
+                  "rp": {
+                    "size_id": 203
+                  }
+                },
+                "mimes": [
+                  "video/mp4"
+                ],
+                "protocols": [
+                  2,
+                  5
+                ],
+                "w": 1024,
+                "h": 576
+              },
+              "bidfloor": 1.2,
+              "bidfloorcur": "USD",
+              "ext": {
+                "rp": {
+                  "track": {
+                    "mint": "",
+                    "mint_version": ""
+                  },
+                  "zone_id": 535510
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test_bid_id",
+                  "impid": "test-imp-id",
+                  "price": 0.27543,
+                  "adm": "some-test-ad",
+                  "cid": "test_cid",
+                  "crid": "test_crid",
+                  "dealid": "test_dealid",
+                  "ext": {
+                    "prebid": {
+                      "type": "video"
+                    }
+                  }
+                }
+              ],
+              "seat": "adman"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "some-test-ad",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/sa_lunamedia/params_test.go b/adapters/sa_lunamedia/params_test.go
new file mode 100644
index 00000000..bf7a1f49
--- /dev/null
+++ b/adapters/sa_lunamedia/params_test.go
@@ -0,0 +1,52 @@
+package salunamedia
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+var validParams = []string{
+	`{ "key": "2", "type": "network"}`,
+	`{ "key": "1"}`,
+	`{ "key": "33232", "type": "publisher"}`,
+}
+
+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.BidderSaLunaMedia, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected sa_lunamedia params: %s", validParam)
+		}
+	}
+}
+
+var invalidParams = []string{
+	``,
+	`null`,
+	`true`,
+	`5`,
+	`[]`,
+	`{}`,
+	`{ "anyparam": "anyvalue" }`,
+	`{ "type": "network" }`,
+	`{ "key": "asddsfd", "type": "any"}`,
+}
+
+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.BidderSaLunaMedia, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
diff --git a/adapters/sa_lunamedia/salunamedia_test.go b/adapters/sa_lunamedia/salunamedia_test.go
new file mode 100644
index 00000000..f5d20582
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamedia_test.go
@@ -0,0 +1,18 @@
+package salunamedia
+
+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.BidderSaLunaMedia, config.Adapter{
+		Endpoint: "http://test.com/pserver"})
+
+	assert.NoError(t, buildErr)
+	adapterstest.RunJSONBidderTest(t, "salunamediatest", bidder)
+}
diff --git a/adapters/sa_lunamedia/salunamediatest/exemplary/banner.json b/adapters/sa_lunamedia/salunamediatest/exemplary/banner.json
new file mode 100644
index 00000000..2ce4ad81
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/exemplary/banner.json
@@ -0,0 +1,142 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [{
+            "id": "id",
+            "secure": 1,
+            "bidfloor": 0.01,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "key": "test"
+              }
+            }
+          }],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": ["IAB12"],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "id",
+          "bidid": "id",
+          "seatbid": [{
+            "bid": [{
+              "id": "id",
+              "impid": "id",
+              "price": 0.1,
+              "nurl": "http://test.com/nurl",
+              "burl": "http://test.com/burl",
+              "adm": "<span>Test</span>",
+              "adomain": ["test.com"],
+              "cat": ["IAB1"],
+              "cid": "cid",
+              "crid": "crid",
+              "w": 300,
+              "h": 250,
+              "ext": {
+                "mediaType": "banner"
+              }
+            }],
+            "seat": "seat"
+          }],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "id",
+            "impid": "id",
+            "price": 0.1,
+            "nurl": "http://test.com/nurl",
+            "burl": "http://test.com/burl",
+            "adm": "<span>Test</span>",
+            "adomain": ["test.com"],
+            "cat": ["IAB1"],
+            "cid": "cid",
+            "crid": "crid",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "mediaType": "banner"
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/exemplary/native.json b/adapters/sa_lunamedia/salunamediatest/exemplary/native.json
new file mode 100644
index 00000000..74d8940f
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/exemplary/native.json
@@ -0,0 +1,132 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "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": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://test.com/pserver",
+      "body": {
+        "id": "id",
+        "imp": [{
+          "id": "id",
+          "secure": 1,
+          "bidfloor": 0.01,
+          "bidfloorcur": "USD",
+          "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": {
+              "key": "test"
+            }
+          }
+        }],
+        "device": {
+          "ua": "UA",
+          "ip": "123.3.4.123"
+        },
+        "regs": {
+          "ext": {
+            "gdpr": 0
+          }
+        },
+        "user": {
+          "id": "userid"
+        },
+        "site": {
+          "id": "id",
+          "domain": "test,com",
+          "cat": ["IAB12"],
+          "publisher": {
+            "id": "pubid"
+          }
+        }
+      }
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": {
+        "id": "id",
+        "bidid": "id",
+        "seatbid": [{
+          "bid": [{
+            "id": "id",
+            "impid": "id",
+            "price": 0.1,
+            "nurl": "http://test.com/nurl",
+            "burl": "http://test.com/burl",
+            "adm": "{}",
+            "adomain": ["test.com"],
+            "cat": ["IAB1"],
+            "cid": "cid",
+            "crid": "crid",
+            "ext": {
+              "mediaType": "native"
+            }
+          }],
+          "seat": "seat"
+        }],
+        "cur": "USD"
+      }
+    }
+  }],
+
+  "expectedBidResponses": [{
+    "currency": "USD",
+    "bids": [{
+      "bid": {
+        "id": "id",
+        "impid": "id",
+        "price": 0.1,
+        "nurl": "http://test.com/nurl",
+        "burl": "http://test.com/burl",
+        "adm": "{}",
+        "adomain": ["test.com"],
+        "cat": ["IAB1"],
+        "cid": "cid",
+        "crid": "crid",
+        "ext": {
+          "mediaType": "native"
+        }
+      },
+      "type": "native"
+    }]
+  }]
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/exemplary/video.json b/adapters/sa_lunamedia/salunamediatest/exemplary/video.json
new file mode 100644
index 00000000..9a042d72
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/exemplary/video.json
@@ -0,0 +1,169 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "video": {
+        "mimes": ["video/mp4", "video/ogg", "video/webm"],
+        "minduration": 3,
+        "maxduration": 3000,
+        "protocols": [2, 3, 5, 6, 7, 8],
+        "w": 480,
+        "h": 320,
+        "linearity": 1,
+        "playbackmethod": [2],
+        "pos": 0
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [
+            {
+              "id": "id",
+              "secure": 1,
+              "bidfloor": 0.01,
+              "bidfloorcur": "USD",
+              "video": {
+                "mimes": [
+                  "video/mp4",
+                  "video/ogg",
+                  "video/webm"
+                ],
+                "minduration": 3,
+                "maxduration": 3000,
+                "protocols": [
+                  2,
+                  3,
+                  5,
+                  6,
+                  7,
+                  8
+                ],
+                "w": 480,
+                "h": 320,
+                "linearity": 1,
+                "playbackmethod": [
+                  2
+                ],
+                "pos": 0
+              },
+              "ext": {
+                "bidder": {
+                  "key": "test"
+                }
+              }
+            }
+          ],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": [
+              "IAB12"
+            ],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "id",
+          "bidid": "id",
+          "seatbid": [{
+            "bid": [{
+              "id": "id",
+              "impid": "id",
+              "price": 0.1,
+              "nurl": "http://test.com/nurl",
+              "burl": "http://test.com/burl",
+              "adm": "<VAST>",
+              "adomain": ["test.com"],
+              "cat": ["IAB1"],
+              "cid": "cid",
+              "crid": "crid",
+              "ext": {
+                "mediaType": "video"
+              }
+            }],
+            "seat": "seat"
+          }],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "id",
+            "impid": "id",
+            "price": 0.1,
+            "nurl": "http://test.com/nurl",
+            "burl": "http://test.com/burl",
+            "adm": "<VAST>",
+            "adomain": ["test.com"],
+            "cat": ["IAB1"],
+            "cid": "cid",
+            "crid": "crid",
+            "ext": {
+              "mediaType": "video"
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/params/race/banner.json b/adapters/sa_lunamedia/salunamediatest/params/race/banner.json
new file mode 100644
index 00000000..c02a5de9
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/params/race/banner.json
@@ -0,0 +1,3 @@
+{
+  "key": "test"
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/params/race/native.json b/adapters/sa_lunamedia/salunamediatest/params/race/native.json
new file mode 100644
index 00000000..c02a5de9
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/params/race/native.json
@@ -0,0 +1,3 @@
+{
+  "key": "test"
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/params/race/video.json b/adapters/sa_lunamedia/salunamediatest/params/race/video.json
new file mode 100644
index 00000000..c02a5de9
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/params/race/video.json
@@ -0,0 +1,3 @@
+{
+  "key": "test"
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/supplemental/bad-response.json b/adapters/sa_lunamedia/salunamediatest/supplemental/bad-response.json
new file mode 100644
index 00000000..6373207d
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/supplemental/bad-response.json
@@ -0,0 +1,98 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [{
+            "id": "id",
+            "secure": 1,
+            "bidfloor": 0.01,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "key": "test"
+              }
+            }
+          }],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": ["IAB12"],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": ""
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "json: cannot unmarshal string into Go value of type openrtb2.BidResponse",
+      "comparison": "literal"
+    }
+  ],
+
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/supplemental/empty-seatbid.json b/adapters/sa_lunamedia/salunamediatest/supplemental/empty-seatbid.json
new file mode 100644
index 00000000..8942b3be
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/supplemental/empty-seatbid.json
@@ -0,0 +1,102 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://test.com/pserver",
+      "body": {
+        "id": "id",
+        "imp": [{
+          "id": "id",
+          "secure": 1,
+          "bidfloor": 0.01,
+          "bidfloorcur": "USD",
+          "banner": {
+            "w": 300,
+            "h": 250
+          },
+          "ext": {
+            "bidder": {
+              "key": "test"
+            }
+          }
+        }],
+        "device": {
+          "ua": "UA",
+          "ip": "123.3.4.123"
+        },
+        "regs": {
+          "ext": {
+            "gdpr": 0
+          }
+        },
+        "user": {
+          "id": "userid"
+        },
+        "site": {
+          "id": "id",
+          "domain": "test,com",
+          "cat": ["IAB12"],
+          "publisher": {
+            "id": "pubid"
+          }
+        }
+      }
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": {
+        "id": "a1580f2f-be6d-11eb-a150-d094662c1c35",
+        "bidid": "359da97d0384d8a14767029c18fd840d",
+        "seatbid": [],
+        "cur": "USD"
+      }
+    }
+  }],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Empty SeatBid",
+      "comparison": "literal"
+    }
+  ],
+
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/supplemental/status-204.json b/adapters/sa_lunamedia/salunamediatest/supplemental/status-204.json
new file mode 100644
index 00000000..042b96bd
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/supplemental/status-204.json
@@ -0,0 +1,92 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [{
+            "id": "id",
+            "secure": 1,
+            "bidfloor": 0.01,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "key": "test"
+              }
+            }
+          }],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": ["IAB12"],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 204,
+        "body": {}
+      }
+    }
+  ],
+
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/supplemental/status-400.json b/adapters/sa_lunamedia/salunamediatest/supplemental/status-400.json
new file mode 100644
index 00000000..1ecdc46e
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/supplemental/status-400.json
@@ -0,0 +1,99 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [{
+            "id": "id",
+            "secure": 1,
+            "bidfloor": 0.01,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "key": "test"
+              }
+            }
+          }],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": ["IAB12"],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 400,
+        "body": "The Key has a different ad format"
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bad Request. \"The Key has a different ad format\"",
+      "comparison": "literal"
+    }
+  ],
+
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/supplemental/status-503.json b/adapters/sa_lunamedia/salunamediatest/supplemental/status-503.json
new file mode 100644
index 00000000..2590418a
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/supplemental/status-503.json
@@ -0,0 +1,98 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [{
+            "id": "id",
+            "secure": 1,
+            "bidfloor": 0.01,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "key": "test"
+              }
+            }
+          }],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": ["IAB12"],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 503
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bidder unavailable. Please contact the bidder support.",
+      "comparison": "literal"
+    }
+  ],
+
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/supplemental/unexpected-status.json b/adapters/sa_lunamedia/salunamediatest/supplemental/unexpected-status.json
new file mode 100644
index 00000000..a54737ca
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/supplemental/unexpected-status.json
@@ -0,0 +1,99 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [{
+            "id": "id",
+            "secure": 1,
+            "bidfloor": 0.01,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "key": "test"
+              }
+            }
+          }],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": ["IAB12"],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 403,
+        "body": "Access is denied"
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Status Code: [ 403 ] \"Access is denied\"",
+      "comparison": "literal"
+    }
+  ],
+
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/usersync_test.go b/adapters/sa_lunamedia/usersync_test.go
new file mode 100644
index 00000000..e3820fbc
--- /dev/null
+++ b/adapters/sa_lunamedia/usersync_test.go
@@ -0,0 +1,33 @@
+package salunamedia
+
+import (
+	"testing"
+	"text/template"
+
+	"github.com/prebid/prebid-server/privacy"
+	"github.com/prebid/prebid-server/privacy/ccpa"
+	"github.com/prebid/prebid-server/privacy/gdpr"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewSaLunamediaSyncer(t *testing.T) {
+	syncURL := "https://test.com/pserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}"
+	syncURLTemplate := template.Must(
+		template.New("sync-template").Parse(syncURL),
+	)
+	syncer := NewSaLunamediaSyncer(syncURLTemplate)
+	syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{
+		GDPR: gdpr.Policy{
+			Signal:  "0",
+			Consent: "allGdpr",
+		},
+		CCPA: ccpa.Policy{
+			Consent: "1---",
+		},
+	})
+
+	assert.NoError(t, err)
+	assert.Equal(t, "https://test.com/pserver?gdpr=0&gdpr_consent=allGdpr&ccpa=1---", syncInfo.URL)
+	assert.Equal(t, "redirect", syncInfo.Type)
+	assert.Equal(t, false, syncInfo.SupportCORS)
+}
diff --git a/config/config_test.go b/config/config_test.go
index fa9dcdc5..c33a345c 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -147,6 +147,30 @@ gdpr:
   host_vendor_id: 15
   default_value: "1"
   non_standard_publishers: ["siteID","fake-site-id","appID","agltb3B1Yi1pbmNyDAsSA0FwcBiJkfIUDA"]
+  tcf2:
+    purpose1:
+      vendor_exceptions: ["foo1a", "foo1b"]
+    purpose2:
+      enabled: false
+      vendor_exceptions: ["foo2"]
+    purpose3:
+      vendor_exceptions: ["foo3"]
+    purpose4:
+      vendor_exceptions: ["foo4"]
+    purpose5:
+      vendor_exceptions: ["foo5"]
+    purpose6:
+      vendor_exceptions: ["foo6"]
+    purpose7:
+      vendor_exceptions: ["foo7"]
+    purpose8:
+      vendor_exceptions: ["foo8"]
+    purpose9:
+      vendor_exceptions: ["foo9"]
+    purpose10:
+      vendor_exceptions: ["foo10"]
+    special_purpose1:
+      vendor_exceptions: ["fooSP1"]
 ccpa:
   enforce: true
 lmt:
@@ -378,6 +402,71 @@ func TestFullConfig(t *testing.T) {
 		cmpBools(t, "cfg.BlacklistedAppMap", cfg.BlacklistedAppMap[cfg.BlacklistedApps[i]], true)
 	}
 
+	//Assert purpose VendorExceptionMap hash tables were built correctly
+	expectedTCF2 := TCF2{
+		Enabled: true,
+		Purpose1: TCF2Purpose{
+			Enabled:            true, // true by default
+			VendorExceptions:   []openrtb_ext.BidderName{openrtb_ext.BidderName("foo1a"), openrtb_ext.BidderName("foo1b")},
+			VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo1a"): {}, openrtb_ext.BidderName("foo1b"): {}},
+		},
+		Purpose2: TCF2Purpose{
+			Enabled:            false,
+			VendorExceptions:   []openrtb_ext.BidderName{openrtb_ext.BidderName("foo2")},
+			VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo2"): {}},
+		},
+		Purpose3: TCF2Purpose{
+			Enabled:            true, // true by default
+			VendorExceptions:   []openrtb_ext.BidderName{openrtb_ext.BidderName("foo3")},
+			VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo3"): {}},
+		},
+		Purpose4: TCF2Purpose{
+			Enabled:            true, // true by default
+			VendorExceptions:   []openrtb_ext.BidderName{openrtb_ext.BidderName("foo4")},
+			VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo4"): {}},
+		},
+		Purpose5: TCF2Purpose{
+			Enabled:            true, // true by default
+			VendorExceptions:   []openrtb_ext.BidderName{openrtb_ext.BidderName("foo5")},
+			VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo5"): {}},
+		},
+		Purpose6: TCF2Purpose{
+			Enabled:            true, // true by default
+			VendorExceptions:   []openrtb_ext.BidderName{openrtb_ext.BidderName("foo6")},
+			VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo6"): {}},
+		},
+		Purpose7: TCF2Purpose{
+			Enabled:            true, // true by default
+			VendorExceptions:   []openrtb_ext.BidderName{openrtb_ext.BidderName("foo7")},
+			VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo7"): {}},
+		},
+		Purpose8: TCF2Purpose{
+			Enabled:            true, // true by default
+			VendorExceptions:   []openrtb_ext.BidderName{openrtb_ext.BidderName("foo8")},
+			VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo8"): {}},
+		},
+		Purpose9: TCF2Purpose{
+			Enabled:            true, // true by default
+			VendorExceptions:   []openrtb_ext.BidderName{openrtb_ext.BidderName("foo9")},
+			VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo9"): {}},
+		},
+		Purpose10: TCF2Purpose{
+			Enabled:            true, // true by default
+			VendorExceptions:   []openrtb_ext.BidderName{openrtb_ext.BidderName("foo10")},
+			VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo10"): {}},
+		},
+		SpecialPurpose1: TCF2Purpose{
+			Enabled:            true, // true by default
+			VendorExceptions:   []openrtb_ext.BidderName{openrtb_ext.BidderName("fooSP1")},
+			VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("fooSP1"): {}},
+		},
+		PurposeOneTreatment: TCF2PurposeOneTreatment{
+			Enabled:       true, // true by default
+			AccessAllowed: true, // true by default
+		},
+	}
+	assert.Equal(t, expectedTCF2, cfg.GDPR.TCF2, "gdpr.tcf2")
+
 	cmpStrings(t, "currency_converter.fetch_url", cfg.CurrencyConverter.FetchURL, "https://currency.prebid.org")
 	cmpInts(t, "currency_converter.fetch_interval_seconds", cfg.CurrencyConverter.FetchIntervalSeconds, 1800)
 	cmpStrings(t, "recaptcha_secret", cfg.RecaptchaSecret, "asdfasdfasdfasdf")
diff --git a/currency/aggregate_conversions_test.go b/currency/aggregate_conversions_test.go
index 35ca51a1..773a596c 100644
--- a/currency/aggregate_conversions_test.go
+++ b/currency/aggregate_conversions_test.go
@@ -65,7 +65,7 @@ func TestGroupedGetRate(t *testing.T) {
 			},
 		},
 		{
-			expectedError: ConversionRateNotFound{"GBP", "EUR"},
+			expectedError: ConversionNotFoundError{FromCur: "GBP", ToCur: "EUR"},
 			testCases: []aTest{
 				{"Valid three-digit currency codes, but conversion rate not found", "GBP", "EUR", 0},
 			},
diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go
index 079b9adb..61164bd7 100644
--- a/endpoints/openrtb2/amp_auction_test.go
+++ b/endpoints/openrtb2/amp_auction_test.go
@@ -32,7 +32,6 @@ func TestGoodAmpRequests(t *testing.T) {
 	goodRequests := map[string]json.RawMessage{
 		"1": json.RawMessage(validRequest(t, "aliased-buyeruids.json")),
 		"2": json.RawMessage(validRequest(t, "aliases.json")),
-		"4": json.RawMessage(validRequest(t, "digitrust.json")),
 		"5": json.RawMessage(validRequest(t, "gdpr-no-consentstring.json")),
 		"6": json.RawMessage(validRequest(t, "gdpr.json")),
 		"7": json.RawMessage(validRequest(t, "site.json")),
@@ -122,11 +121,6 @@ func TestAMPPageInfo(t *testing.T) {
 func TestGDPRConsent(t *testing.T) {
 	consent := "BOu5On0Ou5On0ADACHENAO7pqzAAppY"
 	existingConsent := "BONV8oqONXwgmADACHENAO7pqzAAppY"
-	digitrust := &openrtb_ext.ExtUserDigiTrust{
-		ID:   "anyDigitrustID",
-		KeyV: 1,
-		Pref: 0,
-	}
 
 	testCases := []struct {
 		description     string
@@ -165,12 +159,10 @@ func TestGDPRConsent(t *testing.T) {
 			description: "Overrides Existing Consent - With Sibling Data",
 			consent:     consent,
 			userExt: &openrtb_ext.ExtUser{
-				Consent:   existingConsent,
-				DigiTrust: digitrust,
+				Consent: existingConsent,
 			},
 			expectedUserExt: openrtb_ext.ExtUser{
-				Consent:   consent,
-				DigiTrust: digitrust,
+				Consent: consent,
 			},
 		},
 		{
diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go
index deff0662..213af9a0 100644
--- a/exchange/bidder_test.go
+++ b/exchange/bidder_test.go
@@ -564,7 +564,7 @@ func TestMultiCurrencies(t *testing.T) {
 				{currency: "USD", price: 1.3 * 1.3050530256},
 			},
 			expectedBadCurrencyErrors: []error{
-				currency.ConversionRateNotFound{"JPY", "USD"},
+				currency.ConversionNotFoundError{FromCur: "JPY", ToCur: "USD"},
 			},
 			description: "Case 6 - Bidder respond with a mix of currencies and one unknown on all HTTP responses",
 		},
@@ -587,9 +587,9 @@ func TestMultiCurrencies(t *testing.T) {
 			},
 			expectedBids: []bid{},
 			expectedBadCurrencyErrors: []error{
-				currency.ConversionRateNotFound{"JPY", "USD"},
-				currency.ConversionRateNotFound{"BZD", "USD"},
-				currency.ConversionRateNotFound{"DKK", "USD"},
+				currency.ConversionNotFoundError{FromCur: "JPY", ToCur: "USD"},
+				currency.ConversionNotFoundError{FromCur: "BZD", ToCur: "USD"},
+				currency.ConversionNotFoundError{FromCur: "DKK", ToCur: "USD"},
 			},
 			description: "Case 7 - Bidder respond with currencies not having any rate on all HTTP responses",
 		},
@@ -720,9 +720,9 @@ func TestMultiCurrencies_RateConverterNotSet(t *testing.T) {
 			bidCurrency:       []string{"EUR", "EUR", "EUR"},
 			expectedBidsCount: 0,
 			expectedBadCurrencyErrors: []error{
-				currency.ConversionRateNotFound{"EUR", "USD"},
-				currency.ConversionRateNotFound{"EUR", "USD"},
-				currency.ConversionRateNotFound{"EUR", "USD"},
+				currency.ConversionNotFoundError{FromCur: "EUR", ToCur: "USD"},
+				currency.ConversionNotFoundError{FromCur: "EUR", ToCur: "USD"},
+				currency.ConversionNotFoundError{FromCur: "EUR", ToCur: "USD"},
 			},
 			description: "Case 2 - Bidder respond with the same currency (not default one) on all HTTP responses",
 		},
@@ -754,7 +754,7 @@ func TestMultiCurrencies_RateConverterNotSet(t *testing.T) {
 			bidCurrency:       []string{"EUR", "", "USD"},
 			expectedBidsCount: 2,
 			expectedBadCurrencyErrors: []error{
-				currency.ConversionRateNotFound{"EUR", "USD"},
+				currency.ConversionNotFoundError{FromCur: "EUR", ToCur: "USD"},
 			},
 			description: "Case 7 - Bidder responds with a mix of not set, non default currency and default currency in HTTP responses",
 		},
@@ -762,7 +762,7 @@ func TestMultiCurrencies_RateConverterNotSet(t *testing.T) {
 			bidCurrency:       []string{"GBP", "", "USD"},
 			expectedBidsCount: 2,
 			expectedBadCurrencyErrors: []error{
-				currency.ConversionRateNotFound{"GBP", "USD"},
+				currency.ConversionNotFoundError{FromCur: "GBP", ToCur: "USD"},
 			},
 			description: "Case 8 - Bidder responds with a mix of not set, non default currency and default currency in HTTP responses",
 		},
@@ -770,7 +770,7 @@ func TestMultiCurrencies_RateConverterNotSet(t *testing.T) {
 			bidCurrency:       []string{"GBP", "", ""},
 			expectedBidsCount: 2,
 			expectedBadCurrencyErrors: []error{
-				currency.ConversionRateNotFound{"GBP", "USD"},
+				currency.ConversionNotFoundError{FromCur: "GBP", ToCur: "USD"},
 			},
 			description: "Case 9 - Bidder responds with a mix of not set and empty currencies (default currency) in HTTP responses",
 		},
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 2d1306af..989e6707 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -31,6 +31,7 @@ import (
 
 	"github.com/buger/jsonparser"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
 	"github.com/yudai/gojsondiff"
 	"github.com/yudai/gojsondiff/formatter"
 )
@@ -539,7 +540,7 @@ func TestTwoBiddersDebugDisabledAndEnabled(t *testing.T) {
 
 func TestOverrideWithCustomCurrency(t *testing.T) {
 
-	mockCurrencyClient := &mockCurrencyRatesClient{
+	mockCurrencyClient := &fakeCurrencyRatesHttpClient{
 		responseBody: `{"dataAsOf":"2018-09-12","conversions":{"USD":{"MXN":10.00}}}`,
 	}
 	mockCurrencyConverter := currency.NewRateConverter(
@@ -694,6 +695,72 @@ func TestOverrideWithCustomCurrency(t *testing.T) {
 	}
 }
 
+func TestAdapterCurrency(t *testing.T) {
+	fakeCurrencyClient := &fakeCurrencyRatesHttpClient{
+		responseBody: `{"dataAsOf":"2018-09-12","conversions":{"USD":{"MXN":10.00}}}`,
+	}
+	currencyConverter := currency.NewRateConverter(
+		fakeCurrencyClient,
+		"currency.fake.com",
+		24*time.Hour,
+	)
+	currencyConverter.Run()
+
+	// Initialize Mock Bidder
+	// - Response purposefully causes PBS-Core to stop processing the request, since this test is only
+	//   interested in the call to MakeRequests and nothing after.
+	mockBidder := &mockBidder{}
+	mockBidder.On("MakeRequests", mock.Anything, mock.Anything).Return([]*adapters.RequestData(nil), []error(nil))
+
+	// Initialize Real Exchange
+	e := exchange{
+		cache:             &wellBehavedCache{},
+		me:                &metricsConf.DummyMetricsEngine{},
+		gDPR:              gdpr.AlwaysAllow{},
+		currencyConverter: currencyConverter,
+		categoriesFetcher: nilCategoryFetcher{},
+		bidIDGenerator:    &mockBidIDGenerator{false, false},
+		adapterMap: map[openrtb_ext.BidderName]adaptedBidder{
+			openrtb_ext.BidderName("foo"): adaptBidder(mockBidder, nil, &config.Configuration{}, &metricsConfig.DummyMetricsEngine{}, openrtb_ext.BidderName("foo"), nil),
+		},
+	}
+
+	// Define Bid Request
+	request := &openrtb2.BidRequest{
+		ID: "some-request-id",
+		Imp: []openrtb2.Imp{{
+			ID:     "some-impression-id",
+			Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}, {W: 300, H: 600}}},
+			Ext:    json.RawMessage(`{"foo": {"placementId": 1}}`),
+		}},
+		Site: &openrtb2.Site{
+			Page: "prebid.org",
+			Ext:  json.RawMessage(`{"amp":0}`),
+		},
+		Cur: []string{"USD"},
+		Ext: json.RawMessage(`{"prebid": {"currency": {"rates": {"USD": {"MXN": 20.00}}}}}`),
+	}
+
+	// Run Auction
+	auctionRequest := AuctionRequest{
+		BidRequest: request,
+		Account:    config.Account{},
+		UserSyncs:  &emptyUsersync{},
+	}
+	response, err := e.HoldAuction(context.Background(), auctionRequest, &DebugLog{})
+	assert.NoError(t, err)
+	assert.Equal(t, "some-request-id", response.ID, "Response ID")
+	assert.Empty(t, response.SeatBid, "Response Bids")
+	assert.Contains(t, string(response.Ext), `"errors":{"foo":[{"code":5,"message":"The adapter failed to generate any bid requests, but also failed to generate an error explaining why"}]}`, "Response Ext")
+
+	// Test Currency Converter Properly Passed To Adapter
+	if assert.NotNil(t, mockBidder.lastExtraRequestInfo, "Currency Conversion Argument") {
+		converted, err := mockBidder.lastExtraRequestInfo.ConvertCurrency(2.0, "USD", "MXN")
+		assert.NoError(t, err, "Currency Conversion Error")
+		assert.Equal(t, 40.0, converted, "Currency Conversion Response")
+	}
+}
+
 func TestGetAuctionCurrencyRates(t *testing.T) {
 
 	pbsRates := map[string]map[string]float64{
@@ -859,7 +926,7 @@ func TestGetAuctionCurrencyRates(t *testing.T) {
 		}
 
 		// Init mock currency conversion service
-		mockCurrencyClient := &mockCurrencyRatesClient{
+		mockCurrencyClient := &fakeCurrencyRatesHttpClient{
 			responseBody: `{"dataAsOf":"2018-09-12","conversions":` + string(jsonPbsRates) + `}`,
 		}
 		mockCurrencyConverter := currency.NewRateConverter(
@@ -1720,7 +1787,7 @@ func newRaceCheckingRequest(t *testing.T) *openrtb2.BidRequest {
 		User: &openrtb2.User{
 			ID:       "our-id",
 			BuyerUID: "their-id",
-			Ext:      json.RawMessage(`{"consent":"BONciguONcjGKADACHENAOLS1rAHDAFAAEAASABQAMwAeACEAFw","digitrust":{"id":"digi-id","keyv":1,"pref":1}}`),
+			Ext:      json.RawMessage(`{"consent":"BONciguONcjGKADACHENAOLS1rAHDAFAAEAASABQAMwAeACEAFw"}`),
 		},
 		Regs: &openrtb2.Regs{
 			COPPA: 1,
@@ -1882,7 +1949,7 @@ func TestPanicRecoveryHighLevel(t *testing.T) {
 		User: &openrtb2.User{
 			ID:       "our-id",
 			BuyerUID: "their-id",
-			Ext:      json.RawMessage(`{"consent":"BONciguONcjGKADACHENAOLS1rAHDAFAAEAASABQAMwAeACEAFw","digitrust":{"id":"digi-id","keyv":1,"pref":1}}`),
+			Ext:      json.RawMessage(`{"consent":"BONciguONcjGKADACHENAOLS1rAHDAFAAEAASABQAMwAeACEAFw"}`),
 		},
 		Imp: []openrtb2.Imp{{
 			ID: "some-imp-id",
@@ -3654,15 +3721,32 @@ func (nilCategoryFetcher) FetchCategories(ctx context.Context, primaryAdServer,
 	return "", nil
 }
 
-// mockCurrencyRatesClient is a simple http client mock returning a constant response body
-type mockCurrencyRatesClient struct {
+// fakeCurrencyRatesHttpClient is a simple http client mock returning a constant response body
+type fakeCurrencyRatesHttpClient struct {
 	responseBody string
 }
 
-func (m *mockCurrencyRatesClient) Do(req *http.Request) (*http.Response, error) {
+func (m *fakeCurrencyRatesHttpClient) Do(req *http.Request) (*http.Response, error) {
 	return &http.Response{
 		Status:     "200 OK",
 		StatusCode: http.StatusOK,
 		Body:       ioutil.NopCloser(strings.NewReader(m.responseBody)),
 	}, nil
 }
+
+type mockBidder struct {
+	mock.Mock
+	lastExtraRequestInfo *adapters.ExtraRequestInfo
+}
+
+func (m *mockBidder) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	m.lastExtraRequestInfo = reqInfo
+
+	args := m.Called(request, reqInfo)
+	return args.Get(0).([]*adapters.RequestData), args.Get(1).([]error)
+}
+
+func (m *mockBidder) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	args := m.Called(internalRequest, externalRequest, response)
+	return args.Get(0).(*adapters.BidderResponse), args.Get(1).([]error)
+}
diff --git a/exchange/exchangetest/request-other-user-ext.json b/exchange/exchangetest/request-other-user-ext.json
index 9bd4c02f..f9fb3264 100644
--- a/exchange/exchangetest/request-other-user-ext.json
+++ b/exchange/exchangetest/request-other-user-ext.json
@@ -12,11 +12,6 @@
             "buyeruids": {
               "appnexus": "explicit-appnexus"
             }
-          },
-          "digitrust": {
-            "id": "digi-id",
-            "keyv": 1,
-            "pref": 2
           }
         }
       },
@@ -48,14 +43,7 @@
           },
           "user": {
             "id": "foo",
-            "buyeruid": "explicit-appnexus",
-            "ext": {
-              "digitrust": {
-                "id": "digi-id",
-                "keyv": 1,
-                "pref": 2
-              }
-            }
+            "buyeruid": "explicit-appnexus"
           },
           "imp": [
             {
diff --git a/exchange/exchangetest/request-user-no-prebid.json b/exchange/exchangetest/request-user-no-prebid.json
index bb36ba8a..aae11606 100644
--- a/exchange/exchangetest/request-user-no-prebid.json
+++ b/exchange/exchangetest/request-user-no-prebid.json
@@ -8,11 +8,6 @@
       "user": {
         "id": "foo",
         "ext": {
-          "digitrust": {
-            "id": "digi-id",
-            "keyv": 1,
-            "pref": 2
-          }
         }
       },
       "imp": [
@@ -45,11 +40,6 @@
             "id": "foo",
             "buyeruid": "implicit-appnexus",
             "ext": {
-              "digitrust": {
-                "id": "digi-id",
-                "keyv": 1,
-                "pref": 2
-              }
             }
           },
           "imp": [
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index 5a281f9a..5a9fa187 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -1788,7 +1788,7 @@ func newAdapterAliasBidRequest(t *testing.T) *openrtb2.BidRequest {
 		User: &openrtb2.User{
 			ID:       "our-id",
 			BuyerUID: "their-id",
-			Ext:      json.RawMessage(`{"consent":"BONciguONcjGKADACHENAOLS1rAHDAFAAEAASABQAMwAeACEAFw","digitrust":{"id":"digi-id","keyv":1,"pref":1}}`),
+			Ext:      json.RawMessage(`{"consent":"BONciguONcjGKADACHENAOLS1rAHDAFAAEAASABQAMwAeACEAFw"}`),
 		},
 		Regs: &openrtb2.Regs{
 			Ext: json.RawMessage(`{"gdpr":1}`),
@@ -1833,7 +1833,7 @@ func newBidRequest(t *testing.T) *openrtb2.BidRequest {
 			ID:       "our-id",
 			BuyerUID: "their-id",
 			Yob:      1982,
-			Ext:      json.RawMessage(`{"digitrust":{"id":"digi-id","keyv":1,"pref":1}}`),
+			Ext:      json.RawMessage(`{}`),
 		},
 		Imp: []openrtb2.Imp{{
 			ID: "some-imp-id",
diff --git a/gdpr/impl_test.go b/gdpr/impl_test.go
index cde48546..93d23c1a 100644
--- a/gdpr/impl_test.go
+++ b/gdpr/impl_test.go
@@ -9,6 +9,7 @@ import (
 	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/openrtb_ext"
 
+	"github.com/prebid/go-gdpr/consentconstants"
 	"github.com/prebid/go-gdpr/vendorlist"
 	"github.com/prebid/go-gdpr/vendorlist2"
 
@@ -64,7 +65,7 @@ func TestAllowedSyncs(t *testing.T) {
 		cfg: config.GDPR{
 			HostVendorID: 2,
 			TCF2: config.TCF2{
-				Purpose1: config.PurposeDetail{
+				Purpose1: config.TCF2Purpose{
 					Enabled: true,
 				},
 			},
@@ -104,7 +105,7 @@ func TestProhibitedPurposes(t *testing.T) {
 		cfg: config.GDPR{
 			HostVendorID: 2,
 			TCF2: config.TCF2{
-				Purpose1: config.PurposeDetail{
+				Purpose1: config.TCF2Purpose{
 					Enabled: true,
 				},
 			},
@@ -143,7 +144,7 @@ func TestProhibitedVendors(t *testing.T) {
 		cfg: config.GDPR{
 			HostVendorID: 2,
 			TCF2: config.TCF2{
-				Purpose1: config.PurposeDetail{
+				Purpose1: config.TCF2Purpose{
 					Enabled: true,
 				},
 			},
@@ -287,7 +288,7 @@ func TestAllowActivities(t *testing.T) {
 			NonStandardPublisherMap: map[string]struct{}{"appNexusAppID": {}},
 			TCF2: config.TCF2{
 				Enabled: true,
-				Purpose2: config.PurposeDetail{
+				Purpose2: config.TCF2Purpose{
 					Enabled: true,
 				},
 			},
@@ -360,10 +361,10 @@ var gdprConfig = config.GDPR{
 	HostVendorID: 2,
 	TCF2: config.TCF2{
 		Enabled:         true,
-		Purpose1:        config.PurposeDetail{Enabled: true},
-		Purpose2:        config.PurposeDetail{Enabled: true},
-		Purpose7:        config.PurposeDetail{Enabled: true},
-		SpecialPurpose1: config.PurposeDetail{Enabled: true},
+		Purpose1:        config.TCF2Purpose{Enabled: true},
+		Purpose2:        config.TCF2Purpose{Enabled: true},
+		Purpose7:        config.TCF2Purpose{Enabled: true},
+		SpecialPurpose1: config.TCF2Purpose{Enabled: true},
 	},
 }
 
@@ -796,10 +797,10 @@ func TestAllowActivitiesBidRequests(t *testing.T) {
 				HostVendorID: 2,
 				TCF2: config.TCF2{
 					Enabled:         true,
-					Purpose1:        config.PurposeDetail{Enabled: true},
-					Purpose2:        config.PurposeDetail{Enabled: td.purpose2Enabled},
-					Purpose7:        config.PurposeDetail{Enabled: true},
-					SpecialPurpose1: config.PurposeDetail{Enabled: true},
+					Purpose1:        config.TCF2Purpose{Enabled: true},
+					Purpose2:        config.TCF2Purpose{Enabled: td.purpose2Enabled},
+					Purpose7:        config.TCF2Purpose{Enabled: true},
+					SpecialPurpose1: config.TCF2Purpose{Enabled: true},
 				},
 			},
 			vendorIDs: map[openrtb_ext.BidderName]uint16{
@@ -837,3 +838,154 @@ func TestTCF1Consent(t *testing.T) {
 	assert.Equal(t, false, passGeo, "TCF1 consent - passing geo not allowed")
 	assert.Equal(t, false, passID, "TCF1 consent - passing id not allowed")
 }
+
+func TestAllowActivitiesVendorException(t *testing.T) {
+	noPurposeOrVendorConsentAndPubRestrictsP2 := "CPF_61ePF_61eFxAAAENAiCAAAAAAAAAAAAAACEAAAACEAAgAgAA"
+	noPurposeOrVendorConsentAndPubRestrictsNone := "CPF_61ePF_61eFxAAAENAiCAAAAAAAAAAAAAACEAAAAA"
+
+	testDefs := []struct {
+		description           string
+		p2VendorExceptionMap  map[openrtb_ext.BidderName]struct{}
+		sp1VendorExceptionMap map[openrtb_ext.BidderName]struct{}
+		bidder                openrtb_ext.BidderName
+		consent               string
+		allowBid              bool
+		passGeo               bool
+		passID                bool
+	}{
+		{
+			description:          "Bid/ID blocked by publisher - p2 enabled with p2 vendor exception, pub restricts p2 for vendor",
+			p2VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderAppnexus: {}},
+			bidder:               openrtb_ext.BidderAppnexus,
+			consent:              noPurposeOrVendorConsentAndPubRestrictsP2,
+			allowBid:             false,
+			passGeo:              false,
+			passID:               false,
+		},
+		{
+			description:           "Bid/ID allowed by vendor exception - p2 enabled with p2 vendor exception, pub restricts none",
+			p2VendorExceptionMap:  map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderAppnexus: {}},
+			sp1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{},
+			bidder:                openrtb_ext.BidderAppnexus,
+			consent:               noPurposeOrVendorConsentAndPubRestrictsNone,
+			allowBid:              true,
+			passGeo:               false,
+			passID:                true,
+		},
+		{
+			description:           "Geo blocked - sp1 enabled but no consent",
+			p2VendorExceptionMap:  map[openrtb_ext.BidderName]struct{}{},
+			sp1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{},
+			bidder:                openrtb_ext.BidderAppnexus,
+			consent:               noPurposeOrVendorConsentAndPubRestrictsNone,
+			allowBid:              false,
+			passGeo:               false,
+			passID:                false,
+		},
+		{
+			description:           "Geo allowed by vendor exception - sp1 enabled with sp1 vendor exception",
+			p2VendorExceptionMap:  map[openrtb_ext.BidderName]struct{}{},
+			sp1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderAppnexus: {}},
+			bidder:                openrtb_ext.BidderAppnexus,
+			consent:               noPurposeOrVendorConsentAndPubRestrictsNone,
+			allowBid:              false,
+			passGeo:               true,
+			passID:                false,
+		},
+	}
+
+	for _, td := range testDefs {
+		vendorListData := MarshalVendorList(buildVendorList34())
+		perms := permissionsImpl{
+			cfg: config.GDPR{
+				HostVendorID: 2,
+				TCF2: config.TCF2{
+					Enabled:         true,
+					Purpose2:        config.TCF2Purpose{Enabled: true, VendorExceptionMap: td.p2VendorExceptionMap},
+					SpecialPurpose1: config.TCF2Purpose{Enabled: true, VendorExceptionMap: td.sp1VendorExceptionMap},
+				},
+			},
+			vendorIDs: map[openrtb_ext.BidderName]uint16{
+				openrtb_ext.BidderAppnexus: 32,
+			},
+			fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){
+				tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{
+					34: parseVendorListDataV2(t, vendorListData),
+				}),
+			},
+		}
+		perms.purposeConfigs = map[consentconstants.Purpose]config.TCF2Purpose{
+			consentconstants.Purpose(2): perms.cfg.TCF2.Purpose2,
+			consentconstants.Purpose(3): perms.cfg.TCF2.Purpose3,
+		}
+
+		allowBid, passGeo, passID, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidder, "", SignalYes, td.consent, false)
+		assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description)
+		assert.EqualValuesf(t, td.allowBid, allowBid, "AllowBid failure on %s", td.description)
+		assert.EqualValuesf(t, td.passGeo, passGeo, "PassGeo failure on %s", td.description)
+		assert.EqualValuesf(t, td.passID, passID, "PassID failure on %s", td.description)
+	}
+}
+
+func TestBidderSyncAllowedVendorException(t *testing.T) {
+	noPurposeOrVendorConsentAndPubRestrictsP1 := "CPF_61ePF_61eFxAAAENAiCAAAAAAAAAAAAAAQAAAAAAAAAAIIACACA"
+	noPurposeOrVendorConsentAndPubRestrictsNone := "CPF_61ePF_61eFxAAAENAiCAAAAAAAAAAAAAACEAAAAA"
+
+	testDefs := []struct {
+		description          string
+		p1VendorExceptionMap map[openrtb_ext.BidderName]struct{}
+		bidder               openrtb_ext.BidderName
+		consent              string
+		allowSync            bool
+	}{
+		{
+			description:          "Sync blocked by no consent - p1 enabled, no p1 vendor exception, pub restricts none",
+			p1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{},
+			bidder:               openrtb_ext.BidderAppnexus,
+			consent:              noPurposeOrVendorConsentAndPubRestrictsNone,
+			allowSync:            false,
+		},
+		{
+			description:          "Sync blocked by publisher - p1 enabled with p1 vendor exception, pub restricts p1 for vendor",
+			p1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderAppnexus: {}},
+			bidder:               openrtb_ext.BidderAppnexus,
+			consent:              noPurposeOrVendorConsentAndPubRestrictsP1,
+			allowSync:            false,
+		},
+		{
+			description:          "Sync allowed by vendor exception - p1 enabled with p1 vendor exception, pub restricts none",
+			p1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderAppnexus: {}},
+			bidder:               openrtb_ext.BidderAppnexus,
+			consent:              noPurposeOrVendorConsentAndPubRestrictsNone,
+			allowSync:            true,
+		},
+	}
+
+	for _, td := range testDefs {
+		vendorListData := MarshalVendorList(buildVendorList34())
+		perms := permissionsImpl{
+			cfg: config.GDPR{
+				HostVendorID: 2,
+				TCF2: config.TCF2{
+					Enabled:  true,
+					Purpose1: config.TCF2Purpose{Enabled: true, VendorExceptionMap: td.p1VendorExceptionMap},
+				},
+			},
+			vendorIDs: map[openrtb_ext.BidderName]uint16{
+				openrtb_ext.BidderAppnexus: 32,
+			},
+			fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){
+				tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{
+					34: parseVendorListDataV2(t, vendorListData),
+				}),
+			},
+		}
+		perms.purposeConfigs = map[consentconstants.Purpose]config.TCF2Purpose{
+			consentconstants.Purpose(1): perms.cfg.TCF2.Purpose1,
+		}
+
+		allowSync, err := perms.BidderSyncAllowed(context.Background(), td.bidder, SignalYes, td.consent)
+		assert.NoErrorf(t, err, "Error processing BidderSyncAllowed for %s", td.description)
+		assert.EqualValuesf(t, td.allowSync, allowSync, "AllowSync failure on %s", td.description)
+	}
+}
diff --git a/privacy/scrubber_test.go b/privacy/scrubber_test.go
index 9207315f..1198d0bb 100644
--- a/privacy/scrubber_test.go
+++ b/privacy/scrubber_test.go
@@ -202,7 +202,7 @@ func TestScrubUser(t *testing.T) {
 		BuyerUID: "anyBuyerUID",
 		Yob:      42,
 		Gender:   "anyGender",
-		Ext:      json.RawMessage(`{"digitrust":{"id":"anyId","keyv":4,"pref":8}}`),
+		Ext:      json.RawMessage(`{}`),
 		Geo: &openrtb2.Geo{
 			Lat:   123.456,
 			Lon:   678.89,
@@ -327,7 +327,7 @@ func TestScrubUser(t *testing.T) {
 				BuyerUID: "anyBuyerUID",
 				Yob:      42,
 				Gender:   "anyGender",
-				Ext:      json.RawMessage(`{"digitrust":{"id":"anyId","keyv":4,"pref":8}}`),
+				Ext:      json.RawMessage(`{}`),
 				Geo:      &openrtb2.Geo{},
 			},
 			scrubUser: ScrubStrategyUserNone,
@@ -340,7 +340,7 @@ func TestScrubUser(t *testing.T) {
 				BuyerUID: "anyBuyerUID",
 				Yob:      42,
 				Gender:   "anyGender",
-				Ext:      json.RawMessage(`{"digitrust":{"id":"anyId","keyv":4,"pref":8}}`),
+				Ext:      json.RawMessage(`{}`),
 				Geo: &openrtb2.Geo{
 					Lat:   123.46,
 					Lon:   678.89,
@@ -359,7 +359,7 @@ func TestScrubUser(t *testing.T) {
 				BuyerUID: "anyBuyerUID",
 				Yob:      42,
 				Gender:   "anyGender",
-				Ext:      json.RawMessage(`{"digitrust":{"id":"anyId","keyv":4,"pref":8}}`),
+				Ext:      json.RawMessage(`{}`),
 				Geo: &openrtb2.Geo{
 					Lat:   123.456,
 					Lon:   678.89,
@@ -586,18 +586,18 @@ func TestScrubUserExtIDs(t *testing.T) {
 			expected:    json.RawMessage(`{"anyExisting":42}}`),
 		},
 		{
-			description: "Remove eids + digitrust",
-			userExt:     json.RawMessage(`{"eids":[{"source":"anySource","id":"anyId","uids":[{"id":"anyId","ext":{"id":42}}],"ext":{"id":42}}],"digitrust":{"id":"anyId","keyv":4,"pref":8}}`),
+			description: "Remove eids",
+			userExt:     json.RawMessage(`{"eids":[{"source":"anySource","id":"anyId","uids":[{"id":"anyId","ext":{"id":42}}],"ext":{"id":42}}]}`),
 			expected:    json.RawMessage(`{}`),
 		},
 		{
-			description: "Remove eids + digitrust - With Other Data",
-			userExt:     json.RawMessage(`{"anyExisting":42,"eids":[{"source":"anySource","id":"anyId","uids":[{"id":"anyId","ext":{"id":42}}],"ext":{"id":42}}],"digitrust":{"id":"anyId","keyv":4,"pref":8}}`),
+			description: "Remove eids - With Other Data",
+			userExt:     json.RawMessage(`{"anyExisting":42,"eids":[{"source":"anySource","id":"anyId","uids":[{"id":"anyId","ext":{"id":42}}],"ext":{"id":42}}]}`),
 			expected:    json.RawMessage(`{"anyExisting":42}`),
 		},
 		{
-			description: "Remove eids + digitrust - With Other Nested Data",
-			userExt:     json.RawMessage(`{"anyExisting":{"existing":42},"eids":[{"source":"anySource","id":"anyId","uids":[{"id":"anyId","ext":{"id":42}}],"ext":{"id":42}}],"digitrust":{"id":"anyId","keyv":4,"pref":8}}`),
+			description: "Remove eids - With Other Nested Data",
+			userExt:     json.RawMessage(`{"anyExisting":{"existing":42},"eids":[{"source":"anySource","id":"anyId","uids":[{"id":"anyId","ext":{"id":42}}],"ext":{"id":42}}]}`),
 			expected:    json.RawMessage(`{"anyExisting":{"existing":42}}`),
 		},
 		{
@@ -620,21 +620,6 @@ func TestScrubUserExtIDs(t *testing.T) {
 			userExt:     json.RawMessage(`{"anyExisting":{"existing":42},"eids":[{"source":"anySource","id":"anyId","uids":[{"id":"anyId","ext":{"id":42}}],"ext":{"id":42}}]}`),
 			expected:    json.RawMessage(`{"anyExisting":{"existing":42}}`),
 		},
-		{
-			description: "Remove digitrust Only",
-			userExt:     json.RawMessage(`{"digitrust":{"id":"anyId","keyv":4,"pref":8}}`),
-			expected:    json.RawMessage(`{}`),
-		},
-		{
-			description: "Remove digitrust Only - With Other Data",
-			userExt:     json.RawMessage(`{"anyExisting":42,"digitrust":{"id":"anyId","keyv":4,"pref":8}}`),
-			expected:    json.RawMessage(`{"anyExisting":42}`),
-		},
-		{
-			description: "Remove digitrust Only - With Other Nested Data",
-			userExt:     json.RawMessage(`{"anyExisting":{"existing":42},"digitrust":{"id":"anyId","keyv":4,"pref":8}}`),
-			expected:    json.RawMessage(`{"anyExisting":{"existing":42}}`),
-		},
 	}
 
 	for _, test := range testCases {
diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go
index 0cea346e..59ed67cc 100644
--- a/usersync/usersyncers/syncer_test.go
+++ b/usersync/usersyncers/syncer_test.go
@@ -37,6 +37,7 @@ func TestNewSyncerMap(t *testing.T) {
 			string(openrtb_ext.BidderBeachfront):       syncConfig,
 			string(openrtb_ext.BidderBeintoo):          syncConfig,
 			string(openrtb_ext.BidderBetween):          syncConfig,
+			string(openrtb_ext.BidderBidmyadz):         syncConfig,
 			string(openrtb_ext.BidderBmtm):             syncConfig,
 			string(openrtb_ext.BidderBrightroll):       syncConfig,
 			string(openrtb_ext.BidderColossus):         syncConfig,
@@ -57,6 +58,7 @@ func TestNewSyncerMap(t *testing.T) {
 			string(openrtb_ext.BidderGrid):             syncConfig,
 			string(openrtb_ext.BidderGumGum):           syncConfig,
 			string(openrtb_ext.BidderImprovedigital):   syncConfig,
+			string(openrtb_ext.BidderInMobi):           syncConfig,
 			string(openrtb_ext.BidderInvibes):          syncConfig,
 			string(openrtb_ext.BidderIx):               syncConfig,
 			string(openrtb_ext.BidderJixie):            syncConfig,
@@ -64,6 +66,7 @@ func TestNewSyncerMap(t *testing.T) {
 			string(openrtb_ext.BidderLockerDome):       syncConfig,
 			string(openrtb_ext.BidderLogicad):          syncConfig,
 			string(openrtb_ext.BidderLunaMedia):        syncConfig,
+			string(openrtb_ext.BidderSaLunaMedia):      syncConfig,
 			string(openrtb_ext.BidderMarsmedia):        syncConfig,
 			string(openrtb_ext.BidderMediafuse):        syncConfig,
 			string(openrtb_ext.BidderMgid):             syncConfig,
@@ -114,11 +117,11 @@ func TestNewSyncerMap(t *testing.T) {
 		openrtb_ext.BidderAdprime:           true,
 		openrtb_ext.BidderAlgorix:           true,
 		openrtb_ext.BidderApplogy:           true,
+		openrtb_ext.BidderAxonix:            true,
 		openrtb_ext.BidderBidmachine:        true,
 		openrtb_ext.BidderBidsCube:          true,
 		openrtb_ext.BidderEpom:              true,
 		openrtb_ext.BidderDecenterAds:       true,
-		openrtb_ext.BidderInMobi:            true,
 		openrtb_ext.BidderInteractiveoffers: true,
 		openrtb_ext.BidderKayzen:            true,
 		openrtb_ext.BidderKidoz:             true,