Repository: prebid/prebid-server
Pull request #2201 (2022-03-23 14:27:22)

PubMatic: add "acat" parameter
Add support to 'act' request ext param in PubMatic adapter.

Documentation https://docs.prebid.org/dev-docs/pbs-bidders.html#pubmatic (https://github.com/prebid/prebid.github.io/pull/3657)

PBJS: https://github.com/prebid/Prebid.js/pull/8246

pm-nilesh-chate: > Please update `static/bidder-params/pubmatic.json` to include the new acat bidder parameter.

done

Patch:
diff --git a/adapters/adyoulike/adyoulike.go b/adapters/adyoulike/adyoulike.go
index 17c42e4a..8537c54d 100644
--- a/adapters/adyoulike/adyoulike.go
+++ b/adapters/adyoulike/adyoulike.go
@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
+	"strings"
 
 	"github.com/buger/jsonparser"
 	"github.com/mxmCherry/openrtb/v15/openrtb2"
@@ -36,6 +37,23 @@ func (a *adapter) MakeRequests(
 	reqCopy := *openRTBRequest
 	reqCopy.Imp = []openrtb2.Imp{}
 	for ind, imp := range openRTBRequest.Imp {
+
+		// Check if imp comes with bid floor amount defined in a foreign currency
+		if imp.BidFloor > 0 && imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != "USD" {
+			// Convert to US dollars
+			convertedValue, err := reqInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD")
+			if err != nil {
+				return nil, []error{err}
+			}
+			// Update after conversion. All imp elements inside request.Imp are shallow copies
+			// therefore, their non-pointer values are not shared memory and are safe to modify.
+			imp.BidFloorCur = "USD"
+			imp.BidFloor = convertedValue
+		}
+
+		// Set the CUR of bid to USD after converting all floors
+		reqCopy.Cur = []string{"USD"}
+
 		reqCopy.Imp = append(reqCopy.Imp, imp)
 
 		tagID, err = jsonparser.GetString(reqCopy.Imp[ind].Ext, "bidder", "placement")
@@ -106,7 +124,8 @@ func (a *adapter) MakeBids(
 	}
 
 	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(openRTBRequest.Imp))
-	bidResponse.Currency = openRTBBidderResponse.Cur
+	bidResponse.Currency = "USD"
+
 	for _, seatBid := range openRTBBidderResponse.SeatBid {
 		for idx := range seatBid.Bid {
 			b := &adapters.TypedBid{
diff --git a/adapters/pubmatic/pubmatic.go b/adapters/pubmatic/pubmatic.go
index 79f07200..00c9c906 100644
--- a/adapters/pubmatic/pubmatic.go
+++ b/adapters/pubmatic/pubmatic.go
@@ -66,7 +66,7 @@ func (a *PubmaticAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ad
 	extractWrapperExtFromImp := true
 	extractPubIDFromImp := true
 
-	wrapperExt, err := extractPubmaticWrapperExtFromRequest(request)
+	wrapperExt, acat, err := extractPubmaticExtFromRequest(request)
 	if err != nil {
 		return nil, []error{err}
 	}
@@ -114,9 +114,14 @@ func (a *PubmaticAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ad
 		return nil, errs
 	}
 
+	reqExt := make(map[string]interface{})
+	if len(acat) > 0 {
+		reqExt["acat"] = acat
+	}
 	if wrapperExt != nil {
-		reqExt := make(map[string]interface{})
 		reqExt["wrapper"] = wrapperExt
+	}
+	if len(reqExt) > 0 {
 		rawExt, err := json.Marshal(reqExt)
 		if err != nil {
 			return nil, []error{err}
@@ -310,23 +315,32 @@ func parseImpressionObject(imp *openrtb2.Imp, extractWrapperExtFromImp, extractP
 	return wrapExt, pubID, nil
 }
 
-// extractPubmaticWrapperExtFromRequest parse the imp to get it ready to send to pubmatic
-func extractPubmaticWrapperExtFromRequest(request *openrtb2.BidRequest) (*pubmaticWrapperExt, error) {
-	var wrpExt pubmaticWrapperExt
+// extractPubmaticExtFromRequest parse the req.ext to fetch wrapper and acat params
+func extractPubmaticExtFromRequest(request *openrtb2.BidRequest) (*pubmaticWrapperExt, []string, error) {
+	var acat []string
+	var wrpExt *pubmaticWrapperExt
 	reqExtBidderParams, err := adapters.ExtractReqExtBidderParamsMap(request)
 	if err != nil {
-		return nil, err
+		return nil, acat, err
 	}
 
 	//get request ext bidder params
 	if wrapperObj, present := reqExtBidderParams["wrapper"]; present && len(wrapperObj) != 0 {
-		err = json.Unmarshal(wrapperObj, &wrpExt)
+		wrpExt = &pubmaticWrapperExt{}
+		err = json.Unmarshal(wrapperObj, wrpExt)
 		if err != nil {
-			return nil, err
+			return nil, acat, err
+		}
+	}
+
+	if acatBytes, ok := reqExtBidderParams["acat"]; ok {
+		err = json.Unmarshal(acatBytes, &acat)
+		for i := 0; i < len(acat); i++ {
+			acat[i] = strings.TrimSpace(acat[i])
 		}
-		return &wrpExt, nil
 	}
-	return nil, nil
+
+	return wrpExt, acat, err
 }
 
 func addKeywordsToExt(keywords []*openrtb_ext.ExtImpPubmaticKeyVal, extMap map[string]interface{}) {
diff --git a/adapters/yahoossp/yahoossp.go b/adapters/yahoossp/yahoossp.go
index 652d57f9..f0cc23bf 100644
--- a/adapters/yahoossp/yahoossp.go
+++ b/adapters/yahoossp/yahoossp.go
@@ -117,14 +117,15 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest
 				}}
 			}
 
-			if openrtb_ext.BidTypeBanner != mediaTypeId {
-				//only banner is supported, anything else is ignored
+			if openrtb_ext.BidTypeBanner != mediaTypeId &&
+				openrtb_ext.BidTypeVideo != mediaTypeId {
+				//only banner and video are mediaTypeId, anything else is ignored
 				continue
 			}
 
 			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
 				Bid:     &bid,
-				BidType: openrtb_ext.BidTypeBanner,
+				BidType: mediaTypeId,
 			})
 		}
 	}
@@ -140,6 +141,8 @@ func getImpInfo(impId string, imps []openrtb2.Imp) (bool, openrtb_ext.BidType) {
 			exists = true
 			if imp.Banner != nil {
 				mediaType = openrtb_ext.BidTypeBanner
+			} else if imp.Video != nil {
+				mediaType = openrtb_ext.BidTypeVideo
 			}
 			break
 		}
@@ -156,13 +159,20 @@ func changeRequestForBidService(request *openrtb2.BidRequest, extension *openrtb
 		request.App.ID = extension.Dcn
 	}
 
-	if request.Imp[0].Banner == nil {
-		return nil
+	if request.Imp[0].Banner != nil {
+		banner := *request.Imp[0].Banner
+		request.Imp[0].Banner = &banner
+
+		err := validateBanner(&banner)
+		if err != nil {
+			return err
+		}
 	}
 
-	banner := *request.Imp[0].Banner
-	request.Imp[0].Banner = &banner
+	return nil
+}
 
+func validateBanner(banner *openrtb2.Banner) error {
 	if banner.W != nil && banner.H != nil {
 		if *banner.W == 0 || *banner.H == 0 {
 			return fmt.Errorf("Invalid sizes provided for Banner %dx%d", *banner.W, *banner.H)
diff --git a/config/bidderinfo.go b/config/bidderinfo.go
index 536acf31..0892c0f1 100644
--- a/config/bidderinfo.go
+++ b/config/bidderinfo.go
@@ -51,11 +51,6 @@ type Syncer struct {
 	// as the key for consistency, but that is not enforced as a requirement.
 	Key string `yaml:"key" mapstructure:"key"`
 
-	// Default identifies which endpoint is preferred if both are allowed by the publisher. This is
-	// only required if there is more than one endpoint configured for the bidder. Valid values are
-	// `iframe` and `redirect`.
-	Default string `yaml:"default" mapstructure:"default"`
-
 	// Supports allows bidders to specify which user sync endpoints they support but which don't have
 	// good defaults. Host companies should contact the bidder for the endpoint configuration. Hosts
 	// may not override this value.
@@ -96,10 +91,6 @@ func (s *Syncer) Override(original *Syncer) *Syncer {
 		copy.Key = s.Key
 	}
 
-	if s.Default != "" {
-		copy.Default = s.Default
-	}
-
 	if original == nil {
 		copy.IFrame = s.IFrame.Override(nil)
 		copy.Redirect = s.Redirect.Override(nil)
diff --git a/config/config.go b/config/config.go
index 9324acce..0b3bed04 100644
--- a/config/config.go
+++ b/config/config.go
@@ -916,6 +916,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.orbidder.endpoint", "https://orbidder.otto.de/openrtb2")
 	v.SetDefault("adapters.outbrain.endpoint", "https://prebidtest.zemanta.com/api/bidder/prebidtest/bid/")
 	v.SetDefault("adapters.pangle.disabled", true)
+	v.SetDefault("adapters.pgam.endpoint", "http://ghb.pgamssp.com/pbs/ortb")
 	v.SetDefault("adapters.pubmatic.endpoint", "https://hbopenbid.pubmatic.com/translator?source=prebid-server")
 	v.SetDefault("adapters.pubnative.endpoint", "http://dsp.pubnative.net/bid/v1/request")
 	v.SetDefault("adapters.pulsepoint.endpoint", "http://bid.contextweb.com/header/s/ortb/prebid-s2s")
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index 42caa3a7..e4c68057 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -1665,7 +1665,7 @@ func (deps *endpointDeps) processStoredRequests(ctx context.Context, requestJson
 		if err != nil {
 			return nil, nil, []error{err}
 		}
-		if isAppRequest && (deps.cfg.GenerateRequestID || bidRequestID == "{{UUID}}") {
+		if (deps.cfg.GenerateRequestID && isAppRequest) || bidRequestID == "{{UUID}}" {
 			uuidPatch, err := generateUuidForBidRequest(deps.uuidGenerator)
 			if err != nil {
 				return nil, nil, []error{err}
@@ -1923,20 +1923,6 @@ func generateUuidForBidRequest(uuidGenerator uuidutil.UUIDGenerator) ([]byte, er
 	return []byte(`{"id":"` + newBidRequestID + `"}`), nil
 }
 
-func checkIfAppRequest(request []byte) (bool, error) {
-	requestApp, dataType, _, err := jsonparser.Get(request, "app")
-	if dataType == jsonparser.NotExist {
-		return false, nil
-	}
-	if err != nil {
-		return false, err
-	}
-	if requestApp != nil {
-		return true, nil
-	}
-	return false, nil
-}
-
 func (deps *endpointDeps) setIntegrationType(req *openrtb_ext.RequestWrapper, account *config.Account) error {
 	reqExt, err := req.GetRequestExt()
 	if err != nil {
@@ -1956,3 +1942,17 @@ func (deps *endpointDeps) setIntegrationType(req *openrtb_ext.RequestWrapper, ac
 	}
 	return nil
 }
+
+func checkIfAppRequest(request []byte) (bool, error) {
+	requestApp, dataType, _, err := jsonparser.Get(request, "app")
+	if dataType == jsonparser.NotExist {
+		return false, nil
+	}
+	if err != nil {
+		return false, err
+	}
+	if requestApp != nil {
+		return true, nil
+	}
+	return false, nil
+}
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 7e98d688..12d31f0d 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -240,6 +240,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderOrbidder:          orbidder.Builder,
 		openrtb_ext.BidderOutbrain:          outbrain.Builder,
 		openrtb_ext.BidderPangle:            pangle.Builder,
+		openrtb_ext.BidderPGAM:              adtelligent.Builder,
 		openrtb_ext.BidderPubmatic:          pubmatic.Builder,
 		openrtb_ext.BidderPubnative:         pubnative.Builder,
 		openrtb_ext.BidderPulsepoint:        pulsepoint.Builder,
diff --git a/exchange/targeting.go b/exchange/targeting.go
index 00008d29..0113d932 100644
--- a/exchange/targeting.go
+++ b/exchange/targeting.go
@@ -96,7 +96,7 @@ func (targData *targetData) addKeys(keys map[string]string, key openrtb_ext.Targ
 		keys[key.BidderKey(bidderName, maxLength)] = value
 	}
 	if targData.includeWinners && overallWinner {
-		keys[string(key)] = value
+		keys[key.TruncateKey(maxLength)] = value
 	}
 }
 
diff --git a/firstpartydata/first_party_data.go b/firstpartydata/first_party_data.go
index d1940448..78ab5076 100644
--- a/firstpartydata/first_party_data.go
+++ b/firstpartydata/first_party_data.go
@@ -221,20 +221,26 @@ func unmarshalJSONToInt64(input json.RawMessage) (int64, error) {
 	if err != nil {
 		return -1, err
 	}
-	resNum, err := num.Int64()
-	return resNum, err
+	result, err := num.Int64()
+	return result, err
 }
 
 func unmarshalJSONToString(input json.RawMessage) (string, error) {
-	var inputString string
-	err := json.Unmarshal(input, &inputString)
-	return inputString, err
+	var result string
+	err := json.Unmarshal(input, &result)
+	return result, err
+}
+
+func unmarshalJSONToData(input json.RawMessage) ([]openrtb2.Data, error) {
+	var result []openrtb2.Data
+	err := json.Unmarshal(input, &result)
+	return result, err
 }
 
 func unmarshalJSONToStringArray(input json.RawMessage) ([]string, error) {
-	var inputString []string
-	err := json.Unmarshal(input, &inputString)
-	return inputString, err
+	var result []string
+	err := json.Unmarshal(input, &result)
+	return result, err
 }
 
 //resolveExtension inserts remaining {site/app/user} attributes back to {site/app/user}.ext.data
@@ -294,6 +300,15 @@ func mergeUsers(original *openrtb2.User, fpdConfigUser map[string]json.RawMessag
 		delete(fpdConfigUser, yobKey)
 	}
 
+	if userData, present := fpdConfigUser[dataKey]; present {
+		newUserData, err := unmarshalJSONToData(userData)
+		if err != nil {
+			return newUser, err
+		}
+		newUser.Data = append(newUser.Data, newUserData...)
+		delete(fpdConfigUser, dataKey)
+	}
+
 	if len(fpdConfigUser) > 0 {
 		newUser.Ext, err = resolveExtension(fpdConfigUser, original.Ext)
 	}
diff --git a/openrtb_ext/bid.go b/openrtb_ext/bid.go
index 7c73fb0d..bf6bb1c8 100644
--- a/openrtb_ext/bid.go
+++ b/openrtb_ext/bid.go
@@ -161,6 +161,13 @@ func min(x, y int) int {
 	return y
 }
 
+func (key TargetingKey) TruncateKey(maxLength int) string {
+	if maxLength > 0 {
+		return string(key)[:min(len(string(key)), maxLength)]
+	}
+	return string(key)
+}
+
 const (
 	StoredRequestAttributes = "storedrequestattributes"
 )
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 9e51e6e6..524ab5e5 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -175,6 +175,7 @@ const (
 	BidderOrbidder          BidderName = "orbidder"
 	BidderOutbrain          BidderName = "outbrain"
 	BidderPangle            BidderName = "pangle"
+	BidderPGAM              BidderName = "pgam"
 	BidderPubmatic          BidderName = "pubmatic"
 	BidderPubnative         BidderName = "pubnative"
 	BidderPulsepoint        BidderName = "pulsepoint"
@@ -321,6 +322,7 @@ func CoreBidderNames() []BidderName {
 		BidderOperaads,
 		BidderOrbidder,
 		BidderOutbrain,
+		BidderPGAM,
 		BidderPangle,
 		BidderPubmatic,
 		BidderPubnative,
diff --git a/static/bidder-info/adyoulike.yaml b/static/bidder-info/adyoulike.yaml
index 8fdca5e2..59711ff0 100644
--- a/static/bidder-info/adyoulike.yaml
+++ b/static/bidder-info/adyoulike.yaml
@@ -9,7 +9,6 @@ capabilities:
       - video
       - native
 userSync:
-  default: iframe
   iframe:
     url: "https://visitor.omnitagjs.com/visitor/isync?uid=19340f4f097d16f41f34fc0274981ca4&name=PrebidServer&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url={{.RedirectURL}}"
     userMacro: "[BUYER_USERID]"
diff --git a/static/bidder-info/apacdex.yaml b/static/bidder-info/apacdex.yaml
index 2e8cd08f..5ef24021 100644
--- a/static/bidder-info/apacdex.yaml
+++ b/static/bidder-info/apacdex.yaml
@@ -11,7 +11,6 @@ capabilities:
       - banner
       - video
 userSync:
-  default: iframe
   iframe:
     url: https://sync.quantumdex.io/usersync/pbs?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&r={{.RedirectURL}}
     userMacro: "[UID]"
diff --git a/static/bidder-info/openx.yaml b/static/bidder-info/openx.yaml
index 4b456014..96add482 100644
--- a/static/bidder-info/openx.yaml
+++ b/static/bidder-info/openx.yaml
@@ -12,7 +12,6 @@ capabilities:
       - video
 modifyingVastXmlAllowed: true
 userSync:
-  default: "iframe"
   iframe:
     url: "https://u.openx.net/w/1.0/cm?id=891039ac-a916-42bb-a651-4be9e3b201da&ph=a3aece0c-9e80-4316-8deb-faf804779bd1&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&r={{.RedirectURL}}"
     userMacro: "{OPENX_ID}"
diff --git a/static/bidder-info/pgam.yaml b/static/bidder-info/pgam.yaml
new file mode 100644
index 00000000..16d25850
--- /dev/null
+++ b/static/bidder-info/pgam.yaml
@@ -0,0 +1,16 @@
+maintainer:
+  email: "ppatel@pgammedia.com"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+  site:
+    mediaTypes:
+      - banner
+      - video
+userSync:
+  # PGAM ssp supports user syncing, but requires configuration by the host. contact this
+  # bidder directly at the email address in this file to ask about enabling user sync.
+  supports:
+    - iframe
diff --git a/static/bidder-info/quantumdex.yaml b/static/bidder-info/quantumdex.yaml
index 2e8cd08f..5ef24021 100644
--- a/static/bidder-info/quantumdex.yaml
+++ b/static/bidder-info/quantumdex.yaml
@@ -11,7 +11,6 @@ capabilities:
       - banner
       - video
 userSync:
-  default: iframe
   iframe:
     url: https://sync.quantumdex.io/usersync/pbs?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&r={{.RedirectURL}}
     userMacro: "[UID]"
diff --git a/static/bidder-info/triplelift.yaml b/static/bidder-info/triplelift.yaml
index 84eea869..8a86428d 100644
--- a/static/bidder-info/triplelift.yaml
+++ b/static/bidder-info/triplelift.yaml
@@ -14,7 +14,6 @@ userSync:
   # Triplelift supports user syncing but requires configuration by the host as the RedirectURL domain must be allowlisted. 
   # Contact this bidder directly at the email address above to ask about enabling user sync.
   # 
-  default: iframe
   iframe:
     url: "https://eb2.3lift.com/sync?gdpr={{.GDPR}}&cmp_cs={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir={{.RedirectURL}}"
     userMacro: $UID
diff --git a/static/bidder-info/triplelift_native.yaml b/static/bidder-info/triplelift_native.yaml
index dc60d572..96d49b32 100644
--- a/static/bidder-info/triplelift_native.yaml
+++ b/static/bidder-info/triplelift_native.yaml
@@ -12,7 +12,6 @@ userSync:
   # Triplelift supports user syncing but requires configuration by the host as the RedirectURL domain must be allowlisted. 
   # Contact this bidder directly at the email address above to ask about enabling user sync.
   # 
-  default: iframe
   iframe:
     url: "https://eb2.3lift.com/sync?gdpr={{.GDPR}}&cmp_cs={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir={{.RedirectURL}}"
     userMacro: $UID
diff --git a/static/bidder-info/valueimpression.yaml b/static/bidder-info/valueimpression.yaml
index 2e8cd08f..5ef24021 100644
--- a/static/bidder-info/valueimpression.yaml
+++ b/static/bidder-info/valueimpression.yaml
@@ -11,7 +11,6 @@ capabilities:
       - banner
       - video
 userSync:
-  default: iframe
   iframe:
     url: https://sync.quantumdex.io/usersync/pbs?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&r={{.RedirectURL}}
     userMacro: "[UID]"
diff --git a/static/bidder-info/yahoossp.yaml b/static/bidder-info/yahoossp.yaml
index 06d0cb18..cefa603d 100644
--- a/static/bidder-info/yahoossp.yaml
+++ b/static/bidder-info/yahoossp.yaml
@@ -5,9 +5,11 @@ capabilities:
   app:
     mediaTypes:
       - banner
+      - video
   site:
     mediaTypes:
       - banner
+      - video
 userSync:
   # yahoossp supports user syncing, but requires configuration by the host. contact this
   # bidder directly at the email address in this file to ask about enabling user sync.
diff --git a/static/bidder-params/pgam.json b/static/bidder-params/pgam.json
new file mode 100644
index 00000000..c0a016a7
--- /dev/null
+++ b/static/bidder-params/pgam.json
@@ -0,0 +1,26 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "PGAM Adapter Params",
+  "description": "A schema which validates params accepted by the PGAM ssp adapter",
+
+  "type": "object",
+  "properties": {
+    "placementId": {
+      "type": "integer",
+      "description": "An ID which identifies this placement of the impression"
+    },
+    "siteId": {
+      "type": "integer",
+      "description": "An ID which identifies the site selling the impression"
+    },
+    "aid": {
+      "type": "integer",
+      "description": "An ID which identifies the channel"
+    },
+    "bidFloor": {
+      "type": "number",
+      "description": "BidFloor, US Dollars"
+    }
+  },
+  "required": ["aid"]
+}
diff --git a/static/bidder-params/pubmatic.json b/static/bidder-params/pubmatic.json
index a13b5906..2b903608 100644
--- a/static/bidder-params/pubmatic.json
+++ b/static/bidder-params/pubmatic.json
@@ -24,6 +24,13 @@
 			"type": "string",
 			"description": "Deals Custom Targeting, pipe separated key-value pairs e.g key1=V1,V2,V3|key2=v1|key3=v3,v5"
 		},
+		"acat": {
+			"type": "array",
+			"description": "List of allowed categories for a given auction to be sent in request.ext",
+			"items": {
+				"type": "string"
+			}
+		},
 		"wrapper": {
 			"type": "object",
 			"description": "Specifies pubmatic openwrap configuration for a publisher",
diff --git a/usersync/syncer.go b/usersync/syncer.go
index c944cf0b..c9ca39c2 100644
--- a/usersync/syncer.go
+++ b/usersync/syncer.go
@@ -60,9 +60,8 @@ const (
 
 var ErrSyncerEndpointRequired = errors.New("at least one endpoint (iframe and/or redirect) is required")
 var ErrSyncerKeyRequired = errors.New("key is required")
-var ErrSyncerDefaultSyncTypeRequired = errors.New("default sync type is required when more then one sync endpoint is configured")
 
-// NewSyncer creates a new Syncer from the provided configuration, or an error if macro substition
+// NewSyncer creates a new Syncer from the provided configuration, or return an error if macro substition
 // fails or an endpoint url is invalid.
 func NewSyncer(hostConfig config.UserSync, syncerConfig config.Syncer) (Syncer, error) {
 	if syncerConfig.Key == "" {
@@ -74,14 +73,9 @@ func NewSyncer(hostConfig config.UserSync, syncerConfig config.Syncer) (Syncer,
 	}
 
 	syncer := standardSyncer{
-		key:         syncerConfig.Key,
-		supportCORS: syncerConfig.SupportCORS != nil && *syncerConfig.SupportCORS,
-	}
-
-	if defaultSyncType, err := resolveDefaultSyncType(syncerConfig); err != nil {
-		return nil, err
-	} else {
-		syncer.defaultSyncType = defaultSyncType
+		key:             syncerConfig.Key,
+		defaultSyncType: resolveDefaultSyncType(syncerConfig),
+		supportCORS:     syncerConfig.SupportCORS != nil && *syncerConfig.SupportCORS,
 	}
 
 	if syncerConfig.IFrame != nil {
@@ -109,32 +103,11 @@ func NewSyncer(hostConfig config.UserSync, syncerConfig config.Syncer) (Syncer,
 	return syncer, nil
 }
 
-func resolveDefaultSyncType(syncerConfig config.Syncer) (SyncType, error) {
-	if syncerConfig.Default == "" {
-		if syncerConfig.IFrame != nil && syncerConfig.Redirect != nil {
-			return SyncTypeUnknown, ErrSyncerDefaultSyncTypeRequired
-		} else if syncerConfig.IFrame != nil {
-			return SyncTypeIFrame, nil
-		} else {
-			return SyncTypeRedirect, nil
-		}
-	}
-
-	if syncType, err := SyncTypeParse(syncerConfig.Default); err == nil {
-		switch syncType {
-		case SyncTypeIFrame:
-			if syncerConfig.IFrame == nil {
-				return SyncTypeUnknown, errDefaultTypeMissingIFrame
-			}
-		case SyncTypeRedirect:
-			if syncerConfig.Redirect == nil {
-				return SyncTypeUnknown, errDefaultTypeMissingRedirect
-			}
-		}
-		return syncType, nil
+func resolveDefaultSyncType(syncerConfig config.Syncer) SyncType {
+	if syncerConfig.IFrame != nil {
+		return SyncTypeIFrame
 	}
-
-	return SyncTypeUnknown, fmt.Errorf("invalid default sync type '%s'", syncerConfig.Default)
+	return SyncTypeRedirect
 }
 
 // macro substitution regex
diff --git a/usersync/syncersbuilder.go b/usersync/syncersbuilder.go
index 95b3e989..4c4c4207 100644
--- a/usersync/syncersbuilder.go
+++ b/usersync/syncersbuilder.go
@@ -91,7 +91,7 @@ func shouldCreateSyncer(cfg config.BidderInfo) bool {
 
 	// a syncer may provide just a Supports field to provide hints to the host. we should only try to create a syncer
 	// if there is at least one non-Supports value populated.
-	return cfg.Syncer.Key != "" || cfg.Syncer.Default != "" || cfg.Syncer.IFrame != nil || cfg.Syncer.Redirect != nil || cfg.Syncer.SupportCORS != nil
+	return cfg.Syncer.Key != "" || cfg.Syncer.IFrame != nil || cfg.Syncer.Redirect != nil || cfg.Syncer.SupportCORS != nil
 }
 
 func chooseSyncerConfig(biddersSyncerConfig []namedSyncerConfig) (namedSyncerConfig, error) {
diff --git a/usersync/synctype.go b/usersync/synctype.go
index c9e59f36..5bacb9f0 100644
--- a/usersync/synctype.go
+++ b/usersync/synctype.go
@@ -1,10 +1,5 @@
 package usersync
 
-import (
-	"fmt"
-	"strings"
-)
-
 // SyncType specifies the mechanism used to perform a user sync.
 type SyncType string
 
@@ -21,19 +16,6 @@ const (
 	SyncTypeRedirect SyncType = "redirect"
 )
 
-// SyncTypeParse returns the SyncType parsed from a string, case insensitive.
-func SyncTypeParse(v string) (SyncType, error) {
-	if strings.EqualFold(v, string(SyncTypeIFrame)) {
-		return SyncTypeIFrame, nil
-	}
-
-	if strings.EqualFold(v, string(SyncTypeRedirect)) {
-		return SyncTypeRedirect, nil
-	}
-
-	return SyncTypeUnknown, fmt.Errorf("invalid sync type `%s`", v)
-}
-
 // SyncTypeFilter determines which sync types, if any, the bidder is permitted to use.
 type SyncTypeFilter struct {
 	IFrame   BidderFilter


Test patch:
diff --git a/adapters/adyoulike/adyoulike_test.go b/adapters/adyoulike/adyoulike_test.go
index 9ab689f3..e4d21a87 100644
--- a/adapters/adyoulike/adyoulike_test.go
+++ b/adapters/adyoulike/adyoulike_test.go
@@ -12,7 +12,8 @@ const testsBidderEndpoint = "https://localhost/bid/4"
 
 func TestJsonSamples(t *testing.T) {
 	bidder, buildErr := Builder(openrtb_ext.BidderAdyoulike, config.Adapter{
-		Endpoint: testsBidderEndpoint})
+		Endpoint: testsBidderEndpoint,
+	})
 
 	if buildErr != nil {
 		t.Fatalf("Builder returned unexpected error %v", buildErr)
diff --git a/adapters/adyoulike/adyouliketest/exemplary/currency-conversion.json b/adapters/adyoulike/adyouliketest/exemplary/currency-conversion.json
new file mode 100644
index 00000000..85e14fbe
--- /dev/null
+++ b/adapters/adyoulike/adyouliketest/exemplary/currency-conversion.json
@@ -0,0 +1,115 @@
+{
+    "mockBidRequest": {
+      "id": "test-request-id",
+      "imp": [
+        {
+          "id": "banner-imp-id",
+          "banner": {
+            "format": [
+              {
+                "w": 300,
+                "h": 250
+              }
+            ]
+          },
+          "bidfloor": 1.00,
+          "bidfloorcur": "EUR",
+          "ext": {
+            "bidder": {
+              "placement": "12345"
+            }
+          }
+        }
+      ],
+      "ext": {
+        "prebid": {
+          "currency": {
+            "rates": {
+              "EUR": {
+                "USD": 0.05
+              }
+            },
+            "usepbsrates": false
+          }
+        }
+      }
+    },
+    "httpCalls": [
+      {
+        "expectedRequest": {
+          "uri": "https://localhost/bid/4",
+          "body": {
+            "id": "test-request-id",
+            "cur": ["USD"],
+            "imp": [
+              {
+                "banner": {
+                  "format": [
+                    {
+                      "h": 250,
+                      "w": 300
+                    }
+                  ]
+                },
+                "bidfloor": 0.05,
+                "bidfloorcur": "USD",
+                "ext": {
+                  "bidder": {
+                    "placement": "12345"
+                  }
+                },
+                "id": "banner-imp-id",
+                "tagid": "12345"
+              }
+            ],
+            "ext": {
+              "prebid": {
+                "currency": {
+                  "rates": {
+                    "EUR": {
+                      "USD": 0.05
+                    }
+                  },
+                  "usepbsrates": false
+                }
+              }
+             }
+          }
+        },
+        "mockResponse": {
+          "status": 200,
+          "body": {
+            "id": "test-response-id",
+            "cur": "USD",
+            "seatbid": [{
+              "seat": "1",
+              "bid": [{
+                  "id":    "12340",
+                  "impid": "banner-imp-id",
+                  "price": 300,
+                  "adm": "%3C%3Fxml%20version%3D%221.0%22%20encod%2Fhtml%3E",
+                  "nurl": "http://example.com/winnoticeurl0"
+                }
+              ]
+            }]
+          }
+        }
+      }
+    ],
+    "expectedBidResponses": [
+      {
+        "bids": [
+          {
+            "bid": {
+              "id":    "12340",
+              "impid": "banner-imp-id",
+              "price": 300,
+              "nurl":  "http://example.com/winnoticeurl0",
+              "adm":   "%3C%3Fxml%20version%3D%221.0%22%20encod%2Fhtml%3E"
+            },
+            "type": "banner"
+          }
+        ]
+      }
+    ]
+  }
diff --git a/adapters/adyoulike/adyouliketest/exemplary/multiformat-impression.json b/adapters/adyoulike/adyouliketest/exemplary/multiformat-impression.json
index 2ae99c04..8e69fcf5 100644
--- a/adapters/adyoulike/adyouliketest/exemplary/multiformat-impression.json
+++ b/adapters/adyoulike/adyouliketest/exemplary/multiformat-impression.json
@@ -49,6 +49,7 @@
           "uri": "https://localhost/bid/4",
           "body": {
             "id": "test-request-id",
+            "cur": ["USD"],
             "imp": [
               {
                 "banner": {
diff --git a/adapters/adyoulike/adyouliketest/supplemental/currency-missing-conversion.json b/adapters/adyoulike/adyouliketest/supplemental/currency-missing-conversion.json
new file mode 100644
index 00000000..d7d65e43
--- /dev/null
+++ b/adapters/adyoulike/adyouliketest/supplemental/currency-missing-conversion.json
@@ -0,0 +1,43 @@
+{
+    "mockBidRequest": {
+      "id": "test-request-id",
+      "imp": [
+        {
+          "id": "banner-imp-id",
+          "banner": {
+            "format": [
+              {
+                "w": 300,
+                "h": 250
+              }
+            ]
+          },
+          "bidfloor": 1.00,
+          "bidfloorcur": "JPY",
+          "ext": {
+            "bidder": {
+              "placement": "12345"
+            }
+          }
+        }
+      ],
+      "ext": {
+        "prebid": {
+          "currency": {
+              "rates": {
+              "MXN": {
+                  "USD": 0.05
+              }
+              },
+              "usepbsrates": false
+          }
+        }
+      }
+    },
+    "expectedMakeRequestsErrors": [
+      {
+        "value": "Currency conversion rate not found: 'JPY' => 'USD'",
+        "comparison": "literal"
+      }
+    ]
+  }
diff --git a/adapters/adyoulike/adyouliketest/supplemental/invalid-bid-response.json b/adapters/adyoulike/adyouliketest/supplemental/invalid-bid-response.json
index bda8d3e6..01a80efd 100644
--- a/adapters/adyoulike/adyouliketest/supplemental/invalid-bid-response.json
+++ b/adapters/adyoulike/adyouliketest/supplemental/invalid-bid-response.json
@@ -26,6 +26,7 @@
           "uri": "https://localhost/bid/4",
           "body": {
             "id": "test-request-id",
+            "cur": ["USD"],
             "imp": [
               {
                 "banner": {
diff --git a/adapters/adyoulike/adyouliketest/supplemental/status-bad-request.json b/adapters/adyoulike/adyouliketest/supplemental/status-bad-request.json
index 83b5f361..5c4c2df3 100644
--- a/adapters/adyoulike/adyouliketest/supplemental/status-bad-request.json
+++ b/adapters/adyoulike/adyouliketest/supplemental/status-bad-request.json
@@ -26,6 +26,7 @@
           "uri": "https://localhost/bid/4",
           "body": {
             "id": "test-request-id",
+            "cur": ["USD"],
             "imp": [
               {
                 "banner": {
diff --git a/adapters/adyoulike/adyouliketest/supplemental/status-no-content.json b/adapters/adyoulike/adyouliketest/supplemental/status-no-content.json
index d7d7df19..c296128e 100644
--- a/adapters/adyoulike/adyouliketest/supplemental/status-no-content.json
+++ b/adapters/adyoulike/adyouliketest/supplemental/status-no-content.json
@@ -26,6 +26,7 @@
           "uri": "https://localhost/bid/4",
           "body": {
             "id": "test-request-id",
+            "cur": ["USD"],
             "imp": [
               {
                 "banner": {
diff --git a/adapters/adyoulike/adyouliketest/supplemental/status-service-unavailable.json b/adapters/adyoulike/adyouliketest/supplemental/status-service-unavailable.json
index 2b5872a1..445d01e2 100644
--- a/adapters/adyoulike/adyouliketest/supplemental/status-service-unavailable.json
+++ b/adapters/adyoulike/adyouliketest/supplemental/status-service-unavailable.json
@@ -26,6 +26,7 @@
           "uri": "https://localhost/bid/4",
           "body": {
             "id": "test-request-id",
+            "cur": ["USD"],
             "imp": [
               {
                 "banner": {
diff --git a/adapters/adyoulike/adyouliketest/supplemental/status-unknown.json b/adapters/adyoulike/adyouliketest/supplemental/status-unknown.json
index 0b9ce745..5177befd 100644
--- a/adapters/adyoulike/adyouliketest/supplemental/status-unknown.json
+++ b/adapters/adyoulike/adyouliketest/supplemental/status-unknown.json
@@ -26,6 +26,7 @@
           "uri": "https://localhost/bid/4",
           "body": {
             "id": "test-request-id",
+            "cur": ["USD"],
             "imp": [
               {
                 "banner": {
diff --git a/adapters/pubmatic/pubmatic_test.go b/adapters/pubmatic/pubmatic_test.go
index da5f632e..4985d052 100644
--- a/adapters/pubmatic/pubmatic_test.go
+++ b/adapters/pubmatic/pubmatic_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
 	"github.com/prebid/prebid-server/adapters/adapterstest"
 	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/openrtb_ext"
@@ -150,3 +151,116 @@ func TestParseImpressionObject(t *testing.T) {
 		})
 	}
 }
+
+func TestExtractPubmaticExtFromRequest(t *testing.T) {
+	type args struct {
+		request *openrtb2.BidRequest
+	}
+	tests := []struct {
+		name               string
+		args               args
+		expectedWrapperExt *pubmaticWrapperExt
+		expectedAcat       []string
+		wantErr            bool
+	}{
+		{
+			name:    "Empty bidder param",
+			wantErr: true,
+		},
+		{
+			name: "Pubmatic wrapper ext missing/empty",
+			args: args{
+				request: &openrtb2.BidRequest{
+					Ext: json.RawMessage(`{"prebid":{"bidderparams":{}}}`),
+				},
+			},
+			wantErr: false,
+		},
+		{
+			name: "Only Pubmatic wrapper ext present",
+			args: args{
+				request: &openrtb2.BidRequest{
+					Ext: json.RawMessage(`{"prebid":{"bidderparams":{"wrapper":{"profile":123,"version":456}}}}`),
+				},
+			},
+			expectedWrapperExt: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456},
+			wantErr:            false,
+		},
+		{
+			name: "Invalid Pubmatic wrapper ext",
+			args: args{
+				request: &openrtb2.BidRequest{
+					Ext: json.RawMessage(`{"prebid":{"bidderparams":{"wrapper":{"profile":"123","version":456}}}}`),
+				},
+			},
+			wantErr: true,
+		},
+		{
+			name: "Valid Pubmatic acat ext",
+			args: args{
+				request: &openrtb2.BidRequest{
+					Ext: json.RawMessage(`{"prebid":{"bidderparams":{"acat":[" drg \t","dlu","ssr"],"wrapper":{"profile":123,"version":456}}}}`),
+				},
+			},
+			expectedWrapperExt: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456},
+			expectedAcat:       []string{"drg", "dlu", "ssr"},
+			wantErr:            false,
+		},
+		{
+			name: "Invalid Pubmatic acat ext. We are ok with acat being non nil in this case as we are returning unmarshal error",
+			args: args{
+				request: &openrtb2.BidRequest{
+					Ext: json.RawMessage(`{"prebid":{"bidderparams":{"acat":[1,3,4],"wrapper":{"profile":123,"version":456}}}}`),
+				},
+			},
+			expectedWrapperExt: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456},
+			expectedAcat:       []string{"", "", ""},
+			wantErr:            true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			gotWrapperExt, gotAcat, err := extractPubmaticExtFromRequest(tt.args.request)
+			assert.Equal(t, tt.wantErr, err != nil)
+			assert.Equal(t, tt.expectedWrapperExt, gotWrapperExt)
+			assert.Equal(t, tt.expectedAcat, gotAcat)
+		})
+	}
+}
+
+func TestPubmaticAdapter_MakeRequests(t *testing.T) {
+	type fields struct {
+		URI string
+	}
+	type args struct {
+		request *openrtb2.BidRequest
+		reqInfo *adapters.ExtraRequestInfo
+	}
+	tests := []struct {
+		name            string
+		fields          fields
+		args            args
+		expectedReqData []*adapters.RequestData
+		wantErr         bool
+	}{
+		// Happy paths covered by TestJsonSamples()
+		// Covering only error scenarios here
+		{
+			name: "invalid bidderparams",
+			args: args{
+				request: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"bidderparams":{"wrapper":"123"}}}`)},
+			},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			a := &PubmaticAdapter{
+				URI: tt.fields.URI,
+			}
+			gotReqData, gotErr := a.MakeRequests(tt.args.request, tt.args.reqInfo)
+			assert.Equal(t, tt.wantErr, len(gotErr) != 0)
+			assert.Equal(t, tt.expectedReqData, gotReqData)
+		})
+	}
+}
diff --git a/adapters/pubmatic/pubmatictest/exemplary/banner.json b/adapters/pubmatic/pubmatictest/exemplary/banner.json
index 313099f2..5012192a 100644
--- a/adapters/pubmatic/pubmatictest/exemplary/banner.json
+++ b/adapters/pubmatic/pubmatictest/exemplary/banner.json
@@ -33,6 +33,13 @@
         "device":{
             "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
         },
+        "ext": {
+          "prebid": {
+            "bidderparams": {
+              "acat": ["drg","dlu","ssr"]
+            }
+          }
+        },
         "site": {
 		      	"id": "siteID",
 		    	  "publisher": {
@@ -81,7 +88,8 @@
                 "wrapper": {
                     "profile": 5123,
                     "version":1
-                }
+                },
+                "acat": ["drg","dlu","ssr"]
             }
           }
         },
diff --git a/adapters/pubmatic/pubmatictest/exemplary/video.json b/adapters/pubmatic/pubmatictest/exemplary/video.json
index 693ee3eb..cc43fc89 100644
--- a/adapters/pubmatic/pubmatictest/exemplary/video.json
+++ b/adapters/pubmatic/pubmatictest/exemplary/video.json
@@ -44,7 +44,14 @@
 		    	"publisher": {
 			    	"id": "1234"
 		  	}
-	  	}
+	  	},
+      "ext": {
+        "prebid": {
+          "bidderparams": {
+            "acat": ["drg","dlu","ssr"]
+          }
+        }
+      }
     },
   
     "httpCalls": [
@@ -92,7 +99,8 @@
                 "wrapper": {
                     "profile": 5123,
                     "version":1
-                }
+                },
+                "acat": ["drg","dlu","ssr"]
             }
           }
         },
diff --git a/adapters/yahoossp/yahoossptest/exemplary/simple-video.json b/adapters/yahoossp/yahoossptest/exemplary/simple-video.json
new file mode 100644
index 00000000..d6227264
--- /dev/null
+++ b/adapters/yahoossp/yahoossptest/exemplary/simple-video.json
@@ -0,0 +1,132 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "w": 728, 
+          "h": 90,
+          "protocols": [2],
+          "placement": 1,
+          "startdelay": -2,
+          "playbackmethod": [2],
+          "mimes": ["foo", "bar"]
+        },
+        "ext": {
+          "bidder": {
+            "dcn": "dcn1",
+            "pos": "pos2"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+      "ip": "127.0.0.1"
+    },
+    "site": {
+      "id": "test-site-id",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ]
+        },
+        "uri": "",
+        "body": {
+          "device": {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+            "ip": "127.0.0.1"
+          },
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id":"test-imp-id",
+              "tagid": "pos2",
+              "video": {
+                "w": 728, 
+                "h": 90,
+                "protocols": [2],
+                "placement": 1,
+                "startdelay": -2,
+                "playbackmethod": [2],
+                "mimes": ["foo", "bar"]
+              },
+              "ext": {
+                "bidder": {
+                  "dcn": "dcn1",
+                  "pos": "pos2"
+                }
+              }
+            }
+          ],
+          "site": {
+            "id": "dcn1",
+            "publisher": {
+              "id": "1"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "yahoossp",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adm": "some-test-vast-ad",
+                "crid": "crid_10",
+                "h": 90,
+                "w": 728
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-test-vast-ad",
+            "crid": "crid_10",
+            "w": 728,
+            "h": 90
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/yahoossp/yahoossptest/supplemental/invalid-banner-height.json b/adapters/yahoossp/yahoossptest/supplemental/invalid-banner-height.json
new file mode 100644
index 00000000..da4f7918
--- /dev/null
+++ b/adapters/yahoossp/yahoossptest/supplemental/invalid-banner-height.json
@@ -0,0 +1,26 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "w": 728,
+          "h": 0
+        },
+        "ext": {
+          "bidder": {
+          }
+        }
+      }
+    ],
+    "site": {}
+  },
+
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Invalid sizes provided for Banner 728x0",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/yahoossp/yahoossptest/supplemental/non-banner-bids-ignored.json b/adapters/yahoossp/yahoossptest/supplemental/non-supported-requests-bids-ignored.json
similarity index 95%
rename from adapters/yahoossp/yahoossptest/supplemental/non-banner-bids-ignored.json
rename to adapters/yahoossp/yahoossptest/supplemental/non-supported-requests-bids-ignored.json
index 6f40e2a9..11a93f68 100644
--- a/adapters/yahoossp/yahoossptest/supplemental/non-banner-bids-ignored.json
+++ b/adapters/yahoossp/yahoossptest/supplemental/non-supported-requests-bids-ignored.json
@@ -4,8 +4,8 @@
     "imp": [
       {
         "id": "test-imp-id",
-        "video": {
-          "mimes": ["video/mp4"]
+        "audio": {
+          "mimes": ["audio/mp3"]
         },
         "ext": {
           "bidder": {
@@ -52,8 +52,8 @@
             {
               "id": "test-imp-id",
               "tagid": "pos2",
-              "video": {
-               "mimes": ["video/mp4"]
+              "audio": {
+               "mimes": ["audio/mp3"]
               },
               "ext": {
                 "bidder": {
diff --git a/adapters/yahoossp/yahoossptest/supplemental/simple-banner-ignore-width-when-height-missing.json b/adapters/yahoossp/yahoossptest/supplemental/simple-banner-ignore-width-when-height-missing.json
new file mode 100644
index 00000000..16e64c61
--- /dev/null
+++ b/adapters/yahoossp/yahoossptest/supplemental/simple-banner-ignore-width-when-height-missing.json
@@ -0,0 +1,118 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "w": 300,
+          "format": [{"w": 728, "h": 90}]
+        },
+        "tagid": "123",
+        "ext": {
+          "bidder": {
+            "dcn": "dcn1",
+            "pos": "pos2"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+      "ip": "127.0.0.1"
+    },
+    "site": {
+      "id": "test-site-id"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ]
+        },
+        "uri": "",
+        "body": {
+          "device": {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+            "ip": "127.0.0.1"
+          },
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "tagid": "pos2",
+              "banner": {
+                "format": [{"w": 728, "h": 90}],
+                "w": 728,
+                "h": 90
+              },
+              "ext": {
+                "bidder": {
+                  "dcn": "dcn1",
+                  "pos": "pos2"
+                }
+              }
+            }
+          ],
+          "site": {
+            "id": "dcn1"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "yahoossp",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "h": 90,
+                "w": 728
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "w": 728,
+            "h": 90
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/config/bidderinfo_test.go b/config/bidderinfo_test.go
index 9cf5fe09..df5b8591 100644
--- a/config/bidderinfo_test.go
+++ b/config/bidderinfo_test.go
@@ -44,8 +44,7 @@ func TestLoadBidderInfoFromDisk(t *testing.T) {
 				},
 			},
 			Syncer: &Syncer{
-				Key:     "foo",
-				Default: "iframe",
+				Key: "foo",
 				IFrame: &SyncerEndpoint{
 					URL:         "https://foo.com/sync?mode=iframe&r={{.RedirectURL}}",
 					RedirectURL: "{{.ExternalURL}}/setuid/iframe",
@@ -208,12 +207,6 @@ func TestSyncerOverride(t *testing.T) {
 			givenOverride: &Syncer{Key: "override"},
 			expected:      &Syncer{Key: "override"},
 		},
-		{
-			description:   "Override Default",
-			givenOriginal: &Syncer{Default: "original"},
-			givenOverride: &Syncer{Default: "override"},
-			expected:      &Syncer{Default: "override"},
-		},
 		{
 			description:   "Override IFrame",
 			givenOriginal: &Syncer{IFrame: &SyncerEndpoint{URL: "original"}},
@@ -240,9 +233,9 @@ func TestSyncerOverride(t *testing.T) {
 		},
 		{
 			description:   "Override Partial - Other Fields Untouched",
-			givenOriginal: &Syncer{Key: "originalKey", Default: "originalDefault"},
-			givenOverride: &Syncer{Default: "overrideDefault"},
-			expected:      &Syncer{Key: "originalKey", Default: "overrideDefault"},
+			givenOriginal: &Syncer{Key: "originalKey", ExternalURL: "originalExternalURL"},
+			givenOverride: &Syncer{ExternalURL: "overrideExternalURL"},
+			expected:      &Syncer{Key: "originalKey", ExternalURL: "overrideExternalURL"},
 		},
 	}
 
diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go
index 190405db..0f56036d 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -1855,13 +1855,13 @@ func TestStoredRequestGenerateUuid(t *testing.T) {
 			expectedID:             uuid,
 		},
 		{
-			description:            "GenerateRequestID is true, rawData is an app request, has stored bid, and stored bidrequestID is not the macro {{UUID}}, we should generate uuid",
+			description:            "GenerateRequestID is true, rawData is a site request, has stored bid, and stored bidrequestID is not the macro {{UUID}}, we should not generate uuid",
 			givenRawData:           testBidRequests[3],
 			givenGenerateRequestID: true,
-			expectedID:             uuid,
+			expectedID:             "ThisID",
 		},
 		{
-			description:            "GenerateRequestID is false, rawData is an app request and has stored bid, but stored bidrequestID is the macro {{UUID}}, so we should generate uuid",
+			description:            "GenerateRequestID is false, rawData is an app request and has stored bid, and stored bidrequestID is the macro {{UUID}}, so we should generate uuid",
 			givenRawData:           testBidRequests[4],
 			givenGenerateRequestID: false,
 			expectedID:             uuid,
@@ -1879,10 +1879,10 @@ func TestStoredRequestGenerateUuid(t *testing.T) {
 			expectedID:             "ThisID",
 		},
 		{
-			description:            "GenerateRequestID is true, but rawData is a site request, we should not generate uuid",
+			description:            "GenerateRequestID is false, and rawData is a site request, and macro {{UUID}} is present, we should generate uuid",
 			givenRawData:           testBidRequests[1],
-			givenGenerateRequestID: true,
-			expectedID:             "ThisID",
+			givenGenerateRequestID: false,
+			expectedID:             uuid,
 		},
 		{
 			description:            "Macro ID {{UUID}} case sensitivity check meaning a macro that is lowercase {{uuid}} shouldn't generate a uuid",
@@ -1891,19 +1891,12 @@ func TestStoredRequestGenerateUuid(t *testing.T) {
 			expectedID:             "ThisID",
 		},
 		{
-			description:            "Test to check that stored requests are being merged when Macro ID is present with a site rquest",
+			description:            "Test to check that stored requests are being merged properly when UUID isn't being generated",
 			givenRawData:           testBidRequests[5],
 			givenGenerateRequestID: false,
 			expectedID:             "ThisID",
 			expectedCur:            "USD",
 		},
-		{
-			description:            "Test to check that stored requests are being merged when Generate Request ID flag with a site rquest",
-			givenRawData:           testBidRequests[5],
-			givenGenerateRequestID: true,
-			expectedID:             "ThisID",
-			expectedCur:            "USD",
-		},
 	}
 
 	for _, test := range testCases {
@@ -3966,7 +3959,7 @@ var testStoredRequestData = map[string]json.RawMessage{
 						}
 				}}
 		}`),
-	"4": json.RawMessage(`{"id": "{{UUID}}", "cur": ["USD"]}`),
+	"4": json.RawMessage(`{"id": "ThisID", "cur": ["USD"]}`),
 }
 
 // Stored Imp Requests
@@ -4455,7 +4448,8 @@ var testBidRequests = []string{
 		],
 		"ext": {
 			"prebid": {
-				"targeting": {
+				"storedrequest": {
+					"id": "1"
 				}
 			}
 		}
@@ -4489,8 +4483,8 @@ var testBidRequests = []string{
 	}`,
 	`{
 		"id": "ThisID",
-		"app": {
-			"id": "123"
+		"site": {
+			"page": "prebid.org"
 		},
 		"imp": [
 			{
diff --git a/exchange/targeting_test.go b/exchange/targeting_test.go
index f2726de0..d452d191 100644
--- a/exchange/targeting_test.go
+++ b/exchange/targeting_test.go
@@ -262,8 +262,9 @@ var bid084 *openrtb2.Bid = &openrtb2.Bid{
 	Price: 0.84,
 }
 
-var truncateTargetAttrValueLess int = 10
-var truncateTargetAttrValueGreater int = 25
+var truncateTargetAttrValue10 int = 10
+var truncateTargetAttrValue5 int = 5
+var truncateTargetAttrValue25 int = 25
 var truncateTargetAttrValueNegative int = -1
 var TargetingTests []TargetingTestData = []TargetingTestData{
 	{
@@ -451,7 +452,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{
 				},
 			},
 		},
-		TruncateTargetAttr: &truncateTargetAttrValueLess,
+		TruncateTargetAttr: &truncateTargetAttrValue10,
 	},
 	{
 		Description: "Truncate Targeting Attribute value is given and is greater than const MaxKeyLength",
@@ -485,7 +486,7 @@ var TargetingTests []TargetingTestData = []TargetingTestData{
 				},
 			},
 		},
-		TruncateTargetAttr: &truncateTargetAttrValueGreater,
+		TruncateTargetAttr: &truncateTargetAttrValue25,
 	},
 	{
 		Description: "Truncate Targeting Attribute value is given and is negative",
@@ -521,6 +522,99 @@ var TargetingTests []TargetingTestData = []TargetingTestData{
 		},
 		TruncateTargetAttr: &truncateTargetAttrValueNegative,
 	},
+	{
+		Description: "Check that key gets truncated properly when value is smaller than key",
+		TargetData: targetData{
+			priceGranularity: openrtb_ext.PriceGranularityFromString("med"),
+			includeWinners:   true,
+		},
+		Auction: auction{
+			winningBidsByBidder: map[string]map[openrtb_ext.BidderName]*pbsOrtbBid{
+				"ImpId-1": {
+					openrtb_ext.BidderAppnexus: {
+						bid:     bid123,
+						bidType: openrtb_ext.BidTypeBanner,
+					},
+					openrtb_ext.BidderRubicon: {
+						bid:     bid084,
+						bidType: openrtb_ext.BidTypeBanner,
+					},
+				},
+			},
+		},
+		ExpectedBidTargetsByBidder: map[string]map[openrtb_ext.BidderName]map[string]string{
+			"ImpId-1": {
+				openrtb_ext.BidderAppnexus: {
+					"hb_bi": "appnexus",
+					"hb_pb": "1.20",
+				},
+				openrtb_ext.BidderRubicon: {},
+			},
+		},
+		TruncateTargetAttr: &truncateTargetAttrValue5,
+	},
+	{
+		Description: "Check that key gets truncated properly when value is greater than key",
+		TargetData: targetData{
+			priceGranularity: openrtb_ext.PriceGranularityFromString("med"),
+			includeWinners:   true,
+		},
+		Auction: auction{
+			winningBidsByBidder: map[string]map[openrtb_ext.BidderName]*pbsOrtbBid{
+				"ImpId-1": {
+					openrtb_ext.BidderAppnexus: {
+						bid:     bid123,
+						bidType: openrtb_ext.BidTypeBanner,
+					},
+					openrtb_ext.BidderRubicon: {
+						bid:     bid084,
+						bidType: openrtb_ext.BidTypeBanner,
+					},
+				},
+			},
+		},
+		ExpectedBidTargetsByBidder: map[string]map[openrtb_ext.BidderName]map[string]string{
+			"ImpId-1": {
+				openrtb_ext.BidderAppnexus: {
+					"hb_bidder": "appnexus",
+					"hb_pb":     "1.20",
+				},
+				openrtb_ext.BidderRubicon: {},
+			},
+		},
+		TruncateTargetAttr: &truncateTargetAttrValue25,
+	},
+	{
+		Description: "Check that key gets truncated properly when value is negative",
+		TargetData: targetData{
+			priceGranularity: openrtb_ext.PriceGranularityFromString("med"),
+			includeWinners:   true,
+		},
+		Auction: auction{
+			winningBidsByBidder: map[string]map[openrtb_ext.BidderName]*pbsOrtbBid{
+				"ImpId-1": {
+					openrtb_ext.BidderAppnexus: {
+						bid:     bid123,
+						bidType: openrtb_ext.BidTypeBanner,
+					},
+					openrtb_ext.BidderRubicon: {
+						bid:     bid084,
+						bidType: openrtb_ext.BidTypeBanner,
+					},
+				},
+			},
+		},
+		ExpectedBidTargetsByBidder: map[string]map[openrtb_ext.BidderName]map[string]string{
+			"ImpId-1": {
+				openrtb_ext.BidderAppnexus: {
+					"hb_bidder": "appnexus",
+					"hb_pb":     "1.20",
+				},
+				openrtb_ext.BidderRubicon: {},
+			},
+		},
+		TruncateTargetAttr: &truncateTargetAttrValueNegative,
+	},
 }
 
 func TestSetTargeting(t *testing.T) {
diff --git a/firstpartydata/first_party_data_test.go b/firstpartydata/first_party_data_test.go
index 1e09bab1..1e0dc015 100644
--- a/firstpartydata/first_party_data_test.go
+++ b/firstpartydata/first_party_data_test.go
@@ -762,7 +762,7 @@ func TestResolveUser(t *testing.T) {
 	fpdConfigUser[yobKey] = []byte(`1980`)
 	fpdConfigUser[genderKey] = []byte(`"M"`)
 	fpdConfigUser[keywordsKey] = []byte(`"fpdConfigUserKeywords"`)
-	fpdConfigUser["data"] = []byte(`[{"id":"UserDataId1", "name":"UserDataName1"}, {"id":"UserDataId2", "name":"UserDataName2"}]`)
+	fpdConfigUser[dataKey] = []byte(`[{"id":"UserDataId1", "name":"UserDataName1"}, {"id":"UserDataId2", "name":"UserDataName2"}]`)
 	fpdConfigUser["ext"] = []byte(`{"data":{"fpdConfigUserExt": 123}}`)
 
 	bidRequestUser := &openrtb2.User{
@@ -789,6 +789,8 @@ func TestResolveUser(t *testing.T) {
 		Data: []openrtb2.Data{
 			{ID: "openRtbGlobalFPDUserDataId1", Name: "openRtbGlobalFPDUserDataName1"},
 			{ID: "openRtbGlobalFPDUserDataId2", Name: "openRtbGlobalFPDUserDataName2"},
+			{ID: "UserDataId1", Name: "UserDataName1"},
+			{ID: "UserDataId2", Name: "UserDataName2"},
 		},
 	}
 
@@ -801,10 +803,6 @@ func TestResolveUser(t *testing.T) {
 			description:       "bid request user.ext is nil",
 			bidRequestUserExt: nil,
 			expectedUserExt: `{"data":{
-									"data":[
-										{"id":"UserDataId1","name":"UserDataName1"},
-										{"id":"UserDataId2","name":"UserDataName2"}
-									],
 									"fpdConfigUserExt":123,
 									"globalFPDUserData":"globalFPDUserDataValue",
 									"id":"fpdConfigUserId"
@@ -815,10 +813,6 @@ func TestResolveUser(t *testing.T) {
 			description:       "bid request user.ext is not nil",
 			bidRequestUserExt: []byte(`{"bidRequestUserExt": 1234}`),
 			expectedUserExt: `{"data":{
-									"data":[
-										{"id":"UserDataId1","name":"UserDataName1"},
-										{"id":"UserDataId2","name":"UserDataName2"}
-									],
 									"fpdConfigUserExt":123,
 									"globalFPDUserData":"globalFPDUserDataValue",
 									"id":"fpdConfigUserId"
@@ -836,7 +830,7 @@ func TestResolveUser(t *testing.T) {
 		fpdConfigUser[yobKey] = []byte(`1980`)
 		fpdConfigUser[genderKey] = []byte(`"M"`)
 		fpdConfigUser[keywordsKey] = []byte(`"fpdConfigUserKeywords"`)
-		fpdConfigUser["data"] = []byte(`[{"id":"UserDataId1", "name":"UserDataName1"}, {"id":"UserDataId2", "name":"UserDataName2"}]`)
+		fpdConfigUser[dataKey] = []byte(`[{"id":"UserDataId1", "name":"UserDataName1"}, {"id":"UserDataId2", "name":"UserDataName2"}]`)
 		fpdConfigUser["ext"] = []byte(`{"data":{"fpdConfigUserExt": 123}}`)
 		fpdConfig := &openrtb_ext.ORTB2{User: fpdConfigUser}
 
@@ -885,7 +879,7 @@ func TestMergeUsers(t *testing.T) {
 	fpdConfigUser[yobKey] = []byte(`1980`)
 	fpdConfigUser[genderKey] = []byte(`"M"`)
 	fpdConfigUser[keywordsKey] = []byte(`"fpdConfigUserKeywords"`)
-	fpdConfigUser["data"] = []byte(`[{"id":"UserDataId1", "name":"UserDataName1"}, {"id":"UserDataId2", "name":"UserDataName2"}]`)
+	fpdConfigUser[dataKey] = []byte(`[{"id":"UserDataId1", "name":"UserDataName1"}, {"id":"UserDataId2", "name":"UserDataName2"}]`)
 	fpdConfigUser["ext"] = []byte(`{"data":{"fpdConfigUserExt": 123}}`)
 
 	resultUser, err := mergeUsers(originalUser, fpdConfigUser)
@@ -893,9 +887,6 @@ func TestMergeUsers(t *testing.T) {
 
 	expectedUserExt := `{"bidRequestUserExt":1234,
 						 "data":{
-							"data":[
-								{"id":"UserDataId1","name":"UserDataName1"},
-								{"id":"UserDataId2","name":"UserDataName2"}],
 							"fpdConfigUserExt":123,
 							"id":"fpdConfigUserId"}
 						 }`
@@ -910,6 +901,8 @@ func TestMergeUsers(t *testing.T) {
 		Data: []openrtb2.Data{
 			{ID: "openRtbGlobalFPDUserDataId1", Name: "openRtbGlobalFPDUserDataName1"},
 			{ID: "openRtbGlobalFPDUserDataId2", Name: "openRtbGlobalFPDUserDataName2"},
+			{ID: "UserDataId1", Name: "UserDataName1"},
+			{ID: "UserDataId2", Name: "UserDataName2"},
 		},
 	}
 	assert.Equal(t, expectedUser, resultUser, "Result user is incorrect")
@@ -959,7 +952,7 @@ func TestResolveSite(t *testing.T) {
 	fpdConfigSite[keywordsKey] = []byte(`"fpdConfigSiteKeywords"`)
 	fpdConfigSite[nameKey] = []byte(`"fpdConfigSiteName"`)
 	fpdConfigSite[pageKey] = []byte(`"fpdConfigSitePage"`)
-	fpdConfigSite["data"] = []byte(`[{"id":"SiteDataId1", "name":"SiteDataName1"}, {"id":"SiteDataId2", "name":"SiteDataName2"}]`)
+	fpdConfigSite[dataKey] = []byte(`[{"id":"SiteDataId1", "name":"SiteDataName1"}, {"id":"SiteDataId2", "name":"SiteDataName2"}]`)
 	fpdConfigSite["ext"] = []byte(`{"data":{"fpdConfigSiteExt": 123}}`)
 
 	bidRequestSite := &openrtb2.Site{
@@ -1070,7 +1063,7 @@ func TestResolveSite(t *testing.T) {
 		fpdConfigSite := make(map[string]json.RawMessage, 0)
 		fpdConfigSite["id"] = []byte(`"fpdConfigSiteId"`)
 		fpdConfigSite[keywordsKey] = []byte(`"fpdConfigSiteKeywords"`)
-		fpdConfigSite["data"] = []byte(`[{"id":"SiteDataId1", "name":"SiteDataName1"}, {"id":"SiteDataId2", "name":"SiteDataName2"}]`)
+		fpdConfigSite[dataKey] = []byte(`[{"id":"SiteDataId1", "name":"SiteDataName1"}, {"id":"SiteDataId2", "name":"SiteDataName2"}]`)
 		fpdConfigSite["ext"] = []byte(`{"data":{"fpdConfigSiteExt": 123}}`)
 		fpdConfig := &openrtb_ext.ORTB2{Site: fpdConfigSite}
 
@@ -1134,7 +1127,7 @@ func TestMergeSites(t *testing.T) {
 	fpdConfigSite[pageCatKey] = []byte(`["cars3", "auto3"]`)
 	fpdConfigSite[searchKey] = []byte(`"fpdConfigSiteSearch"`)
 	fpdConfigSite[refKey] = []byte(`"fpdConfigSiteRef"`)
-	fpdConfigSite["data"] = []byte(`[{"id":"SiteDataId1", "name":"SiteDataName1"}, {"id":"SiteDataId2", "name":"SiteDataName2"}]`)
+	fpdConfigSite[dataKey] = []byte(`[{"id":"SiteDataId1", "name":"SiteDataName1"}, {"id":"SiteDataId2", "name":"SiteDataName2"}]`)
 	fpdConfigSite["ext"] = []byte(`{"data":{"fpdConfigSiteExt": 123}}`)
 
 	resultSite, err := mergeSites(originalSite, fpdConfigSite, "appnexus")
@@ -1181,7 +1174,7 @@ func TestResolveApp(t *testing.T) {
 	fpdConfigApp[keywordsKey] = []byte(`"fpdConfigAppKeywords"`)
 	fpdConfigApp[nameKey] = []byte(`"fpdConfigAppName"`)
 	fpdConfigApp[bundleKey] = []byte(`"fpdConfigAppBundle"`)
-	fpdConfigApp["data"] = []byte(`[{"id":"AppDataId1", "name":"AppDataName1"}, {"id":"AppDataId2", "name":"AppDataName2"}]`)
+	fpdConfigApp[dataKey] = []byte(`[{"id":"AppDataId1", "name":"AppDataName1"}, {"id":"AppDataId2", "name":"AppDataName2"}]`)
 	fpdConfigApp["ext"] = []byte(`{"data":{"fpdConfigAppExt": 123}}`)
 
 	bidRequestApp := &openrtb2.App{
@@ -1292,7 +1285,7 @@ func TestResolveApp(t *testing.T) {
 		fpdConfigApp := make(map[string]json.RawMessage, 0)
 		fpdConfigApp["id"] = []byte(`"fpdConfigAppId"`)
 		fpdConfigApp[keywordsKey] = []byte(`"fpdConfigAppKeywords"`)
-		fpdConfigApp["data"] = []byte(`[{"id":"AppDataId1", "name":"AppDataName1"}, {"id":"AppDataId2", "name":"AppDataName2"}]`)
+		fpdConfigApp[dataKey] = []byte(`[{"id":"AppDataId1", "name":"AppDataName1"}, {"id":"AppDataId2", "name":"AppDataName2"}]`)
 		fpdConfigApp["ext"] = []byte(`{"data":{"fpdConfigAppExt": 123}}`)
 		fpdConfig := &openrtb_ext.ORTB2{App: fpdConfigApp}
 
@@ -1356,7 +1349,7 @@ func TestMergeApps(t *testing.T) {
 	fpdConfigApp[catKey] = []byte(`["cars1", "auto1"]`)
 	fpdConfigApp[sectionCatKey] = []byte(`["cars2", "auto2"]`)
 	fpdConfigApp[pageCatKey] = []byte(`["cars3", "auto3"]`)
-	fpdConfigApp["data"] = []byte(`[{"id":"AppDataId1", "name":"AppDataName1"}, {"id":"AppDataId2", "name":"AppDataName2"}]`)
+	fpdConfigApp[dataKey] = []byte(`[{"id":"AppDataId1", "name":"AppDataName1"}, {"id":"AppDataId2", "name":"AppDataName2"}]`)
 	fpdConfigApp["ext"] = []byte(`{"data":{"fpdConfigAppExt": 123}}`)
 
 	resultApp, err := mergeApps(originalApp, fpdConfigApp)
diff --git a/firstpartydata/tests/extractfpdforbidders/two-bidders-global-and-non-global-user.json b/firstpartydata/tests/extractfpdforbidders/two-bidders-global-and-non-global-user.json
index c04838c7..ed81b415 100644
--- a/firstpartydata/tests/extractfpdforbidders/two-bidders-global-and-non-global-user.json
+++ b/firstpartydata/tests/extractfpdforbidders/two-bidders-global-and-non-global-user.json
@@ -200,19 +200,19 @@
         "gender": "F",
         "yob": 2000,
         "keywords": "apnFpdUserKeyword",
+        "data": [
+          {
+            "id": "apnFpdUserContentDataId1",
+            "name": "apnFpdUserContentDataName1"
+          },
+          {
+            "id": "apnFpdUserContentDataId2",
+            "name": "apnFpdUserContentDataName2"
+          }
+        ],
         "ext": {
           "data": {
-            "id": "apnUserId",
-            "data": [
-              {
-                "id": "apnFpdUserContentDataId1",
-                "name": "apnFpdUserContentDataName1"
-              },
-              {
-                "id": "apnFpdUserContentDataId2",
-                "name": "apnFpdUserContentDataName2"
-              }
-            ]
+            "id": "apnUserId"
           }
         }
       }
diff --git a/openrtb_ext/bid_test.go b/openrtb_ext/bid_test.go
index 43e5a8cf..aebc1d68 100644
--- a/openrtb_ext/bid_test.go
+++ b/openrtb_ext/bid_test.go
@@ -1,6 +1,10 @@
 package openrtb_ext
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
 
 func TestBidderKey(t *testing.T) {
 	apnKey := HbpbConstantKey.BidderKey(BidderAppnexus, 50)
@@ -16,6 +20,39 @@ func TestTruncatedKey(t *testing.T) {
 	}
 }
 
+func TestTruncateKey(t *testing.T) {
+	testCases := []struct {
+		description          string
+		givenMaxLength       int
+		givenTargetingKey    TargetingKey
+		expectedTargetingKey string
+	}{
+		{
+			description:          "Targeting key is smaller than max length, expect targeting key to stay the same",
+			givenMaxLength:       15,
+			givenTargetingKey:    TargetingKey("hb_bidder_key"),
+			expectedTargetingKey: "hb_bidder_key",
+		},
+		{
+			description:          "Targeting key is larger than max length, expect targeting key to be truncated",
+			givenMaxLength:       9,
+			givenTargetingKey:    TargetingKey("hb_bidder_key"),
+			expectedTargetingKey: "hb_bidder",
+		},
+		{
+			description:          "Max length isn't greater than zero, expect targeting key to not be truncated",
+			givenMaxLength:       0,
+			givenTargetingKey:    TargetingKey("hb_bidder_key"),
+			expectedTargetingKey: "hb_bidder_key",
+		},
+	}
+
+	for _, test := range testCases {
+		truncatedKey := test.givenTargetingKey.TruncateKey(test.givenMaxLength)
+		assert.Equalf(t, test.expectedTargetingKey, truncatedKey, "The Targeting Key is incorrect: %s\n", test.description)
+	}
+}
+
 func TestBidParsing(t *testing.T) {
 	assertBidParse(t, "banner", BidTypeBanner)
 	assertBidParse(t, "video", BidTypeVideo)
diff --git a/usersync/syncer_test.go b/usersync/syncer_test.go
index 6ff23009..21a86932 100644
--- a/usersync/syncer_test.go
+++ b/usersync/syncer_test.go
@@ -26,7 +26,6 @@ func TestNewSyncer(t *testing.T) {
 	testCases := []struct {
 		description         string
 		givenKey            string
-		givenDefault        string
 		givenIFrameConfig   *config.SyncerEndpoint
 		givenRedirectConfig *config.SyncerEndpoint
 		givenExternalURL    string
@@ -38,7 +37,6 @@ func TestNewSyncer(t *testing.T) {
 		{
 			description:         "Missing Key",
 			givenKey:            "",
-			givenDefault:        "iframe",
 			givenIFrameConfig:   iframeConfig,
 			givenRedirectConfig: nil,
 			expectedError:       "key is required",
@@ -46,23 +44,13 @@ func TestNewSyncer(t *testing.T) {
 		{
 			description:         "Missing Endpoints",
 			givenKey:            "a",
-			givenDefault:        "",
 			givenIFrameConfig:   nil,
 			givenRedirectConfig: nil,
 			expectedError:       "at least one endpoint (iframe and/or redirect) is required",
 		},
-		{
-			description:         "Resolve Default Sync Type Error ",
-			givenKey:            "a",
-			givenDefault:        "",
-			givenIFrameConfig:   iframeConfig,
-			givenRedirectConfig: redirectConfig,
-			expectedError:       "default sync type is required when more then one sync endpoint is configured",
-		},
 		{
 			description:         "IFrame & Redirect Endpoints",
 			givenKey:            "a",
-			givenDefault:        "iframe",
 			givenIFrameConfig:   iframeConfig,
 			givenRedirectConfig: redirectConfig,
 			expectedDefault:     SyncTypeIFrame,
@@ -72,7 +60,6 @@ func TestNewSyncer(t *testing.T) {
 		{
 			description:         "IFrame - Parse Error",
 			givenKey:            "a",
-			givenDefault:        "iframe",
 			givenIFrameConfig:   errParseConfig,
 			givenRedirectConfig: nil,
 			expectedError:       "iframe template: a_usersync_url:1: function \"malformed\" not defined",
@@ -80,7 +67,6 @@ func TestNewSyncer(t *testing.T) {
 		{
 			description:         "IFrame - Validation Error",
 			givenKey:            "a",
-			givenDefault:        "iframe",
 			givenIFrameConfig:   errInvalidConfig,
 			givenRedirectConfig: nil,
 			expectedError:       "iframe composed url: \"notAURL:http%3A%2F%2Fhost.com%2Fhost\" is invalid",
@@ -88,7 +74,6 @@ func TestNewSyncer(t *testing.T) {
 		{
 			description:         "Redirect - Parse Error",
 			givenKey:            "a",
-			givenDefault:        "redirect",
 			givenIFrameConfig:   nil,
 			givenRedirectConfig: errParseConfig,
 			expectedError:       "redirect template: a_usersync_url:1: function \"malformed\" not defined",
@@ -96,7 +81,6 @@ func TestNewSyncer(t *testing.T) {
 		{
 			description:         "Redirect - Validation Error",
 			givenKey:            "a",
-			givenDefault:        "redirect",
 			givenIFrameConfig:   nil,
 			givenRedirectConfig: errInvalidConfig,
 			expectedError:       "redirect composed url: \"notAURL:http%3A%2F%2Fhost.com%2Fhost\" is invalid",
@@ -104,7 +88,6 @@ func TestNewSyncer(t *testing.T) {
 		{
 			description:         "Syncer Level External URL",
 			givenKey:            "a",
-			givenDefault:        "iframe",
 			givenExternalURL:    "http://syncer.com",
 			givenIFrameConfig:   iframeConfig,
 			givenRedirectConfig: redirectConfig,
@@ -118,7 +101,6 @@ func TestNewSyncer(t *testing.T) {
 		syncerConfig := config.Syncer{
 			Key:         test.givenKey,
 			SupportCORS: &supportCORS,
-			Default:     test.givenDefault,
 			IFrame:      test.givenIFrameConfig,
 			Redirect:    test.givenRedirectConfig,
 			ExternalURL: test.givenExternalURL,
@@ -166,73 +148,27 @@ func TestResolveDefaultSyncType(t *testing.T) {
 		description      string
 		givenConfig      config.Syncer
 		expectedSyncType SyncType
-		expectedError    string
 	}{
 		{
-			description:      "IFrame & Redirect - IFrame Default",
-			givenConfig:      config.Syncer{Default: "iframe", IFrame: anyEndpoint, Redirect: anyEndpoint},
-			expectedSyncType: SyncTypeIFrame,
-		},
-		{
-			description:      "IFrame & Redirect - Redirect Default",
-			givenConfig:      config.Syncer{Default: "redirect", IFrame: anyEndpoint, Redirect: anyEndpoint},
-			expectedSyncType: SyncTypeRedirect,
-		},
-		{
-			description:      "IFrame & Redirect - No Default",
-			givenConfig:      config.Syncer{Default: "", IFrame: anyEndpoint, Redirect: anyEndpoint},
-			expectedSyncType: SyncTypeUnknown,
-			expectedError:    "default sync type is required when more then one sync endpoint is configured",
-		},
-		{
-			description:      "IFrame & Redirect - Invalid Default",
-			givenConfig:      config.Syncer{Default: "invalid", IFrame: anyEndpoint, Redirect: anyEndpoint},
-			expectedSyncType: SyncTypeUnknown,
-			expectedError:    "invalid default sync type 'invalid'",
-		},
-		{
-			description:      "IFrame Only - IFrame Default",
-			givenConfig:      config.Syncer{Default: "iframe", IFrame: anyEndpoint, Redirect: nil},
+			description:      "IFrame & Redirect",
+			givenConfig:      config.Syncer{IFrame: anyEndpoint, Redirect: anyEndpoint},
 			expectedSyncType: SyncTypeIFrame,
 		},
 		{
-			description:      "IFrame Only - No Default",
-			givenConfig:      config.Syncer{Default: "", IFrame: anyEndpoint, Redirect: nil},
+			description:      "IFrame Only",
+			givenConfig:      config.Syncer{IFrame: anyEndpoint, Redirect: nil},
 			expectedSyncType: SyncTypeIFrame,
 		},
-		{
-			description:      "IFrame Only - Redirect Default",
-			givenConfig:      config.Syncer{Default: "redirect", IFrame: anyEndpoint, Redirect: nil},
-			expectedSyncType: SyncTypeUnknown,
-			expectedError:    "default is set to redirect but no redirect endpoint is configured",
-		},
 		{
 			description:      "Redirect Only - Redirect Default",
-			givenConfig:      config.Syncer{Default: "redirect", IFrame: nil, Redirect: anyEndpoint},
+			givenConfig:      config.Syncer{IFrame: nil, Redirect: anyEndpoint},
 			expectedSyncType: SyncTypeRedirect,
 		},
-		{
-			description:      "IFrame Only - No Default",
-			givenConfig:      config.Syncer{Default: "", IFrame: nil, Redirect: anyEndpoint},
-			expectedSyncType: SyncTypeRedirect,
-		},
-		{
-			description:      "IFrame Only - IFrame Default",
-			givenConfig:      config.Syncer{Default: "iframe", IFrame: nil, Redirect: anyEndpoint},
-			expectedSyncType: SyncTypeUnknown,
-			expectedError:    "default is set to iframe but no iframe endpoint is configured",
-		},
 	}
 
 	for _, test := range testCases {
-		result, err := resolveDefaultSyncType(test.givenConfig)
-
+		result := resolveDefaultSyncType(test.givenConfig)
 		assert.Equal(t, test.expectedSyncType, result, test.description+":result")
-		if test.expectedError == "" {
-			assert.NoError(t, err, test.description+":err")
-		} else {
-			assert.EqualError(t, err, test.expectedError, test.description+":err")
-		}
 	}
 }
 
diff --git a/usersync/syncersbuilder_test.go b/usersync/syncersbuilder_test.go
index e36b1c2e..79727be6 100644
--- a/usersync/syncersbuilder_test.go
+++ b/usersync/syncersbuilder_test.go
@@ -22,10 +22,11 @@ func TestBuildSyncers(t *testing.T) {
 	var (
 		hostConfig              = config.Configuration{ExternalURL: "http://host.com", UserSync: config.UserSync{RedirectURL: "{{.ExternalURL}}/{{.SyncerKey}}/host"}}
 		iframeConfig            = &config.SyncerEndpoint{URL: "https://bidder.com/iframe?redirect={{.RedirectURL}}"}
+		iframeConfigError       = &config.SyncerEndpoint{URL: "https://bidder.com/iframe?redirect={{xRedirectURL}}"} // Error caused by invalid macro
 		infoKeyAPopulated       = config.BidderInfo{Enabled: true, Syncer: &config.Syncer{Key: "a", IFrame: iframeConfig}}
 		infoKeyADisabled        = config.BidderInfo{Enabled: false, Syncer: &config.Syncer{Key: "a", IFrame: iframeConfig}}
 		infoKeyAEmpty           = config.BidderInfo{Enabled: true, Syncer: &config.Syncer{Key: "a"}}
-		infoKeyAError           = config.BidderInfo{Enabled: true, Syncer: &config.Syncer{Key: "a", Default: "redirect", IFrame: iframeConfig}} // Error caused by invalid default sync type
+		infoKeyAError           = config.BidderInfo{Enabled: true, Syncer: &config.Syncer{Key: "a", IFrame: iframeConfigError}}
 		infoKeyASupportsOnly    = config.BidderInfo{Enabled: true, Syncer: &config.Syncer{Supports: []string{"iframe"}}}
 		infoKeyBPopulated       = config.BidderInfo{Enabled: true, Syncer: &config.Syncer{Key: "b", IFrame: iframeConfig}}
 		infoKeyBEmpty           = config.BidderInfo{Enabled: true, Syncer: &config.Syncer{Key: "b"}}
@@ -63,7 +64,7 @@ func TestBuildSyncers(t *testing.T) {
 			givenConfig:      hostConfig,
 			givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyAError},
 			expectedErrors: []string{
-				"cannot create syncer for bidder bidder1 with key a: default is set to redirect but no redirect endpoint is configured",
+				"cannot create syncer for bidder bidder1 with key a: iframe template: a_usersync_url:1: function \"xRedirectURL\" not defined",
 			},
 		},
 		{
@@ -105,7 +106,7 @@ func TestBuildSyncers(t *testing.T) {
 			givenConfig:      hostConfig,
 			givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyAEmpty, "bidder2": infoKeyAError},
 			expectedErrors: []string{
-				"cannot create syncer for bidder bidder2 with key a: default is set to redirect but no redirect endpoint is configured",
+				"cannot create syncer for bidder bidder2 with key a: iframe template: a_usersync_url:1: function \"xRedirectURL\" not defined",
 			},
 		},
 		{
@@ -137,7 +138,7 @@ func TestBuildSyncers(t *testing.T) {
 			givenConfig:      hostConfig,
 			givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyAError, "bidder2": infoKeyBEmpty},
 			expectedErrors: []string{
-				"cannot create syncer for bidder bidder1 with key a: default is set to redirect but no redirect endpoint is configured",
+				"cannot create syncer for bidder bidder1 with key a: iframe template: a_usersync_url:1: function \"xRedirectURL\" not defined",
 				"cannot create syncer for bidder bidder2 with key b: at least one endpoint (iframe and/or redirect) is required",
 			},
 		},
@@ -199,7 +200,7 @@ func TestShouldCreateSyncer(t *testing.T) {
 		},
 		{
 			description: "Enabled, Syncer - Fully Loaded",
-			given:       config.BidderInfo{Enabled: true, Syncer: &config.Syncer{Key: "anyKey", Default: "iframe", Supports: anySupports, IFrame: anyEndpoint, Redirect: anyEndpoint, SupportCORS: &anyCORS}},
+			given:       config.BidderInfo{Enabled: true, Syncer: &config.Syncer{Key: "anyKey", Supports: anySupports, IFrame: anyEndpoint, Redirect: anyEndpoint, SupportCORS: &anyCORS}},
 			expected:    true,
 		},
 		{
@@ -207,11 +208,6 @@ func TestShouldCreateSyncer(t *testing.T) {
 			given:       config.BidderInfo{Enabled: true, Syncer: &config.Syncer{Key: "anyKey"}},
 			expected:    true,
 		},
-		{
-			description: "Enabled, Syncer - Only Default",
-			given:       config.BidderInfo{Enabled: true, Syncer: &config.Syncer{Default: "iframe"}},
-			expected:    true,
-		},
 		{
 			description: "Enabled, Syncer - Only Supports",
 			given:       config.BidderInfo{Enabled: true, Syncer: &config.Syncer{Supports: anySupports}},
@@ -244,7 +240,7 @@ func TestShouldCreateSyncer(t *testing.T) {
 		},
 		{
 			description: "Disabled, Syncer - Fully Loaded",
-			given:       config.BidderInfo{Enabled: false, Syncer: &config.Syncer{Key: "anyKey", Default: "iframe", Supports: anySupports, IFrame: anyEndpoint, Redirect: anyEndpoint, SupportCORS: &anyCORS}},
+			given:       config.BidderInfo{Enabled: false, Syncer: &config.Syncer{Key: "anyKey", Supports: anySupports, IFrame: anyEndpoint, Redirect: anyEndpoint, SupportCORS: &anyCORS}},
 			expected:    false,
 		},
 		{
@@ -252,11 +248,6 @@ func TestShouldCreateSyncer(t *testing.T) {
 			given:       config.BidderInfo{Enabled: false, Syncer: &config.Syncer{Key: "anyKey"}},
 			expected:    false,
 		},
-		{
-			description: "Disabled, Syncer - Only Default",
-			given:       config.BidderInfo{Enabled: false, Syncer: &config.Syncer{Default: "iframe"}},
-			expected:    false,
-		},
 		{
 			description: "Disabled, Syncer - Only Supports",
 			given:       config.BidderInfo{Enabled: false, Syncer: &config.Syncer{Supports: anySupports}},
diff --git a/usersync/synctype_test.go b/usersync/synctype_test.go
index 35a241f1..1f172f5f 100644
--- a/usersync/synctype_test.go
+++ b/usersync/synctype_test.go
@@ -50,49 +50,3 @@ func TestSyncTypeFilter(t *testing.T) {
 		assert.ElementsMatch(t, test.expectedSyncTypes, syncTypes, test.description)
 	}
 }
-
-func TestSyncTypeParse(t *testing.T) {
-	testCases := []struct {
-		description   string
-		given         string
-		expected      SyncType
-		expectedError string
-	}{
-		{
-			description: "IFrame",
-			given:       "iframe",
-			expected:    SyncTypeIFrame,
-		},
-		{
-			description: "IFrame - Case Insensitive",
-			given:       "iFrAmE",
-			expected:    SyncTypeIFrame,
-		},
-		{
-			description: "Redirect",
-			given:       "redirect",
-			expected:    SyncTypeRedirect,
-		},
-		{
-			description: "Redirect - Case Insensitive",
-			given:       "ReDiReCt",
-			expected:    SyncTypeRedirect,
-		},
-		{
-			description:   "Invalid",
-			given:         "invalid",
-			expectedError: "invalid sync type `invalid`",
-		},
-	}
-
-	for _, test := range testCases {
-		result, err := SyncTypeParse(test.given)
-
-		if test.expectedError == "" {
-			assert.NoError(t, err, test.description+":err")
-			assert.Equal(t, test.expected, result, test.description+":result")
-		} else {
-			assert.EqualError(t, err, test.expectedError, test.description+":err")
-		}
-	}
-}