Repository: prebid/prebid-server
Pull request #3530 (2024-02-21 17:14:51)

Adnuntius: site.ext targeting
This PR is meant to allow Adnuntius to do targeting on site Ext and also pick the first external ID from EIDs until we allow for multiple IDs in our adserver.

github-actions[bot]: ## Code coverage summary 
Note: 
- Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors 
- Coverage summary encompasses all commits leading up to the latest one, d9208517cce0bce023aecc5707cda2cc76c8a44f 
#### adnuntius 
Refer [here](https://htmlpreview.github.io/?https://github.com/prebid/prebid-server/coverage-preview/.github/preview/7992967514_1708535735/adnuntius.html) for heat map coverage report 
``` 
github.com/prebid/prebid-server/v2/adapters/adnuntius/adnuntius.go:92:	Builder			100.0%
github.com/prebid/prebid-server/v2/adapters/adnuntius/adnuntius.go:102:	MakeRequests		100.0%
github.com/prebid/prebid-server/v2/adapters/adnuntius/adnuntius.go:106:	setHeaders		100.0%
github.com/prebid/prebid-server/v2/adapters/adnuntius/adnuntius.go:122:	makeEndpointUrl		89.3%
github.com/prebid/prebid-server/v2/adapters/adnuntius/adnuntius.go:171:	getImpSizes		90.0%
github.com/prebid/prebid-server/v2/adapters/adnuntius/adnuntius.go:194:	generateRequests	90.0%
github.com/prebid/prebid-server/v2/adapters/adnuntius/adnuntius.go:309:	MakeBids		81.8%
github.com/prebid/prebid-server/v2/adapters/adnuntius/adnuntius.go:336:	getSiteExtAsKv		80.0%
github.com/prebid/prebid-server/v2/adapters/adnuntius/adnuntius.go:346:	getGDPR			85.7%
github.com/prebid/prebid-server/v2/adapters/adnuntius/adnuntius.go:371:	generateAdResponse	84.0%
github.com/prebid/prebid-server/v2/adapters/adnuntius/adnuntius.go:436:	generateBidResponse	88.0%
total:									(statements)		88.3%

 ``` 


Patch:
diff --git a/Makefile b/Makefile
index 2d8aae6c..cf4ac52b 100644
--- a/Makefile
+++ b/Makefile
@@ -33,3 +33,7 @@ image:
 # format runs format
 format:
 	./scripts/format.sh -f true
+
+# formatcheck runs format for diagnostics, without modifying the code
+formatcheck:
+	./scripts/format.sh -f false
diff --git a/adapters/adnuntius/adnuntius.go b/adapters/adnuntius/adnuntius.go
index 4b823455..c1d71cc1 100644
--- a/adapters/adnuntius/adnuntius.go
+++ b/adapters/adnuntius/adnuntius.go
@@ -33,6 +33,9 @@ type adnAdunit struct {
 type extDeviceAdnuntius struct {
 	NoCookies bool `json:"noCookies,omitempty"`
 }
+type siteExt struct {
+	Data interface{} `json:"data"`
+}
 
 type Ad struct {
 	Bid struct {
@@ -71,9 +74,10 @@ type adnMetaData struct {
 	Usi string `json:"usi,omitempty"`
 }
 type adnRequest struct {
-	AdUnits  []adnAdunit `json:"adUnits"`
-	MetaData adnMetaData `json:"metaData,omitempty"`
-	Context  string      `json:"context,omitempty"`
+	AdUnits   []adnAdunit `json:"adUnits"`
+	MetaData  adnMetaData `json:"metaData,omitempty"`
+	Context   string      `json:"context,omitempty"`
+	KeyValues interface{} `json:"kv,omitempty"`
 }
 
 type RequestExt struct {
@@ -138,7 +142,6 @@ func makeEndpointUrl(ortbRequest openrtb2.BidRequest, a *adapter, noCookies bool
 		if deviceExt.NoCookies {
 			noCookies = true
 		}
-
 	}
 
 	_, offset := a.time.Now().Zone()
@@ -249,11 +252,31 @@ func (a *adapter) generateRequests(ortbRequest openrtb2.BidRequest) ([]*adapters
 		site = ortbRequest.Site.Page
 	}
 
+	extSite, erro := getSiteExtAsKv(&ortbRequest)
+	if erro != nil {
+		return nil, []error{fmt.Errorf("failed to parse site Ext: %v", err)}
+	}
+
 	for _, networkAdunits := range networkAdunitMap {
 
 		adnuntiusRequest := adnRequest{
-			AdUnits: networkAdunits,
-			Context: site,
+			AdUnits:   networkAdunits,
+			Context:   site,
+			KeyValues: extSite.Data,
+		}
+
+		var extUser openrtb_ext.ExtUser
+		if ortbRequest.User != nil && ortbRequest.User.Ext != nil {
+			if err := json.Unmarshal(ortbRequest.User.Ext, &extUser); err != nil {
+				return nil, []error{fmt.Errorf("failed to parse Ext User: %v", err)}
+			}
+		}
+
+		// Will change when our adserver can accept multiple user IDS
+		if extUser.Eids != nil && len(extUser.Eids) > 0 {
+			if len(extUser.Eids[0].UIDs) > 0 {
+				adnuntiusRequest.MetaData.Usi = extUser.Eids[0].UIDs[0].ID
+			}
 		}
 
 		ortbUser := ortbRequest.User
@@ -310,6 +333,16 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, externalRequest *adapte
 	return bidResponse, nil
 }
 
+func getSiteExtAsKv(request *openrtb2.BidRequest) (siteExt, error) {
+	var extSite siteExt
+	if request.Site != nil && request.Site.Ext != nil {
+		if err := json.Unmarshal(request.Site.Ext, &extSite); err != nil {
+			return extSite, fmt.Errorf("failed to parse ExtSite in Adnuntius: %v", err)
+		}
+	}
+	return extSite, nil
+}
+
 func getGDPR(request *openrtb2.BidRequest) (string, string, error) {
 
 	gdpr := ""
diff --git a/adapters/rubicon/rubicon.go b/adapters/rubicon/rubicon.go
index 01b1e797..6cffa1b2 100644
--- a/adapters/rubicon/rubicon.go
+++ b/adapters/rubicon/rubicon.go
@@ -938,7 +938,7 @@ func isVideo(imp openrtb2.Imp) bool {
 
 func isFullyPopulatedVideo(video *openrtb2.Video) bool {
 	// These are just recommended video fields for XAPI
-	return video.MIMEs != nil && video.Protocols != nil && video.MaxDuration != 0 && video.Linearity != 0 && video.API != nil
+	return video.MIMEs != nil && video.Protocols != nil && video.MaxDuration != 0 && video.Linearity != 0
 }
 
 func resolveNativeObject(native *openrtb2.Native, target map[string]interface{}) (*openrtb2.Native, error) {
diff --git a/adapters/seedingAlliance/seedingAlliance.go b/adapters/seedingAlliance/seedingAlliance.go
index 03b6853b..af48133d 100644
--- a/adapters/seedingAlliance/seedingAlliance.go
+++ b/adapters/seedingAlliance/seedingAlliance.go
@@ -33,11 +33,11 @@ func Builder(_ openrtb_ext.BidderName, config config.Adapter, server config.Serv
 }
 
 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, extraRequestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
-	var seatId string
+	var accountId string
 	var err error
 
 	for i := range request.Imp {
-		if seatId, err = getExtInfo(&request.Imp[i]); err != nil {
+		if accountId, err = getExtInfo(&request.Imp[i]); err != nil {
 			return nil, []error{err}
 		}
 	}
@@ -51,7 +51,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, extraRequestInfo *a
 		return nil, []error{err}
 	}
 
-	url, err := macros.ResolveMacros(a.endpoint, macros.EndpointTemplateParams{AccountID: seatId})
+	url, err := macros.ResolveMacros(a.endpoint, macros.EndpointTemplateParams{AccountID: accountId})
 	if err != nil {
 		return nil, []error{err}
 	}
@@ -146,7 +146,7 @@ func getExtInfo(imp *openrtb2.Imp) (string, error) {
 	var ext adapters.ExtImpBidder
 	var extSA openrtb_ext.ImpExtSeedingAlliance
 
-	seatID := "pbs"
+	accountId := "pbs"
 
 	if err := json.Unmarshal(imp.Ext, &ext); err != nil {
 		return "", fmt.Errorf("could not unmarshal adapters.ExtImpBidder: %w", err)
@@ -159,8 +159,12 @@ func getExtInfo(imp *openrtb2.Imp) (string, error) {
 	imp.TagID = extSA.AdUnitID
 
 	if extSA.SeatID != "" {
-		seatID = extSA.SeatID
+		accountId = extSA.SeatID
 	}
 
-	return seatID, nil
+	if extSA.AccountID != "" {
+		accountId = extSA.AccountID
+	}
+
+	return accountId, nil
 }
diff --git a/adapters/stroeerCore/stroeercore.go b/adapters/stroeerCore/stroeercore.go
index 733d549e..f2ef4923 100644
--- a/adapters/stroeerCore/stroeercore.go
+++ b/adapters/stroeerCore/stroeercore.go
@@ -23,17 +23,22 @@ type response struct {
 }
 
 type bidResponse struct {
-	ID     string  `json:"id"`
-	BidID  string  `json:"bidId"`
-	CPM    float64 `json:"cpm"`
-	Width  int64   `json:"width"`
-	Height int64   `json:"height"`
-	Ad     string  `json:"ad"`
-	CrID   string  `json:"crid"`
-	Mtype  string  `json:"mtype"`
+	ID     string          `json:"id"`
+	BidID  string          `json:"bidId"`
+	CPM    float64         `json:"cpm"`
+	Width  int64           `json:"width"`
+	Height int64           `json:"height"`
+	Ad     string          `json:"ad"`
+	CrID   string          `json:"crid"`
+	Mtype  string          `json:"mtype"`
+	DSA    json.RawMessage `json:"dsa"`
 }
 
-func (b bidResponse) resolveMediaType() (mt openrtb2.MarkupType, bt openrtb_ext.BidType, err error) {
+type bidExt struct {
+	DSA json.RawMessage `json:"dsa,omitempty"`
+}
+
+func (b *bidResponse) resolveMediaType() (mt openrtb2.MarkupType, bt openrtb_ext.BidType, err error) {
 	switch b.Mtype {
 	case "banner":
 		return openrtb2.MarkupBanner, openrtb_ext.BidTypeBanner, nil
@@ -82,6 +87,15 @@ func (a *adapter) MakeBids(bidRequest *openrtb2.BidRequest, requestData *adapter
 			MType: markupType,
 		}
 
+		if bid.DSA != nil {
+			dsaJson, err := json.Marshal(bidExt{bid.DSA})
+			if err != nil {
+				errors = append(errors, err)
+			} else {
+				openRtbBid.Ext = dsaJson
+			}
+		}
+
 		bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{
 			Bid:     &openRtbBid,
 			BidType: bidType,
diff --git a/analytics/pubstack/eventchannel/sender.go b/analytics/pubstack/eventchannel/sender.go
index 951de4d4..fe068b15 100644
--- a/analytics/pubstack/eventchannel/sender.go
+++ b/analytics/pubstack/eventchannel/sender.go
@@ -3,10 +3,11 @@ package eventchannel
 import (
 	"bytes"
 	"fmt"
-	"github.com/golang/glog"
 	"net/http"
 	"net/url"
 	"path"
+
+	"github.com/golang/glog"
 )
 
 type Sender = func(payload []byte) error
@@ -26,6 +27,7 @@ func NewHttpSender(client *http.Client, endpoint string) Sender {
 		if err != nil {
 			return err
 		}
+		resp.Body.Close()
 
 		if resp.StatusCode != http.StatusOK {
 			glog.Errorf("[pubstack] Wrong code received %d instead of %d", resp.StatusCode, http.StatusOK)
diff --git a/dsa/validate.go b/dsa/validate.go
index f6ece66e..034dae8b 100644
--- a/dsa/validate.go
+++ b/dsa/validate.go
@@ -1,51 +1,103 @@
 package dsa
 
 import (
+	"errors"
+
 	"github.com/prebid/prebid-server/v2/exchange/entities"
 	"github.com/prebid/prebid-server/v2/openrtb_ext"
+	"github.com/prebid/prebid-server/v2/util/jsonutil"
+)
 
-	"github.com/buger/jsonparser"
+// Required values representing whether a DSA object is required
+const (
+	Required               int8 = 2 // bid responses without DSA object will not be accepted
+	RequiredOnlinePlatform int8 = 3 // bid responses without DSA object will not be accepted, Publisher is Online Platform
 )
 
+// PubRender values representing publisher rendering intentions
 const (
-	// Required - bid responses without DSA object will not be accepted
-	Required = 2
-	// RequiredOnlinePlatform - bid responses without DSA object will not be accepted, Publisher is an Online Platform
-	RequiredOnlinePlatform = 3
+	PubRenderCannotRender int8 = 0 // publisher can't render
+	PubRenderWillRender   int8 = 2 // publisher will render
+)
+
+// AdRender values representing buyer/advertiser rendering intentions
+const (
+	AdRenderWillRender int8 = 1 // buyer/advertiser will render
+)
+
+var (
+	ErrDsaMissing        = errors.New("DSA object missing when required")
+	ErrBehalfTooLong     = errors.New("DSA behalf exceeds limit of 100 chars")
+	ErrPaidTooLong       = errors.New("DSA paid exceeds limit of 100 chars")
+	ErrNeitherWillRender = errors.New("DSA publisher and buyer both signal will not render")
+	ErrBothWillRender    = errors.New("DSA publisher and buyer both signal will render")
+)
+
+const (
+	behalfMaxLength = 100
+	paidMaxLength   = 100
 )
 
 // Validate determines whether a given bid is valid from a DSA perspective.
 // A bid is considered valid unless the bid request indicates that a DSA object is required
-// in bid responses and the object happens to be missing from the specified bid.
-func Validate(req *openrtb_ext.RequestWrapper, bid *entities.PbsOrtbBid) (valid bool) {
-	if !dsaRequired(req) {
-		return true
+// in bid responses and the object happens to be missing from the specified bid, or if the bid
+// DSA object contents are invalid
+func Validate(req *openrtb_ext.RequestWrapper, bid *entities.PbsOrtbBid) error {
+	reqDSA := getReqDSA(req)
+	bidDSA := getBidDSA(bid)
+
+	if dsaRequired(reqDSA) && bidDSA == nil {
+		return ErrDsaMissing
 	}
-	if bid == nil || bid.Bid == nil {
-		return false
+	if bidDSA == nil {
+		return nil
+	}
+	if len(bidDSA.Behalf) > behalfMaxLength {
+		return ErrBehalfTooLong
 	}
-	_, dataType, _, err := jsonparser.Get(bid.Bid.Ext, "dsa")
-	if dataType == jsonparser.Object && err == nil {
-		return true
-	} else if err != nil && err != jsonparser.KeyPathNotFoundError {
-		return true
+	if len(bidDSA.Paid) > paidMaxLength {
+		return ErrPaidTooLong
 	}
-	return false
+	if reqDSA != nil && reqDSA.PubRender != nil && bidDSA.AdRender != nil {
+		if *reqDSA.PubRender == PubRenderCannotRender && *bidDSA.AdRender != AdRenderWillRender {
+			return ErrNeitherWillRender
+		}
+		if *reqDSA.PubRender == PubRenderWillRender && *bidDSA.AdRender == AdRenderWillRender {
+			return ErrBothWillRender
+		}
+	}
+	return nil
 }
 
 // dsaRequired examines the bid request to determine if the dsarequired field indicates
 // that bid responses include a dsa object
-func dsaRequired(req *openrtb_ext.RequestWrapper) bool {
+func dsaRequired(dsa *openrtb_ext.ExtRegsDSA) bool {
+	if dsa == nil || dsa.Required == nil {
+		return false
+	}
+	return *dsa.Required == Required || *dsa.Required == RequiredOnlinePlatform
+}
+
+// getReqDSA retrieves the DSA object from the request
+func getReqDSA(req *openrtb_ext.RequestWrapper) *openrtb_ext.ExtRegsDSA {
+	if req == nil {
+		return nil
+	}
 	regExt, err := req.GetRegExt()
 	if regExt == nil || err != nil {
-		return false
+		return nil
 	}
-	regsDSA := regExt.GetDSA()
-	if regsDSA == nil {
-		return false
+	return regExt.GetDSA()
+}
+
+// getBidDSA retrieves the DSA object from the bid
+func getBidDSA(bid *entities.PbsOrtbBid) *openrtb_ext.ExtBidDSA {
+	if bid == nil || bid.Bid == nil {
+		return nil
 	}
-	if regsDSA.Required == Required || regsDSA.Required == RequiredOnlinePlatform {
-		return true
+	var bidExt openrtb_ext.ExtBid
+	if err := jsonutil.Unmarshal(bid.Bid.Ext, &bidExt); err != nil {
+		return nil
 	}
-	return false
+	return bidExt.DSA
 }
diff --git a/errortypes/code.go b/errortypes/code.go
index 1de5e648..399dd663 100644
--- a/errortypes/code.go
+++ b/errortypes/code.go
@@ -31,6 +31,7 @@ const (
 	AdServerTargetingWarningCode
 	BidAdjustmentWarningCode
 	FloorBidRejectionWarningCode
+	InvalidBidResponseDSAWarningCode
 )
 
 // Coder provides an error or warning code with severity.
diff --git a/exchange/exchange.go b/exchange/exchange.go
index ffd3b2e8..41134104 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -1245,14 +1245,14 @@ func (e *exchange) makeBid(bids []*entities.PbsOrtbBid, auc *auction, returnCrea
 	errs := make([]error, 0, 1)
 
 	for _, bid := range bids {
-		if !dsa.Validate(bidRequest, bid) {
-			RequiredError := openrtb_ext.ExtBidderMessage{
-				Code:    errortypes.BadServerResponseErrorCode,
-				Message: "bidResponse rejected: DSA object missing when required",
+		if err := dsa.Validate(bidRequest, bid); err != nil {
+			dsaMessage := openrtb_ext.ExtBidderMessage{
+				Code:    errortypes.InvalidBidResponseDSAWarningCode,
+				Message: fmt.Sprintf("bid rejected: %s", err.Error()),
 			}
-			bidResponseExt.Warnings[adapter] = append(bidResponseExt.Warnings[adapter], RequiredError)
+			bidResponseExt.Warnings[adapter] = append(bidResponseExt.Warnings[adapter], dsaMessage)
 
-			seatNonBids.addBid(bid, int(ResponseRejectedPrivacy), adapter.String())
+			seatNonBids.addBid(bid, int(ResponseRejectedGeneral), adapter.String())
 			continue // Don't add bid to result
 		}
 		if e.bidValidationEnforcement.BannerCreativeMaxSize == config.ValidationEnforce && bid.BidType == openrtb_ext.BidTypeBanner {
diff --git a/exchange/non_bid_reason.go b/exchange/non_bid_reason.go
index f105d0ad..2dff2dfb 100644
--- a/exchange/non_bid_reason.go
+++ b/exchange/non_bid_reason.go
@@ -6,9 +6,9 @@ package exchange
 type NonBidReason int
 
 const (
-	NoBidUnknownError                      NonBidReason = 0   // No Bid - General
+	NoBidUnknownError                      NonBidReason = 0 // No Bid - General
+	ResponseRejectedGeneral                NonBidReason = 300
 	ResponseRejectedCategoryMappingInvalid NonBidReason = 303 // Response Rejected - Category Mapping Invalid
-	ResponseRejectedPrivacy                NonBidReason = 305
 	ResponseRejectedCreativeSizeNotAllowed NonBidReason = 351 // Response Rejected - Invalid Creative (Size Not Allowed)
 	ResponseRejectedCreativeNotSecure      NonBidReason = 352 // Response Rejected - Invalid Creative (Not Secure)
 )
diff --git a/main.go b/main.go
index e72f02f1..1909199d 100644
--- a/main.go
+++ b/main.go
@@ -8,11 +8,13 @@ import (
 	"runtime"
 	"time"
 
+	jsoniter "github.com/json-iterator/go"
 	"github.com/prebid/prebid-server/v2/config"
 	"github.com/prebid/prebid-server/v2/currency"
 	"github.com/prebid/prebid-server/v2/openrtb_ext"
 	"github.com/prebid/prebid-server/v2/router"
 	"github.com/prebid/prebid-server/v2/server"
+	"github.com/prebid/prebid-server/v2/util/jsonutil"
 	"github.com/prebid/prebid-server/v2/util/task"
 
 	"github.com/golang/glog"
@@ -21,6 +23,7 @@ import (
 
 func init() {
 	rand.Seed(time.Now().UnixNano())
+	jsoniter.RegisterExtension(&jsonutil.RawMessageExtension{})
 }
 
 func main() {
diff --git a/modules/generator/builder.tmpl b/modules/generator/builder.tmpl
index b7b78103..db0cd1a4 100644
--- a/modules/generator/builder.tmpl
+++ b/modules/generator/builder.tmpl
@@ -1,20 +1,21 @@
 package modules
-
-{{if .}}
 import (
-    {{- range .}}
-    {{.Vendor}}{{.Module | Title}} "github.com/prebid/prebid-server/v2/modules/{{.Vendor}}/{{.Module}}"
+{{- range $vendor, $modules := .}}
+    {{- range $module := $modules}}
+        {{$vendor}}{{$module | Title}} "github.com/prebid/prebid-server/v2/modules/{{$vendor}}/{{$module}}"
     {{- end}}
+{{- end}}
 )
-{{end}}
 
 // builders returns mapping between module name and its builder
 // vendor and module names are chosen based on the module directory name
 func builders() ModuleBuilders {
     return ModuleBuilders{
-        {{- range .}}
-        "{{.Vendor}}": {
-            "{{.Module}}": {{.Vendor}}{{.Module | Title}}.Builder,
+        {{- range $vendor, $modules := .}}
+        "{{$vendor}}": {
+            {{- range $module := $modules}}
+            "{{$module}}": {{$vendor}}{{$module | Title}}.Builder,
+            {{- end}}
         },
         {{- end}}
     }
diff --git a/modules/generator/buildergen.go b/modules/generator/buildergen.go
index b906682b..21993242 100644
--- a/modules/generator/buildergen.go
+++ b/modules/generator/buildergen.go
@@ -10,6 +10,7 @@ import (
 	"os"
 	"path/filepath"
 	"regexp"
+	"sort"
 	"strings"
 	"text/template"
 )
@@ -20,26 +21,26 @@ var (
 	outName  = "builder.go"
 )
 
-type Module struct {
-	Vendor string
-	Module string
-}
-
 func main() {
-	var modules []Module
+	modules := make(map[string][]string)
 
 	filepath.WalkDir("./", func(path string, d fs.DirEntry, err error) error {
 		if !r.MatchString(path) {
 			return nil
 		}
 		match := r.FindStringSubmatch(path)
-		modules = append(modules, Module{
-			Vendor: match[1],
-			Module: match[2],
-		})
+		vendorModules := modules[match[1]]
+		vendorModules = append(vendorModules, match[2])
+		modules[match[1]] = vendorModules
+
 		return nil
 	})
 
+	for vendorName, names := range modules {
+		sort.Strings(names)
+		modules[vendorName] = names
+	}
+
 	funcMap := template.FuncMap{"Title": strings.Title}
 	t, err := template.New(tmplName).Funcs(funcMap).ParseFiles(fmt.Sprintf("generator/%s", tmplName))
 	if err != nil {
diff --git a/openrtb_ext/bid.go b/openrtb_ext/bid.go
index 2e190389..7d3dcbd7 100644
--- a/openrtb_ext/bid.go
+++ b/openrtb_ext/bid.go
@@ -7,6 +7,7 @@ import (
 
 // ExtBid defines the contract for bidresponse.seatbid.bid[i].ext
 type ExtBid struct {
+	DSA    *ExtBidDSA    `json:"dsa,omitempty"`
 	Prebid *ExtBidPrebid `json:"prebid,omitempty"`
 }
 
@@ -83,6 +84,13 @@ type ExtBidPrebidEvents struct {
 	Imp string `json:"imp,omitempty"`
 }
 
+// ExtBidDSA defines the contract for bidresponse.seatbid.bid[i].ext.dsa
+type ExtBidDSA struct {
+	AdRender *int8  `json:"adrender,omitempty"`
+	Behalf   string `json:"behalf,omitempty"`
+	Paid     string `json:"paid,omitempty"`
+}
+
 // BidType describes the allowed values for bidresponse.seatbid.bid[i].ext.prebid.type
 type BidType string
 
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 173120f7..fcd2b15c 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -612,6 +612,7 @@ func NewBidderParamsValidator(schemaDirectory string) (BidderParamValidator, err
 		if _, ok := bidderMap[bidderName]; !ok {
 			return nil, fmt.Errorf("File %s/%s does not match a valid BidderName.", schemaDirectory, fileInfo.Name())
 		}
+
 		toOpen, err := paramsValidator.abs(filepath.Join(schemaDirectory, fileInfo.Name()))
 		if err != nil {
 			return nil, fmt.Errorf("Failed to get an absolute representation of the path: %s, %v", toOpen, err)
diff --git a/openrtb_ext/imp_seedingAlliance.go b/openrtb_ext/imp_seedingAlliance.go
index 0f594d3c..d383ad39 100644
--- a/openrtb_ext/imp_seedingAlliance.go
+++ b/openrtb_ext/imp_seedingAlliance.go
@@ -1,6 +1,7 @@
 package openrtb_ext
 
 type ImpExtSeedingAlliance struct {
-	AdUnitID string `json:"adUnitId"`
-	SeatID   string `json:"seatId"`
+	AdUnitID  string `json:"adUnitId"`
+	SeatID    string `json:"seatId"`
+	AccountID string `json:"accountId"`
 }
diff --git a/openrtb_ext/regs.go b/openrtb_ext/regs.go
index 8057ce2c..eca5ff98 100644
--- a/openrtb_ext/regs.go
+++ b/openrtb_ext/regs.go
@@ -16,5 +16,7 @@ type ExtRegs struct {
 // ExtRegsDSA defines the contract for bidrequest.regs.ext.dsa
 type ExtRegsDSA struct {
 	// Required should be a between 0 and 3 inclusive, see https://github.com/InteractiveAdvertisingBureau/openrtb/blob/main/extensions/community_extensions/dsa_transparency.md
-	Required int8 `json:"dsarequired,omitempty"`
+	Required *int8 `json:"dsarequired,omitempty"`
+	// PubRender should be between 0 and 2 inclusive, see https://github.com/InteractiveAdvertisingBureau/openrtb/blob/main/extensions/community_extensions/dsa_transparency.md
+	PubRender *int8 `json:"pubrender,omitempty"`
 }
diff --git a/router/router.go b/router/router.go
index d89d1f59..c285bbda 100644
--- a/router/router.go
+++ b/router/router.go
@@ -93,7 +93,7 @@ func newJsonDirectoryServer(schemaDirectory string, validator openrtb_ext.Bidder
 		data[aliasName] = bidderData
 	}
 
-	response, err := json.Marshal(data)
+	response, err := jsonutil.Marshal(data)
 	if err != nil {
 		glog.Fatalf("Failed to marshal bidder param JSON-schema: %v", err)
 	}
diff --git a/static/bidder-info/adf.yaml b/static/bidder-info/adf.yaml
index 2310f346..d7d9eccf 100644
--- a/static/bidder-info/adf.yaml
+++ b/static/bidder-info/adf.yaml
@@ -1,4 +1,12 @@
+# Please uncomment the appropriate endpoint URL for your datacenter
+# Europe
 endpoint: "https://adx.adform.net/adx/openrtb"
+# North/South America
+# endpoint: "https://adx2.adform.net/adx/openrtb"
+# APAC
+# endpoint: "https://adx3.adform.net/adx/openrtb"
+geoscope:
+  - global
 maintainer:
   email: "scope.sspp@adform.com"
 gvlVendorID: 50
diff --git a/static/bidder-info/bmtm.yaml b/static/bidder-info/bmtm.yaml
index 3d3f2ca6..27452195 100644
--- a/static/bidder-info/bmtm.yaml
+++ b/static/bidder-info/bmtm.yaml
@@ -1,6 +1,6 @@
 endpoint: "https://one.elitebidder.com/api/pbs"
 maintainer:
-  email: dev@brightmountainmedia.com
+  email: product@brightmountainmedia.com
 modifyingVastXmlAllowed: false
 capabilities:
   app:
diff --git a/static/bidder-info/criteo.yaml b/static/bidder-info/criteo.yaml
index 7d58c68d..d6419d46 100644
--- a/static/bidder-info/criteo.yaml
+++ b/static/bidder-info/criteo.yaml
@@ -15,8 +15,8 @@ userSync:
   # criteo 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.
   redirect:
-    url: "https://ssp-sync.criteo.com/user-sync/redirect?gdprapplies={{.GDPR}}&gdpr={{.GDPRConsent}}&ccpa={{.USPrivacy}}&redir={{.RedirectURL}}&profile=230"
+    url: "https://ssp-sync.criteo.com/user-sync/redirect?gdprapplies={{.GDPR}}&gdpr={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}&profile=230"
     userMacro: "${CRITEO_USER_ID}"
   iframe:
-    url: "https://ssp-sync.criteo.com/user-sync/iframe?gdprapplies={{.GDPR}}&gdpr={{.GDPRConsent}}&ccpa={{.USPrivacy}}&redir={{.RedirectURL}}&profile=230"
+    url: "https://ssp-sync.criteo.com/user-sync/iframe?gdprapplies={{.GDPR}}&gdpr={{.GDPRConsent}}&ccpa={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}&profile=230"
     userMacro: "${CRITEO_USER_ID}"
\ No newline at end of file
diff --git a/static/bidder-info/grid.yaml b/static/bidder-info/grid.yaml
index bf1832c9..9d9e7aa5 100644
--- a/static/bidder-info/grid.yaml
+++ b/static/bidder-info/grid.yaml
@@ -15,5 +15,5 @@ capabilities:
       - native
 userSync:
   redirect:
-    url: "https://x.bidswitch.net/check_uuid/{{.RedirectURL}}?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}"
+    url: "https://x.bidswitch.net/check_uuid/{{.RedirectURL}}?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&us_privacy={{.USPrivacy}}"
     userMacro: "${BSW_UUID}"
diff --git a/static/bidder-info/medianet.yaml b/static/bidder-info/medianet.yaml
index ad741e8f..1b23d5ae 100644
--- a/static/bidder-info/medianet.yaml
+++ b/static/bidder-info/medianet.yaml
@@ -4,6 +4,8 @@ maintainer:
   email: "prebid-support@media.net"
 gvlVendorID: 142
 endpointCompression: gzip
+openrtb:
+  version: 2.6
 modifyingVastXmlAllowed: true
 capabilities:
   app:
diff --git a/static/bidder-info/minutemedia.yaml b/static/bidder-info/minutemedia.yaml
index efe58e57..55f5a2b7 100644
--- a/static/bidder-info/minutemedia.yaml
+++ b/static/bidder-info/minutemedia.yaml
@@ -14,5 +14,5 @@ capabilities:
       - video
 userSync:
   iframe:
-    url: https://pbs-cs.minutemedia-prebid.com/pbs-iframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}
+    url: https://pbs-cs.minutemedia-prebid.com/pbs-iframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}
     userMacro: "[PBS_UID]"
diff --git a/static/bidder-info/rise.yaml b/static/bidder-info/rise.yaml
index 72e56c33..79b64d5a 100644
--- a/static/bidder-info/rise.yaml
+++ b/static/bidder-info/rise.yaml
@@ -14,5 +14,5 @@ capabilities:
       - video
 userSync:
   iframe:
-    url: https://pbs-cs.yellowblue.io/pbs-iframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}
+    url: https://pbs-cs.yellowblue.io/pbs-iframe?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}
     userMacro: "[PBS_UID]"
diff --git a/static/bidder-info/taboola.yaml b/static/bidder-info/taboola.yaml
index 436f7469..0fccee14 100644
--- a/static/bidder-info/taboola.yaml
+++ b/static/bidder-info/taboola.yaml
@@ -13,8 +13,8 @@ capabilities:
       - native
 userSync:
   redirect:
-    url: https://trc.taboola.com/sg/ps/1/cm?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}
+    url: "https://trc.taboola.com/sg/ps/1/cm?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}"
     userMacro: "<TUID>"
   iframe:
-    url: https://cdn.taboola.com/scripts/ps-sync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}
+    url: "https://cdn.taboola.com/scripts/ps-sync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}"
     userMacro: "<TUID>"
diff --git a/static/bidder-params/seedingAlliance.json b/static/bidder-params/seedingAlliance.json
index 5fe463b6..d7208623 100644
--- a/static/bidder-params/seedingAlliance.json
+++ b/static/bidder-params/seedingAlliance.json
@@ -11,7 +11,11 @@
         },
         "seatId": {
             "type": "string",
-            "description": "Seat ID"
+            "description": "Deprecated, please use accountId"
+        },
+        "accountId": {
+            "type": "string",
+            "description": "Account ID of partner"
         }
     },
     "required": [
diff --git a/static/index.html b/static/index.html
index a3518ce2..ac79079f 100644
--- a/static/index.html
+++ b/static/index.html
@@ -3,7 +3,7 @@
         <title>Prebid Server</title>
     </head>
     <body>
-        Prebid Server is a server-to-server proxy for <a href="http://prebid.org">Prebid.js</a> users.
+        Prebid Server is a server-to-server proxy for <a href="https://prebid.org">Prebid.js</a> users.
         The host is not responsible for the content or advertising delivered through this proxy. For more information, 
         please contact prebid-server - at - prebid.org.
     </body>
diff --git a/stored_requests/backends/db_fetcher/fetcher.go b/stored_requests/backends/db_fetcher/fetcher.go
index 3a9b83f7..d6fade0e 100644
--- a/stored_requests/backends/db_fetcher/fetcher.go
+++ b/stored_requests/backends/db_fetcher/fetcher.go
@@ -152,7 +152,7 @@ func (fetcher *dbFetcher) FetchResponses(ctx context.Context, ids []string) (dat
 }
 
 func (fetcher *dbFetcher) FetchAccount(ctx context.Context, accountDefaultsJSON json.RawMessage, accountID string) (json.RawMessage, []error) {
-	return nil, []error{stored_requests.NotFoundError{accountID, "Account"}}
+	return nil, []error{stored_requests.NotFoundError{ID: accountID, DataType: "Account"}}
 }
 
 func (fetcher *dbFetcher) FetchCategories(ctx context.Context, primaryAdServer, publisherId, iabCategory string) (string, error) {
diff --git a/stored_requests/backends/empty_fetcher/fetcher.go b/stored_requests/backends/empty_fetcher/fetcher.go
index c851a997..65e5de90 100644
--- a/stored_requests/backends/empty_fetcher/fetcher.go
+++ b/stored_requests/backends/empty_fetcher/fetcher.go
@@ -33,7 +33,7 @@ func (fetcher EmptyFetcher) FetchResponses(ctx context.Context, ids []string) (d
 }
 
 func (fetcher EmptyFetcher) FetchAccount(ctx context.Context, accountDefaultJSON json.RawMessage, accountID string) (json.RawMessage, []error) {
-	return nil, []error{stored_requests.NotFoundError{accountID, "Account"}}
+	return nil, []error{stored_requests.NotFoundError{ID: accountID, DataType: "Account"}}
 }
 
 func (fetcher EmptyFetcher) FetchCategories(ctx context.Context, primaryAdServer, publisherId, iabCategory string) (string, error) {
diff --git a/util/jsonutil/jsonutil.go b/util/jsonutil/jsonutil.go
index b5bb47cc..695ccd8a 100644
--- a/util/jsonutil/jsonutil.go
+++ b/util/jsonutil/jsonutil.go
@@ -5,8 +5,10 @@ import (
 	"encoding/json"
 	"io"
 	"strings"
+	"unsafe"
 
 	jsoniter "github.com/json-iterator/go"
+	"github.com/modern-go/reflect2"
 	"github.com/prebid/prebid-server/v2/errortypes"
 )
 
@@ -211,3 +213,38 @@ func tryExtractErrorMessage(err error) string {
 func isLikelyDetailedErrorMessage(msg string) bool {
 	return !strings.HasPrefix(msg, "request.")
 }
+
+// RawMessageExtension will call json.Compact() on every json.RawMessage field when getting marshalled.
+type RawMessageExtension struct {
+	jsoniter.DummyExtension
+}
+
+// CreateEncoder substitutes the default jsoniter encoder of the json.RawMessage type with ours, that
+// calls json.Compact() before writting to the stream
+func (e *RawMessageExtension) CreateEncoder(typ reflect2.Type) jsoniter.ValEncoder {
+	if typ == jsonRawMessageType {
+		return &rawMessageCodec{}
+	}
+	return nil
+}
+
+var jsonRawMessageType = reflect2.TypeOfPtr(&json.RawMessage{}).Elem()
+
+// rawMessageCodec implements jsoniter.ValEncoder interface so we can override the default json.RawMessage Encode()
+// function with our implementation
+type rawMessageCodec struct{}
+
+func (codec *rawMessageCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
+	if ptr != nil {
+		jsonRawMsg := *(*[]byte)(ptr)
+
+		dst := bytes.NewBuffer(make([]byte, 0, len(jsonRawMsg)))
+		if err := json.Compact(dst, jsonRawMsg); err == nil {
+			stream.Write(dst.Bytes())
+		}
+	}
+}
+
+func (codec *rawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool {
+	return ptr == nil || len(*((*json.RawMessage)(ptr))) == 0
+}


Test patch:
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/site-ext.json b/adapters/adnuntius/adnuntiustest/supplemental/site-ext.json
new file mode 100644
index 00000000..1d1ef3d3
--- /dev/null
+++ b/adapters/adnuntius/adnuntiustest/supplemental/site-ext.json
@@ -0,0 +1,113 @@
+{
+	"mockBidRequest": {
+		"id": "test-request-id",
+		"user": {
+			"id": "1kjh3429kjh295jkl"
+		},
+		"site": {
+			"ext":{
+				"data" : {
+					"key": ["value"]
+				}
+			}
+		},
+		"imp": [
+			{
+				"id": "test-imp-id",
+				"banner": {
+					"format": [
+						{
+							"w": 300,
+							"h": 250
+						},
+						{
+							"w": 300,
+							"h": 600
+						}
+					]
+				},
+				"ext": {
+					"bidder": {
+						"auId": "123"
+					}
+				}
+			}
+		]
+	},
+	"httpCalls": [
+		{
+			"expectedRequest": {
+				"uri": "http://whatever.url?format=json&tzo=0",
+				"body": {
+					"adUnits": [
+						{
+							"auId": "123",
+							"targetId": "123-test-imp-id",
+							"dimensions": [[300,250],[300,600]]
+						}
+					],
+					"kv": {
+						"key": ["value"]
+					},
+					"metaData": {
+						"usi": "1kjh3429kjh295jkl"
+					},
+					"context": "unknown"
+				}
+			},
+			"mockResponse": {
+				"status": 200,
+				"body": {
+					"adUnits": [
+						{
+							"auId": "0000000000000123",
+							"targetId": "123-test-imp-id",
+							"html": "<ADCODE>",
+							"responseId": "adn-rsp-900646517",
+							"ads": [
+								{
+									"destinationUrls": {
+										"url": "http://www.google.com"
+									},
+									"bid": {
+										"amount": 20.0,
+										"currency": "NOK"
+									},
+									"adId": "adn-id-1559784094",
+									"creativeWidth": "980",
+									"creativeHeight": "240",
+									"creativeId": "jn9hpzvlsf8cpdmm",
+									"lineItemId": "q7y9qm5b0xt9htrv"
+								}
+							]
+						}
+					]
+				}
+			}
+		}
+	],
+	"expectedBidResponses": [
+		{
+			"bids": [
+				{
+					"bid": {
+						"id": "adn-id-1559784094",
+						"impid": "test-imp-id",
+						"price": 20000,
+						"adm": "<ADCODE>",
+						"adid": "adn-id-1559784094",
+						"adomain": [
+							"google.com"
+						],
+						"cid": "q7y9qm5b0xt9htrv",
+						"crid": "jn9hpzvlsf8cpdmm",
+						"w": 980,
+						"h": 240
+					},
+					"type": "banner"
+				}
+			],
+			"currency": "NOK"
+		}
+	]
+}
\ No newline at end of file
diff --git a/adapters/adnuntius/adnuntiustest/supplemental/user-ext.json b/adapters/adnuntius/adnuntiustest/supplemental/user-ext.json
new file mode 100644
index 00000000..7d5f8937
--- /dev/null
+++ b/adapters/adnuntius/adnuntiustest/supplemental/user-ext.json
@@ -0,0 +1,112 @@
+{
+	"mockBidRequest": {
+		"id": "test-request-id",
+		"user": {
+			"ext":{
+				"eids" : [
+					{ 
+						"source": "idProvider", 
+						"uids": [
+							{ "id": "userId", "atype": 1, "ext": { "stype": "ppuid" } }
+						] 
+					}
+				]
+			}
+		},
+		"imp": [
+			{
+				"id": "test-imp-id",
+				"banner": {
+					"format": [
+						{
+							"w": 300,
+							"h": 250
+						},
+						{
+							"w": 300,
+							"h": 600
+						}
+					]
+				},
+				"ext": {
+					"bidder": {
+						"auId": "123"
+					}
+				}
+			}
+		]
+	},
+	"httpCalls": [
+		{
+			"expectedRequest": {
+				"uri": "http://whatever.url?format=json&tzo=0",
+				"body": {
+					"adUnits": [
+						{
+							"auId": "123",
+							"targetId": "123-test-imp-id",
+							"dimensions": [[300,250],[300,600]]
+						}
+					],
+					"metaData": {
+						"usi": "userId"
+					},
+					"context": "unknown"
+				}
+			},
+			"mockResponse": {
+				"status": 200,
+				"body": {
+					"adUnits": [
+						{
+							"auId": "0000000000000123",
+							"targetId": "123-test-imp-id",
+							"html": "<ADCODE>",
+							"responseId": "adn-rsp-900646517",
+							"ads": [
+								{
+									"destinationUrls": {
+										"url": "http://www.google.com"
+									},
+									"bid": {
+										"amount": 20.0,
+										"currency": "NOK"
+									},
+									"adId": "adn-id-1559784094",
+									"creativeWidth": "980",
+									"creativeHeight": "240",
+									"creativeId": "jn9hpzvlsf8cpdmm",
+									"lineItemId": "q7y9qm5b0xt9htrv"
+								}
+							]
+						}
+					]
+				}
+			}
+		}
+	],
+	"expectedBidResponses": [
+		{
+			"bids": [
+				{
+					"bid": {
+						"id": "adn-id-1559784094",
+						"impid": "test-imp-id",
+						"price": 20000,
+						"adm": "<ADCODE>",
+						"adid": "adn-id-1559784094",
+						"adomain": [
+							"google.com"
+						],
+						"cid": "q7y9qm5b0xt9htrv",
+						"crid": "jn9hpzvlsf8cpdmm",
+						"w": 980,
+						"h": 240
+					},
+					"type": "banner"
+				}
+			],
+			"currency": "NOK"
+		}
+	]
+}
\ No newline at end of file
diff --git a/adapters/medianet/medianettest/supplemental/valid-req-200-bid-response-from-mnet.json b/adapters/medianet/medianettest/supplemental/valid-req-200-bid-response-from-mnet.json
index e6a9b654..7925ab3f 100644
--- a/adapters/medianet/medianettest/supplemental/valid-req-200-bid-response-from-mnet.json
+++ b/adapters/medianet/medianettest/supplemental/valid-req-200-bid-response-from-mnet.json
@@ -36,9 +36,7 @@
       "USD"
     ],
     "regs": {
-      "ext": {
-        "gdpr": 0
-      }
+      "gdpr": 0
     }
   },
   "httpCalls": [{
@@ -81,9 +79,7 @@
           "USD"
         ],
         "regs": {
-          "ext": {
-            "gdpr": 0
-          }
+          "gdpr": 0
         }
       }
     },
diff --git a/adapters/seedingAlliance/seedingAlliance_test.go b/adapters/seedingAlliance/seedingAlliance_test.go
index 6d9460b8..ae9b888e 100644
--- a/adapters/seedingAlliance/seedingAlliance_test.go
+++ b/adapters/seedingAlliance/seedingAlliance_test.go
@@ -136,24 +136,27 @@ func TestGetMediaTypeForBid(t *testing.T) {
 
 func TestGetExtInfo(t *testing.T) {
 	type args struct {
-		adUnitId string
-		seatId   string
+		adUnitId  string
+		seatId    string
+		accountId string
 	}
 	tests := []struct {
-		name             string
-		expectedAdUnitID string
-		expectedSeatID   string
-		data             args
-		wantErr          bool
+		name              string
+		expectedAdUnitID  string
+		expectedAccountId string
+		data              args
+		wantErr           bool
 	}{
 		{"regular case", "abc123", "pbs", args{adUnitId: "abc123"}, false},
 		{"nil case", "", "pbs", args{adUnitId: ""}, false},
 		{"unmarshal err case", "", "pbs", args{adUnitId: ""}, true},
 		{"seatId case", "abc123", "seat1", args{adUnitId: "abc123", seatId: "seat1"}, false},
+		{"accountId case", "abc123", "account1", args{adUnitId: "abc123", accountId: "account1"}, false},
+		{"accountId and seatId case", "abc123", "account1", args{adUnitId: "abc123", accountId: "account1", seatId: "seat1"}, false},
 	}
 
 	for _, test := range tests {
-		extSA, err := json.Marshal(openrtb_ext.ImpExtSeedingAlliance{AdUnitID: test.data.adUnitId, SeatID: test.data.seatId})
+		extSA, err := json.Marshal(openrtb_ext.ImpExtSeedingAlliance{AdUnitID: test.data.adUnitId, SeatID: test.data.seatId, AccountID: test.data.accountId})
 		if err != nil {
 			t.Fatalf("unexpected error %v", err)
 		}
@@ -168,7 +171,7 @@ func TestGetExtInfo(t *testing.T) {
 		}
 
 		ortbImp := openrtb2.Imp{Ext: extBidder}
-		seatID, err := getExtInfo(&ortbImp)
+		accountId, err := getExtInfo(&ortbImp)
 		if err != nil {
 			if test.wantErr {
 				continue
@@ -180,8 +183,8 @@ func TestGetExtInfo(t *testing.T) {
 			t.Fatalf("want: %v, got: %v", test.expectedAdUnitID, ortbImp.TagID)
 		}
 
-		if test.expectedSeatID != seatID {
-			t.Fatalf("want: %v, got: %v", test.expectedSeatID, seatID)
+		if test.expectedAccountId != accountId {
+			t.Fatalf("want: %v, got: %v", test.expectedAccountId, accountId)
 		}
 	}
 }
diff --git a/adapters/seedingAlliance/seedingAlliancetest/exemplary/banner_with_account.json b/adapters/seedingAlliance/seedingAlliancetest/exemplary/banner_with_account.json
new file mode 100644
index 00000000..fc3678ea
--- /dev/null
+++ b/adapters/seedingAlliance/seedingAlliancetest/exemplary/banner_with_account.json
@@ -0,0 +1,142 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "site": {
+            "publisher": {
+                "id": "foo",
+                "name": "foo"
+            }
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "adUnitId": "example-tag-id",
+                        "accountId": "123"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "https://mockup.seeding-alliance.de/?ssp=123",
+                "body": {
+                    "cur": [
+                        "EUR"
+                    ],
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ]
+                            },
+                            "tagid": "example-tag-id",
+                            "ext": {
+                                "bidder": {
+                                    "adUnitId": "example-tag-id",
+                                    "accountId": "123"
+                                }
+                            }
+                        }
+                    ],
+                    "site": {
+                        "publisher": {
+                            "id": "foo",
+                            "name": "foo"
+                        }
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "123",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "12341234",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "domain.com"
+                                    ],
+                                    "iurl": "http://abc.com/cr?id=12341234",
+                                    "cid": "123",
+                                    "crid": "12341234",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "banner"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "EUR"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "EUR",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "12341234",
+                        "adomain": [
+                            "domain.com"
+                        ],
+                        "iurl": "http://abc.com/cr?id=12341234",
+                        "cid": "123",
+                        "crid": "12341234",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "prebid": {
+                                "type": "banner"
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/seedingAlliance/seedingAlliancetest/exemplary/banner_with_account_and_seat.json b/adapters/seedingAlliance/seedingAlliancetest/exemplary/banner_with_account_and_seat.json
new file mode 100644
index 00000000..3f010e60
--- /dev/null
+++ b/adapters/seedingAlliance/seedingAlliancetest/exemplary/banner_with_account_and_seat.json
@@ -0,0 +1,144 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "site": {
+            "publisher": {
+                "id": "foo",
+                "name": "foo"
+            }
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "adUnitId": "example-tag-id",
+                        "seatId": "ignored",
+                        "accountId": "123"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "https://mockup.seeding-alliance.de/?ssp=123",
+                "body": {
+                    "cur": [
+                        "EUR"
+                    ],
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ]
+                            },
+                            "tagid": "example-tag-id",
+                            "ext": {
+                                "bidder": {
+                                    "adUnitId": "example-tag-id",
+                                    "seatId": "ignored",
+                                    "accountId": "123"
+                                }
+                            }
+                        }
+                    ],
+                    "site": {
+                        "publisher": {
+                            "id": "foo",
+                            "name": "foo"
+                        }
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "123",
+                            "bid": [
+                                {
+                                    "id": "7706636740145184841",
+                                    "impid": "test-imp-id",
+                                    "price": 0.5,
+                                    "adid": "12341234",
+                                    "adm": "some-test-ad",
+                                    "adomain": [
+                                        "domain.com"
+                                    ],
+                                    "iurl": "http://abc.com/cr?id=12341234",
+                                    "cid": "123",
+                                    "crid": "12341234",
+                                    "h": 250,
+                                    "w": 300,
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "banner"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    ],
+                    "bidid": "5778926625248726496",
+                    "cur": "EUR"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "EUR",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "7706636740145184841",
+                        "impid": "test-imp-id",
+                        "price": 0.5,
+                        "adm": "some-test-ad",
+                        "adid": "12341234",
+                        "adomain": [
+                            "domain.com"
+                        ],
+                        "iurl": "http://abc.com/cr?id=12341234",
+                        "cid": "123",
+                        "crid": "12341234",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "prebid": {
+                                "type": "banner"
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/stroeerCore/stroeercoretest/exemplary/dsa.json b/adapters/stroeerCore/stroeercoretest/exemplary/dsa.json
new file mode 100644
index 00000000..70baef5f
--- /dev/null
+++ b/adapters/stroeerCore/stroeercoretest/exemplary/dsa.json
@@ -0,0 +1,202 @@
+{
+  "mockBidRequest": {
+    "id": "auction-id",
+    "cur": [
+      "EUR"
+    ],
+    "imp": [
+      {
+        "id": "1",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "sid": "123456"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ip": "123.123.123.123"
+    },
+    "site": {
+      "domain": "www.publisher.com",
+      "page": "http://www.publisher.com/some/path"
+    },
+    "user": {
+      "buyeruid": "test-buyer-user-id"
+    },
+    "regs": {
+      "ext": {
+        "dsa": {
+          "dsarequired": 3,
+          "pubrender": 0,
+          "datatopub": 2,
+          "transparency": [
+            {
+              "domain": "example-platform.com",
+              "dsaparams": [
+                1
+              ]
+            },
+            {
+              "domain": "example-ssp.com",
+              "dsaparams": [
+                1,
+                2
+              ]
+            }
+          ]
+        }
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ]
+        },
+        "uri": "http://localhost/s2sdsh",
+        "body": {
+          "id": "auction-id",
+          "cur": [
+            "EUR"
+          ],
+          "imp": [
+            {
+              "id": "1",
+              "tagid": "123456",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "sid": "123456"
+                }
+              }
+            }
+          ],
+          "device": {
+            "ip": "123.123.123.123"
+          },
+          "site": {
+            "domain": "www.publisher.com",
+            "page": "http://www.publisher.com/some/path"
+          },
+          "user": {
+            "buyeruid": "test-buyer-user-id"
+          },
+          "regs": {
+            "ext": {
+              "dsa": {
+                "dsarequired": 3,
+                "pubrender": 0,
+                "datatopub": 2,
+                "transparency": [
+                  {
+                    "domain": "example-platform.com",
+                    "dsaparams": [
+                      1
+                    ]
+                  },
+                  {
+                    "domain": "example-ssp.com",
+                    "dsaparams": [
+                      1,
+                      2
+                    ]
+                  }
+                ]
+              }
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "bids": [
+            {
+              "id": "1829273982920-01",
+              "bidId": "1",
+              "cpm": 2,
+              "width": 300,
+              "height": 600,
+              "ad": "advert",
+              "crid": "wasd",
+              "mtype": "banner",
+              "dsa": {
+                "behalf": "Advertiser A",
+                "paid": "Advertiser B",
+                "transparency": [
+                  {
+                    "domain": "example-domain.com",
+                    "dsaparams": [
+                      1,
+                      2
+                    ]
+                  }
+                ],
+                "adrender": 1
+              }
+            }
+          ]
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "EUR",
+      "bids": [
+        {
+          "bid": {
+            "id": "1829273982920-01",
+            "impid": "1",
+            "price": 2,
+            "adm": "advert",
+            "w": 300,
+            "h": 600,
+            "crid": "wasd",
+            "mtype": 1,
+            "ext": {
+              "dsa": {
+                "behalf": "Advertiser A",
+                "paid": "Advertiser B",
+                "transparency": [
+                  {
+                    "domain": "example-domain.com",
+                    "dsaparams": [
+                      1,
+                      2
+                    ]
+                  }
+                ],
+                "adrender": 1
+              }
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/dsa/validate_test.go b/dsa/validate_test.go
index 74d428c3..9dfa32c6 100644
--- a/dsa/validate_test.go
+++ b/dsa/validate_test.go
@@ -2,23 +2,48 @@ package dsa
 
 import (
 	"encoding/json"
+	"strings"
 	"testing"
 
 	"github.com/prebid/openrtb/v20/openrtb2"
 	"github.com/prebid/prebid-server/v2/exchange/entities"
 	"github.com/prebid/prebid-server/v2/openrtb_ext"
+	"github.com/prebid/prebid-server/v2/util/ptrutil"
 	"github.com/stretchr/testify/assert"
 )
 
 func TestValidate(t *testing.T) {
+	var (
+		validBehalf   = strings.Repeat("a", 100)
+		invalidBehalf = strings.Repeat("a", 101)
+		validPaid     = strings.Repeat("a", 100)
+		invalidPaid   = strings.Repeat("a", 101)
+	)
+
 	tests := []struct {
 		name        string
 		giveRequest *openrtb_ext.RequestWrapper
 		giveBid     *entities.PbsOrtbBid
-		wantValid   bool
+		wantError   error
 	}{
 		{
-			name: "not_required",
+			name:        "nil",
+			giveRequest: nil,
+			giveBid:     nil,
+			wantError:   nil,
+		},
+		{
+			name:        "request_nil",
+			giveRequest: nil,
+			giveBid: &entities.PbsOrtbBid{
+				Bid: &openrtb2.Bid{
+					Ext: json.RawMessage(`{"dsa":{"behalf":"` + validBehalf + `","paid":"` + validPaid + `","adrender":1}}`),
+				},
+			},
+			wantError: nil,
+		},
+		{
+			name: "not_required_and_bid_is_nil",
 			giveRequest: &openrtb_ext.RequestWrapper{
 				BidRequest: &openrtb2.BidRequest{
 					Regs: &openrtb2.Regs{
@@ -27,7 +52,23 @@ func TestValidate(t *testing.T) {
 				},
 			},
 			giveBid:   nil,
-			wantValid: true,
+			wantError: nil,
+		},
+		{
+			name: "not_required_and_bid_dsa_is_valid",
+			giveRequest: &openrtb_ext.RequestWrapper{
+				BidRequest: &openrtb2.BidRequest{
+					Regs: &openrtb2.Regs{
+						Ext: json.RawMessage(`{"dsa": {"dsarequired": 0,"pubrender":0}}`),
+					},
+				},
+			},
+			giveBid: &entities.PbsOrtbBid{
+				Bid: &openrtb2.Bid{
+					Ext: json.RawMessage(`{"dsa":{"behalf":"` + validBehalf + `","paid":"` + validPaid + `","adrender":1}}`),
+				},
+			},
+			wantError: nil,
 		},
 		{
 			name: "required_and_bid_is_nil",
@@ -39,10 +80,10 @@ func TestValidate(t *testing.T) {
 				},
 			},
 			giveBid:   nil,
-			wantValid: false,
+			wantError: ErrDsaMissing,
 		},
 		{
-			name: "required_and_bid.bid_is_nil",
+			name: "required_and_bid_dsa_has_invalid_behalf",
 			giveRequest: &openrtb_ext.RequestWrapper{
 				BidRequest: &openrtb2.BidRequest{
 					Regs: &openrtb2.Regs{
@@ -50,11 +91,15 @@ func TestValidate(t *testing.T) {
 					},
 				},
 			},
-			giveBid:   &entities.PbsOrtbBid{},
-			wantValid: false,
+			giveBid: &entities.PbsOrtbBid{
+				Bid: &openrtb2.Bid{
+					Ext: json.RawMessage(`{"dsa":{"behalf":"` + invalidBehalf + `"}}`),
+				},
+			},
+			wantError: ErrBehalfTooLong,
 		},
 		{
-			name: "required_and_bid.ext.dsa_not_present",
+			name: "required_and_bid_dsa_has_invalid_paid",
 			giveRequest: &openrtb_ext.RequestWrapper{
 				BidRequest: &openrtb2.BidRequest{
 					Regs: &openrtb2.Regs{
@@ -64,13 +109,61 @@ func TestValidate(t *testing.T) {
 			},
 			giveBid: &entities.PbsOrtbBid{
 				Bid: &openrtb2.Bid{
-					Ext: json.RawMessage(`{}`),
+					Ext: json.RawMessage(`{"dsa":{"paid":"` + invalidPaid + `"}}`),
+				},
+			},
+			wantError: ErrPaidTooLong,
+		},
+		{
+			name: "required_and_neither_will_render",
+			giveRequest: &openrtb_ext.RequestWrapper{
+				BidRequest: &openrtb2.BidRequest{
+					Regs: &openrtb2.Regs{
+						Ext: json.RawMessage(`{"dsa": {"dsarequired": 2,"pubrender": 0}}`),
+					},
+				},
+			},
+			giveBid: &entities.PbsOrtbBid{
+				Bid: &openrtb2.Bid{
+					Ext: json.RawMessage(`{"dsa":{"adrender": 0}}`),
+				},
+			},
+			wantError: ErrNeitherWillRender,
+		},
+		{
+			name: "required_and_both_will_render",
+			giveRequest: &openrtb_ext.RequestWrapper{
+				BidRequest: &openrtb2.BidRequest{
+					Regs: &openrtb2.Regs{
+						Ext: json.RawMessage(`{"dsa": {"dsarequired": 2,"pubrender": 2}}`),
+					},
 				},
 			},
-			wantValid: false,
+			giveBid: &entities.PbsOrtbBid{
+				Bid: &openrtb2.Bid{
+					Ext: json.RawMessage(`{"dsa":{"adrender": 1}}`),
+				},
+			},
+			wantError: ErrBothWillRender,
 		},
 		{
-			name: "required_and_bid.ext.dsa_present",
+			name: "required_and_bid_dsa_is_valid",
+			giveRequest: &openrtb_ext.RequestWrapper{
+				BidRequest: &openrtb2.BidRequest{
+					Regs: &openrtb2.Regs{
+						Ext: json.RawMessage(`{"dsa": {"dsarequired": 2,"pubrender": 0}}`),
+					},
+				},
+			},
+			giveBid: &entities.PbsOrtbBid{
+				Bid: &openrtb2.Bid{
+					Ext: json.RawMessage(`{"dsa":{"behalf":"` + validBehalf + `","paid":"` + validPaid + `","adrender":1}}`),
+				},
+			},
+			wantError: nil,
+		},
+		{
+			name: "required_and_bid_dsa_is_valid_no_pubrender",
 			giveRequest: &openrtb_ext.RequestWrapper{
 				BidRequest: &openrtb2.BidRequest{
 					Regs: &openrtb2.Regs{
@@ -80,17 +173,37 @@ func TestValidate(t *testing.T) {
 			},
 			giveBid: &entities.PbsOrtbBid{
 				Bid: &openrtb2.Bid{
-					Ext: json.RawMessage(`{"dsa": {}}`),
+					Ext: json.RawMessage(`{"dsa":{"behalf":"` + validBehalf + `","paid":"` + validPaid + `","adrender":2}}`),
+				},
+			},
+			wantError: nil,
+		},
+		{
+			name: "required_and_bid_dsa_is_valid_no_adrender",
+			giveRequest: &openrtb_ext.RequestWrapper{
+				BidRequest: &openrtb2.BidRequest{
+					Regs: &openrtb2.Regs{
+						Ext: json.RawMessage(`{"dsa": {"dsarequired": 2, "pubrender": 0}}`),
+					},
+				},
+			},
+			giveBid: &entities.PbsOrtbBid{
+				Bid: &openrtb2.Bid{
+					Ext: json.RawMessage(`{"dsa":{"behalf":"` + validBehalf + `","paid":"` + validPaid + `"}}`),
 				},
 			},
-			wantValid: true,
+			wantError: nil,
 		},
 	}
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			valid := Validate(tt.giveRequest, tt.giveBid)
-			assert.Equal(t, tt.wantValid, valid)
+			err := Validate(tt.giveRequest, tt.giveBid)
+			if tt.wantError != nil {
+				assert.Equal(t, err, tt.wantError)
+			} else {
+				assert.NoError(t, err)
+			}
 		})
 	}
 }
@@ -98,55 +211,110 @@ func TestValidate(t *testing.T) {
 func TestDSARequired(t *testing.T) {
 	tests := []struct {
 		name         string
-		giveRequest  *openrtb_ext.RequestWrapper
+		giveReqDSA   *openrtb_ext.ExtRegsDSA
 		wantRequired bool
 	}{
 		{
-			name: "not_required_and_reg.ext.dsa_is_nil",
-			giveRequest: &openrtb_ext.RequestWrapper{
-				BidRequest: &openrtb2.BidRequest{
-					Regs: &openrtb2.Regs{
-						Ext: json.RawMessage(`{}`),
-					},
-				},
+			name:         "nil",
+			giveReqDSA:   nil,
+			wantRequired: false,
+		},
+		{
+			name: "nil_required",
+			giveReqDSA: &openrtb_ext.ExtRegsDSA{
+				Required: nil,
+			},
+			wantRequired: false,
+		},
+		{
+			name: "not_required",
+			giveReqDSA: &openrtb_ext.ExtRegsDSA{
+				Required: ptrutil.ToPtr[int8](0),
+			},
+			wantRequired: false,
+		},
+		{
+			name: "not_required_supported",
+			giveReqDSA: &openrtb_ext.ExtRegsDSA{
+				Required: ptrutil.ToPtr[int8](1),
 			},
 			wantRequired: false,
 		},
 		{
-			name: "not_required_and_reg.ext.dsa_is_empty",
+			name: "required",
+			giveReqDSA: &openrtb_ext.ExtRegsDSA{
+				Required: ptrutil.ToPtr[int8](2),
+			},
+			wantRequired: true,
+		},
+		{
+			name: "required_online_platform",
+			giveReqDSA: &openrtb_ext.ExtRegsDSA{
+				Required: ptrutil.ToPtr[int8](3),
+			},
+			wantRequired: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			required := dsaRequired(tt.giveReqDSA)
+			assert.Equal(t, tt.wantRequired, required)
+		})
+	}
+}
+
+func TestGetReqDSA(t *testing.T) {
+	tests := []struct {
+		name        string
+		giveRequest *openrtb_ext.RequestWrapper
+		expectedDSA *openrtb_ext.ExtRegsDSA
+	}{
+		{
+			name:        "req_is_nil",
+			giveRequest: nil,
+			expectedDSA: nil,
+		},
+		{
+			name: "bidrequest_is_nil",
+			giveRequest: &openrtb_ext.RequestWrapper{
+				BidRequest: nil,
+			},
+			expectedDSA: nil,
+		},
+		{
+			name: "req.regs_is_nil",
 			giveRequest: &openrtb_ext.RequestWrapper{
 				BidRequest: &openrtb2.BidRequest{
-					Regs: &openrtb2.Regs{
-						Ext: json.RawMessage(`{"dsa": {}}`),
-					},
+					Regs: nil,
 				},
 			},
-			wantRequired: false,
+			expectedDSA: nil,
 		},
 		{
-			name: "required_and_reg.ext.dsa_is_0",
+			name: "req.regs.ext_is_nil",
 			giveRequest: &openrtb_ext.RequestWrapper{
 				BidRequest: &openrtb2.BidRequest{
 					Regs: &openrtb2.Regs{
-						Ext: json.RawMessage(`{"dsa": {"dsarequired": 0}}`),
+						Ext: nil,
 					},
 				},
 			},
-			wantRequired: false,
+			expectedDSA: nil,
 		},
 		{
-			name: "required_and_reg.ext.dsa_is_1",
+			name: "req.regs.ext_is_empty",
 			giveRequest: &openrtb_ext.RequestWrapper{
 				BidRequest: &openrtb2.BidRequest{
 					Regs: &openrtb2.Regs{
-						Ext: json.RawMessage(`{"dsa": {"dsarequired": 1}}`),
+						Ext: json.RawMessage(`{}`),
 					},
 				},
 			},
-			wantRequired: false,
+			expectedDSA: nil,
 		},
 		{
-			name: "required_and_reg.ext.dsa_is_2",
+			name: "req.regs.ext_dsa_is_populated",
 			giveRequest: &openrtb_ext.RequestWrapper{
 				BidRequest: &openrtb2.BidRequest{
 					Regs: &openrtb2.Regs{
@@ -154,25 +322,75 @@ func TestDSARequired(t *testing.T) {
 					},
 				},
 			},
-			wantRequired: true,
+			expectedDSA: &openrtb_ext.ExtRegsDSA{
+				Required: ptrutil.ToPtr[int8](2),
+			},
 		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			dsa := getReqDSA(tt.giveRequest)
+			assert.Equal(t, tt.expectedDSA, dsa)
+		})
+	}
+}
+
+func TestGetBidDSA(t *testing.T) {
+	tests := []struct {
+		name        string
+		bid         *entities.PbsOrtbBid
+		expectedDSA *openrtb_ext.ExtBidDSA
+	}{
 		{
-			name: "required_and_reg.ext.dsa_is_3",
-			giveRequest: &openrtb_ext.RequestWrapper{
-				BidRequest: &openrtb2.BidRequest{
-					Regs: &openrtb2.Regs{
-						Ext: json.RawMessage(`{"dsa": {"dsarequired": 3}}`),
-					},
+			name:        "bid_is_nil",
+			bid:         nil,
+			expectedDSA: nil,
+		},
+		{
+			name: "bid.bid_is_nil",
+			bid: &entities.PbsOrtbBid{
+				Bid: nil,
+			},
+			expectedDSA: nil,
+		},
+		{
+			name: "bid.bid.ext_is_nil",
+			bid: &entities.PbsOrtbBid{
+				Bid: &openrtb2.Bid{
+					Ext: nil,
 				},
 			},
-			wantRequired: true,
+			expectedDSA: nil,
+		},
+		{
+			name: "bid.bid.ext_is_empty",
+			bid: &entities.PbsOrtbBid{
+				Bid: &openrtb2.Bid{
+					Ext: json.RawMessage(`{}`),
+				},
+			},
+			expectedDSA: nil,
+		},
+		{
+			name: "bid.bid.ext.dsa_is_populated",
+			bid: &entities.PbsOrtbBid{
+				Bid: &openrtb2.Bid{
+					Ext: json.RawMessage(`{"dsa": {"behalf":"test1","paid":"test2","adrender":1}}`),
+				},
+			},
+			expectedDSA: &openrtb_ext.ExtBidDSA{
+				Behalf:   "test1",
+				Paid:     "test2",
+				AdRender: ptrutil.ToPtr[int8](1),
+			},
 		},
 	}
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			required := dsaRequired(tt.giveRequest)
-			assert.Equal(t, tt.wantRequired, required)
+			dsa := getBidDSA(tt.bid)
+			assert.Equal(t, tt.expectedDSA, dsa)
 		})
 	}
 }
diff --git a/endpoints/info/bidders_detail_test.go b/endpoints/info/bidders_detail_test.go
index 2911aa8e..4965dece 100644
--- a/endpoints/info/bidders_detail_test.go
+++ b/endpoints/info/bidders_detail_test.go
@@ -453,7 +453,10 @@ func TestBiddersDetailHandler(t *testing.T) {
 	for _, test := range testCases {
 		t.Run(test.description, func(t *testing.T) {
 			responseRecorder := httptest.NewRecorder()
-			handler(responseRecorder, nil, httprouter.Params{{"bidderName", test.givenBidder}})
+			handler(responseRecorder, nil, httprouter.Params{{
+				Key:   "bidderName",
+				Value: test.givenBidder,
+			}})
 
 			result := responseRecorder.Result()
 			assert.Equal(t, result.StatusCode, test.expectedStatus, test.description+":statuscode")
diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go
index a9e16c94..9df8b540 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -18,6 +18,7 @@ import (
 	"time"
 
 	"github.com/buger/jsonparser"
+	jsoniter "github.com/json-iterator/go"
 	"github.com/julienschmidt/httprouter"
 	"github.com/prebid/openrtb/v20/native1"
 	nativeRequests "github.com/prebid/openrtb/v20/native1/request"
@@ -43,6 +44,11 @@ import (
 
 const jsonFileExtension string = ".json"
 
+func TestMain(m *testing.M) {
+	jsoniter.RegisterExtension(&jsonutil.RawMessageExtension{})
+	os.Exit(m.Run())
+}
+
 func TestJsonSampleRequests(t *testing.T) {
 	testSuites := []struct {
 		description          string
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 44baaf8d..9156fc06 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -2566,10 +2566,10 @@ func TestCategoryMapping(t *testing.T) {
 	bid3 := openrtb2.Bid{ID: "bid_id3", ImpID: "imp_id3", Price: 30.0000, Cat: cats3, W: 1, H: 1}
 	bid4 := openrtb2.Bid{ID: "bid_id4", ImpID: "imp_id4", Price: 40.0000, Cat: cats4, W: 1, H: 1}
 
-	bid1_1 := entities.PbsOrtbBid{&bid1, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
-	bid1_2 := entities.PbsOrtbBid{&bid2, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, nil, nil, 0, false, "", 20.0000, "USD", ""}
-	bid1_3 := entities.PbsOrtbBid{&bid3, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30, PrimaryCategory: "AdapterOverride"}, nil, nil, 0, false, "", 30.0000, "USD", ""}
-	bid1_4 := entities.PbsOrtbBid{&bid4, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 40.0000, "USD", ""}
+	bid1_1 := entities.PbsOrtbBid{Bid: &bid1, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_2 := entities.PbsOrtbBid{Bid: &bid2, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 20.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_3 := entities.PbsOrtbBid{Bid: &bid3, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30, PrimaryCategory: "AdapterOverride"}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 30.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_4 := entities.PbsOrtbBid{Bid: &bid4, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 40.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
 
 	innerBids := []*entities.PbsOrtbBid{
 		&bid1_1,
@@ -2621,10 +2621,10 @@ func TestCategoryMappingNoIncludeBrandCategory(t *testing.T) {
 	bid3 := openrtb2.Bid{ID: "bid_id3", ImpID: "imp_id3", Price: 30.0000, Cat: cats3, W: 1, H: 1}
 	bid4 := openrtb2.Bid{ID: "bid_id4", ImpID: "imp_id4", Price: 40.0000, Cat: cats4, W: 1, H: 1}
 
-	bid1_1 := entities.PbsOrtbBid{&bid1, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
-	bid1_2 := entities.PbsOrtbBid{&bid2, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, nil, nil, 0, false, "", 20.0000, "USD", ""}
-	bid1_3 := entities.PbsOrtbBid{&bid3, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30, PrimaryCategory: "AdapterOverride"}, nil, nil, 0, false, "", 30.0000, "USD", ""}
-	bid1_4 := entities.PbsOrtbBid{&bid4, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 50}, nil, nil, 0, false, "", 40.0000, "USD", ""}
+	bid1_1 := entities.PbsOrtbBid{Bid: &bid1, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_2 := entities.PbsOrtbBid{Bid: &bid2, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 20.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_3 := entities.PbsOrtbBid{Bid: &bid3, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30, PrimaryCategory: "AdapterOverride"}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 30.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_4 := entities.PbsOrtbBid{Bid: &bid4, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 50}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 40.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
 
 	innerBids := []*entities.PbsOrtbBid{
 		&bid1_1,
@@ -2675,9 +2675,9 @@ func TestCategoryMappingTranslateCategoriesNil(t *testing.T) {
 	bid2 := openrtb2.Bid{ID: "bid_id2", ImpID: "imp_id2", Price: 20.0000, Cat: cats2, W: 1, H: 1}
 	bid3 := openrtb2.Bid{ID: "bid_id3", ImpID: "imp_id3", Price: 30.0000, Cat: cats3, W: 1, H: 1}
 
-	bid1_1 := entities.PbsOrtbBid{&bid1, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
-	bid1_2 := entities.PbsOrtbBid{&bid2, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, nil, nil, 0, false, "", 20.0000, "USD", ""}
-	bid1_3 := entities.PbsOrtbBid{&bid3, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 30.0000, "USD", ""}
+	bid1_1 := entities.PbsOrtbBid{Bid: &bid1, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_2 := entities.PbsOrtbBid{Bid: &bid2, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 20.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_3 := entities.PbsOrtbBid{Bid: &bid3, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 30.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
 
 	innerBids := []*entities.PbsOrtbBid{
 		&bid1_1,
@@ -2757,9 +2757,9 @@ func TestCategoryMappingTranslateCategoriesFalse(t *testing.T) {
 	bid2 := openrtb2.Bid{ID: "bid_id2", ImpID: "imp_id2", Price: 20.0000, Cat: cats2, W: 1, H: 1}
 	bid3 := openrtb2.Bid{ID: "bid_id3", ImpID: "imp_id3", Price: 30.0000, Cat: cats3, W: 1, H: 1}
 
-	bid1_1 := entities.PbsOrtbBid{&bid1, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
-	bid1_2 := entities.PbsOrtbBid{&bid2, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, nil, nil, 0, false, "", 20.0000, "USD", ""}
-	bid1_3 := entities.PbsOrtbBid{&bid3, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 30.0000, "USD", ""}
+	bid1_1 := entities.PbsOrtbBid{Bid: &bid1, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_2 := entities.PbsOrtbBid{Bid: &bid2, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 40}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 20.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_3 := entities.PbsOrtbBid{Bid: &bid3, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 30.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
 
 	innerBids := []*entities.PbsOrtbBid{
 		&bid1_1,
@@ -2885,11 +2885,11 @@ func TestNoCategoryDedupe(t *testing.T) {
 	bid4 := openrtb2.Bid{ID: "bid_id4", ImpID: "imp_id4", Price: 20.0000, Cat: cats4, W: 1, H: 1}
 	bid5 := openrtb2.Bid{ID: "bid_id5", ImpID: "imp_id5", Price: 10.0000, Cat: cats1, W: 1, H: 1}
 
-	bid1_1 := entities.PbsOrtbBid{&bid1, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 14.0000, "USD", ""}
-	bid1_2 := entities.PbsOrtbBid{&bid2, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 14.0000, "USD", ""}
-	bid1_3 := entities.PbsOrtbBid{&bid3, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 20.0000, "USD", ""}
-	bid1_4 := entities.PbsOrtbBid{&bid4, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 20.0000, "USD", ""}
-	bid1_5 := entities.PbsOrtbBid{&bid5, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
+	bid1_1 := entities.PbsOrtbBid{Bid: &bid1, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 14.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_2 := entities.PbsOrtbBid{Bid: &bid2, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 14.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_3 := entities.PbsOrtbBid{Bid: &bid3, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 20.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_4 := entities.PbsOrtbBid{Bid: &bid4, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 20.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_5 := entities.PbsOrtbBid{Bid: &bid5, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
 
 	selectedBids := make(map[string]int)
 	expectedCategories := map[string]string{
@@ -2965,8 +2965,8 @@ func TestCategoryMappingBidderName(t *testing.T) {
 	bid1 := openrtb2.Bid{ID: "bid_id1", ImpID: "imp_id1", Price: 10.0000, Cat: cats1, W: 1, H: 1}
 	bid2 := openrtb2.Bid{ID: "bid_id2", ImpID: "imp_id2", Price: 10.0000, Cat: cats2, W: 1, H: 1}
 
-	bid1_1 := entities.PbsOrtbBid{&bid1, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
-	bid1_2 := entities.PbsOrtbBid{&bid2, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
+	bid1_1 := entities.PbsOrtbBid{Bid: &bid1, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_2 := entities.PbsOrtbBid{Bid: &bid2, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
 
 	innerBids1 := []*entities.PbsOrtbBid{
 		&bid1_1,
@@ -3019,8 +3019,8 @@ func TestCategoryMappingBidderNameNoCategories(t *testing.T) {
 	bid1 := openrtb2.Bid{ID: "bid_id1", ImpID: "imp_id1", Price: 10.0000, Cat: cats1, W: 1, H: 1}
 	bid2 := openrtb2.Bid{ID: "bid_id2", ImpID: "imp_id2", Price: 12.0000, Cat: cats2, W: 1, H: 1}
 
-	bid1_1 := entities.PbsOrtbBid{&bid1, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 17}, nil, nil, 0, false, "", 10.0000, "USD", ""}
-	bid1_2 := entities.PbsOrtbBid{&bid2, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 8}, nil, nil, 0, false, "", 12.0000, "USD", ""}
+	bid1_1 := entities.PbsOrtbBid{Bid: &bid1, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 17}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_2 := entities.PbsOrtbBid{Bid: &bid2, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 8}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 12.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
 
 	innerBids1 := []*entities.PbsOrtbBid{
 		&bid1_1,
@@ -3131,7 +3131,7 @@ func TestBidRejectionErrors(t *testing.T) {
 		innerBids := []*entities.PbsOrtbBid{}
 		for _, bid := range test.bids {
 			currentBid := entities.PbsOrtbBid{
-				bid, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: test.duration}, nil, nil, 0, false, "", 10.0000, "USD", ""}
+				Bid: bid, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: test.duration}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
 			innerBids = append(innerBids, &currentBid)
 		}
 
@@ -3179,8 +3179,8 @@ func TestCategoryMappingTwoBiddersOneBidEachNoCategorySamePrice(t *testing.T) {
 	bidApn1 := openrtb2.Bid{ID: "bid_idApn1", ImpID: "imp_idApn1", Price: 10.0000, Cat: cats1, W: 1, H: 1}
 	bidApn2 := openrtb2.Bid{ID: "bid_idApn2", ImpID: "imp_idApn2", Price: 10.0000, Cat: cats2, W: 1, H: 1}
 
-	bid1_Apn1 := entities.PbsOrtbBid{&bidApn1, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
-	bid1_Apn2 := entities.PbsOrtbBid{&bidApn2, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
+	bid1_Apn1 := entities.PbsOrtbBid{Bid: &bidApn1, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_Apn2 := entities.PbsOrtbBid{Bid: &bidApn2, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
 
 	innerBidsApn1 := []*entities.PbsOrtbBid{
 		&bid1_Apn1,
@@ -3259,11 +3259,11 @@ func TestCategoryMappingTwoBiddersManyBidsEachNoCategorySamePrice(t *testing.T)
 	bidApn2_1 := openrtb2.Bid{ID: "bid_idApn2_1", ImpID: "imp_idApn2_1", Price: 10.0000, Cat: cats2, W: 1, H: 1}
 	bidApn2_2 := openrtb2.Bid{ID: "bid_idApn2_2", ImpID: "imp_idApn2_2", Price: 20.0000, Cat: cats2, W: 1, H: 1}
 
-	bid1_Apn1_1 := entities.PbsOrtbBid{&bidApn1_1, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
-	bid1_Apn1_2 := entities.PbsOrtbBid{&bidApn1_2, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 20.0000, "USD", ""}
+	bid1_Apn1_1 := entities.PbsOrtbBid{Bid: &bidApn1_1, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_Apn1_2 := entities.PbsOrtbBid{Bid: &bidApn1_2, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 20.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
 
-	bid1_Apn2_1 := entities.PbsOrtbBid{&bidApn2_1, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
-	bid1_Apn2_2 := entities.PbsOrtbBid{&bidApn2_2, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 20.0000, "USD", ""}
+	bid1_Apn2_1 := entities.PbsOrtbBid{Bid: &bidApn2_1, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_Apn2_2 := entities.PbsOrtbBid{Bid: &bidApn2_2, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 20.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
 
 	innerBidsApn1 := []*entities.PbsOrtbBid{
 		&bid1_Apn1_1,
@@ -3341,9 +3341,9 @@ func TestRemoveBidById(t *testing.T) {
 	bidApn1_2 := openrtb2.Bid{ID: "bid_idApn1_2", ImpID: "imp_idApn1_2", Price: 20.0000, Cat: cats1, W: 1, H: 1}
 	bidApn1_3 := openrtb2.Bid{ID: "bid_idApn1_3", ImpID: "imp_idApn1_3", Price: 10.0000, Cat: cats1, W: 1, H: 1}
 
-	bid1_Apn1_1 := entities.PbsOrtbBid{&bidApn1_1, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
-	bid1_Apn1_2 := entities.PbsOrtbBid{&bidApn1_2, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 20.0000, "USD", ""}
-	bid1_Apn1_3 := entities.PbsOrtbBid{&bidApn1_3, nil, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, nil, nil, 0, false, "", 10.0000, "USD", ""}
+	bid1_Apn1_1 := entities.PbsOrtbBid{Bid: &bidApn1_1, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_Apn1_2 := entities.PbsOrtbBid{Bid: &bidApn1_2, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 20.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
+	bid1_Apn1_3 := entities.PbsOrtbBid{Bid: &bidApn1_3, BidMeta: nil, BidType: "video", BidTargets: nil, BidVideo: &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, BidEvents: nil, BidFloors: nil, DealPriority: 0, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 10.0000, OriginalBidCur: "USD", TargetBidderCode: ""}
 
 	type aTest struct {
 		desc      string
@@ -3544,7 +3544,7 @@ func TestApplyDealSupport(t *testing.T) {
 			},
 		}
 
-		bid := entities.PbsOrtbBid{&openrtb2.Bid{ID: "123456"}, nil, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, nil, nil, test.in.dealPriority, false, "", 0, "USD", ""}
+		bid := entities.PbsOrtbBid{Bid: &openrtb2.Bid{ID: "123456"}, BidMeta: nil, BidType: "video", BidTargets: map[string]string{}, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, BidEvents: nil, BidFloors: nil, DealPriority: test.in.dealPriority, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 0, OriginalBidCur: "USD", TargetBidderCode: ""}
 		bidCategory := map[string]string{
 			bid.Bid.ID: test.in.targ["hb_pb_cat_dur"],
 		}
@@ -3604,8 +3604,8 @@ func TestApplyDealSupportMultiBid(t *testing.T) {
 					allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{
 						"imp_id1": {
 							openrtb_ext.BidderName("appnexus"): {
-								&entities.PbsOrtbBid{&openrtb2.Bid{ID: "123456"}, nil, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, nil, nil, 5, false, "", 0, "USD", ""},
-								&entities.PbsOrtbBid{&openrtb2.Bid{ID: "789101"}, nil, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, nil, nil, 5, false, "", 0, "USD", ""},
+								&entities.PbsOrtbBid{Bid: &openrtb2.Bid{ID: "123456"}, BidMeta: nil, BidType: "video", BidTargets: map[string]string{}, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, BidEvents: nil, BidFloors: nil, DealPriority: 5, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 0, OriginalBidCur: "USD", TargetBidderCode: ""},
+								&entities.PbsOrtbBid{Bid: &openrtb2.Bid{ID: "789101"}, BidMeta: nil, BidType: "video", BidTargets: map[string]string{}, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, BidEvents: nil, BidFloors: nil, DealPriority: 5, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 0, OriginalBidCur: "USD", TargetBidderCode: ""},
 							},
 						},
 					},
@@ -3650,8 +3650,8 @@ func TestApplyDealSupportMultiBid(t *testing.T) {
 					allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{
 						"imp_id1": {
 							openrtb_ext.BidderName("appnexus"): {
-								&entities.PbsOrtbBid{&openrtb2.Bid{ID: "123456"}, nil, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, nil, nil, 5, false, "", 0, "USD", ""},
-								&entities.PbsOrtbBid{&openrtb2.Bid{ID: "789101"}, nil, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, nil, nil, 5, false, "", 0, "USD", ""},
+								&entities.PbsOrtbBid{Bid: &openrtb2.Bid{ID: "123456"}, BidMeta: nil, BidType: "video", BidTargets: map[string]string{}, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, BidEvents: nil, BidFloors: nil, DealPriority: 5, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 0, OriginalBidCur: "USD", TargetBidderCode: ""},
+								&entities.PbsOrtbBid{Bid: &openrtb2.Bid{ID: "789101"}, BidMeta: nil, BidType: "video", BidTargets: map[string]string{}, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, BidEvents: nil, BidFloors: nil, DealPriority: 5, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 0, OriginalBidCur: "USD", TargetBidderCode: ""},
 							},
 						},
 					},
@@ -3701,8 +3701,8 @@ func TestApplyDealSupportMultiBid(t *testing.T) {
 					allBidsByBidder: map[string]map[openrtb_ext.BidderName][]*entities.PbsOrtbBid{
 						"imp_id1": {
 							openrtb_ext.BidderName("appnexus"): {
-								&entities.PbsOrtbBid{&openrtb2.Bid{ID: "123456"}, nil, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, nil, nil, 5, false, "", 0, "USD", ""},
-								&entities.PbsOrtbBid{&openrtb2.Bid{ID: "789101"}, nil, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, nil, nil, 5, false, "", 0, "USD", ""},
+								&entities.PbsOrtbBid{Bid: &openrtb2.Bid{ID: "123456"}, BidMeta: nil, BidType: "video", BidTargets: map[string]string{}, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, BidEvents: nil, BidFloors: nil, DealPriority: 5, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 0, OriginalBidCur: "USD", TargetBidderCode: ""},
+								&entities.PbsOrtbBid{Bid: &openrtb2.Bid{ID: "789101"}, BidMeta: nil, BidType: "video", BidTargets: map[string]string{}, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, BidEvents: nil, BidFloors: nil, DealPriority: 5, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 0, OriginalBidCur: "USD", TargetBidderCode: ""},
 							},
 						},
 					},
@@ -3893,7 +3893,7 @@ func TestUpdateHbPbCatDur(t *testing.T) {
 	}
 
 	for _, test := range testCases {
-		bid := entities.PbsOrtbBid{&openrtb2.Bid{ID: "123456"}, nil, "video", map[string]string{}, &openrtb_ext.ExtBidPrebidVideo{}, nil, nil, test.dealPriority, false, "", 0, "USD", ""}
+		bid := entities.PbsOrtbBid{Bid: &openrtb2.Bid{ID: "123456"}, BidMeta: nil, BidType: "video", BidTargets: map[string]string{}, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, BidEvents: nil, BidFloors: nil, DealPriority: test.dealPriority, DealTierSatisfied: false, GeneratedBidID: "", OriginalBidCPM: 0, OriginalBidCur: "USD", TargetBidderCode: ""}
 		bidCategory := map[string]string{
 			bid.Bid.ID: test.targ["hb_pb_cat_dur"],
 		}
@@ -4758,14 +4758,14 @@ func TestMakeBidWithValidation(t *testing.T) {
 			name:               "One_of_two_bids_is_invalid_based_on_DSA_object_presence",
 			givenBidRequestExt: json.RawMessage(`{"dsa": {"dsarequired": 2}}`),
 			givenValidations:   config.Validations{},
-			givenBids:          []*entities.PbsOrtbBid{{Bid: &openrtb2.Bid{Ext: json.RawMessage(`{"dsa": {}}`)}}, {Bid: &openrtb2.Bid{}}},
+			givenBids:          []*entities.PbsOrtbBid{{Bid: &openrtb2.Bid{Ext: json.RawMessage(`{"dsa": {"adrender":1}}`)}}, {Bid: &openrtb2.Bid{}}},
 			givenSeat:          "pubmatic",
 			expectedNumOfBids:  1,
 			expectedNonBids: &nonBids{
 				seatNonBidsMap: map[string][]openrtb_ext.NonBid{
 					"pubmatic": {
 						{
-							StatusCode: 305,
+							StatusCode: 300,
 							Ext: openrtb_ext.NonBidExt{
 								Prebid: openrtb_ext.ExtResponseNonBidPrebid{
 									Bid: openrtb_ext.NonBidObject{},
diff --git a/hooks/hookexecution/execution_test.go b/hooks/hookexecution/execution_test.go
index c7d17a15..33f652fa 100644
--- a/hooks/hookexecution/execution_test.go
+++ b/hooks/hookexecution/execution_test.go
@@ -176,7 +176,7 @@ func TestHandleModuleActivitiesProcessedAuctionRequestPayload(t *testing.T) {
 			//check input payload didn't change
 			origInPayloadData := test.inPayloadData
 			activityControl := privacy.NewActivityControl(test.privacyConfig)
-			account := &config.Account{Privacy: config.AccountPrivacy{IPv6Config: config.IPv6{testIPv6ScrubBytes}}}
+			account := &config.Account{Privacy: config.AccountPrivacy{IPv6Config: config.IPv6{AnonKeepBits: testIPv6ScrubBytes}}}
 			newPayload := handleModuleActivities(test.hookCode, activityControl, test.inPayloadData, account)
 			assert.Equal(t, test.expectedPayloadData.Request.BidRequest, newPayload.Request.BidRequest)
 			assert.Equal(t, origInPayloadData, test.inPayloadData)
diff --git a/openrtb_ext/request_wrapper_test.go b/openrtb_ext/request_wrapper_test.go
index f04a51a4..425229e5 100644
--- a/openrtb_ext/request_wrapper_test.go
+++ b/openrtb_ext/request_wrapper_test.go
@@ -2069,7 +2069,7 @@ func TestRebuildRegExt(t *testing.T) {
 		{
 			name:    "req_regs_nil_-_dirty_and_different_-_change",
 			request: openrtb2.BidRequest{},
-			regExt:  RegExt{dsa: &ExtRegsDSA{Required: 1}, dsaDirty: true, gdpr: ptrutil.ToPtr[int8](1), gdprDirty: true, usPrivacy: strA, usPrivacyDirty: true},
+			regExt:  RegExt{dsa: &ExtRegsDSA{Required: ptrutil.ToPtr[int8](1)}, dsaDirty: true, gdpr: ptrutil.ToPtr[int8](1), gdprDirty: true, usPrivacy: strA, usPrivacyDirty: true},
 			expectedRequest: openrtb2.BidRequest{
 				Regs: &openrtb2.Regs{
 					Ext: json.RawMessage(`{"dsa":{"dsarequired":1},"gdpr":1,"us_privacy":"a"}`),
@@ -2085,7 +2085,7 @@ func TestRebuildRegExt(t *testing.T) {
 		{
 			name:    "req_regs_ext_nil_-_dirty_and_different_-_change",
 			request: openrtb2.BidRequest{Regs: &openrtb2.Regs{}},
-			regExt:  RegExt{dsa: &ExtRegsDSA{Required: 1}, dsaDirty: true, gdpr: ptrutil.ToPtr[int8](1), gdprDirty: true, usPrivacy: strA, usPrivacyDirty: true},
+			regExt:  RegExt{dsa: &ExtRegsDSA{Required: ptrutil.ToPtr[int8](1)}, dsaDirty: true, gdpr: ptrutil.ToPtr[int8](1), gdprDirty: true, usPrivacy: strA, usPrivacyDirty: true},
 			expectedRequest: openrtb2.BidRequest{
 				Regs: &openrtb2.Regs{
 					Ext: json.RawMessage(`{"dsa":{"dsarequired":1},"gdpr":1,"us_privacy":"a"}`),
@@ -2101,13 +2101,13 @@ func TestRebuildRegExt(t *testing.T) {
 		{
 			name:            "req_regs_dsa_populated_-_dirty_and_different-_change",
 			request:         openrtb2.BidRequest{Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"dsa":{"dsarequired":1}}`)}},
-			regExt:          RegExt{dsa: &ExtRegsDSA{Required: 2}, dsaDirty: true},
+			regExt:          RegExt{dsa: &ExtRegsDSA{Required: ptrutil.ToPtr[int8](2)}, dsaDirty: true},
 			expectedRequest: openrtb2.BidRequest{Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"dsa":{"dsarequired":2}}`)}},
 		},
 		{
 			name:            "req_regs_dsa_populated_-_dirty_and_same_-_no_change",
 			request:         openrtb2.BidRequest{Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"dsa":{"dsarequired":1}}`)}},
-			regExt:          RegExt{dsa: &ExtRegsDSA{Required: 1}, dsaDirty: true},
+			regExt:          RegExt{dsa: &ExtRegsDSA{Required: ptrutil.ToPtr[int8](1)}, dsaDirty: true},
 			expectedRequest: openrtb2.BidRequest{Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"dsa":{"dsarequired":1}}`)}},
 		},
 		{
@@ -2215,7 +2215,7 @@ func TestRegExtUnmarshal(t *testing.T) {
 			regExt:  &RegExt{},
 			extJson: json.RawMessage(`{"dsa":{"dsarequired":1}}`),
 			expectDSA: &ExtRegsDSA{
-				Required: 1,
+				Required: ptrutil.ToPtr[int8](1),
 			},
 			expectError: false,
 		},
@@ -2224,7 +2224,7 @@ func TestRegExtUnmarshal(t *testing.T) {
 			regExt:  &RegExt{},
 			extJson: json.RawMessage(`{"dsa":{"dsarequired":""}}`),
 			expectDSA: &ExtRegsDSA{
-				Required: 0,
+				Required: ptrutil.ToPtr[int8](0),
 			},
 			expectError: true,
 		},
@@ -2299,7 +2299,7 @@ func TestRegExtGetDSASetDSA(t *testing.T) {
 	assert.False(t, regExt.Dirty())
 
 	dsa := &ExtRegsDSA{
-		Required: 2,
+		Required: ptrutil.ToPtr[int8](2),
 	}
 	regExt.SetDSA(dsa)
 	assert.True(t, regExt.Dirty())
diff --git a/router/aspects/request_timeout_handler_test.go b/router/aspects/request_timeout_handler_test.go
index 4ece1420..f77d48aa 100644
--- a/router/aspects/request_timeout_handler_test.go
+++ b/router/aspects/request_timeout_handler_test.go
@@ -101,7 +101,7 @@ func ExecuteAspectRequest(t *testing.T, timeInQueue string, reqTimeout string, s
 		req.Header.Set(reqTimeoutHeaderName, reqTimeout)
 	}
 
-	customHeaders := config.RequestTimeoutHeaders{reqTimeInQueueHeaderName, reqTimeoutHeaderName}
+	customHeaders := config.RequestTimeoutHeaders{RequestTimeInQueue: reqTimeInQueueHeaderName, RequestTimeoutInQueue: reqTimeoutHeaderName}
 
 	metrics := &metrics.MetricsEngineMock{}
 
diff --git a/router/bidder_params_tests/appnexus.json b/router/bidder_params_tests/appnexus.json
new file mode 100644
index 00000000..11dedd41
--- /dev/null
+++ b/router/bidder_params_tests/appnexus.json
@@ -0,0 +1,27 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "Sample schema",
+    "description": "A sample schema to test the bidder/params endpoint",
+    "type": "object",
+    "properties": {
+        "integer_param": {
+            "type": "integer",
+            "minimum": 1,
+            "description": "A customer id"
+        },
+        "string_param_1": {
+            "type": "string",
+            "minLength": 1,
+            "description": "Text with blanks in between"
+        },
+        "string_param_2": {
+            "type": "string",
+            "minLength": 1,
+            "description": "Text_with_no_blanks_in_between"
+        }
+    },
+    "required": [
+        "integer_param",
+        "string_param_2"
+    ]
+}
diff --git a/router/router_test.go b/router/router_test.go
index cc2f077e..866a8440 100644
--- a/router/router_test.go
+++ b/router/router_test.go
@@ -7,6 +7,7 @@ import (
 	"os"
 	"testing"
 
+	jsoniter "github.com/json-iterator/go"
 	"github.com/prebid/prebid-server/v2/config"
 	"github.com/prebid/prebid-server/v2/openrtb_ext"
 	"github.com/prebid/prebid-server/v2/util/jsonutil"
@@ -18,6 +19,11 @@ const adapterDirectory = "../adapters"
 
 type testValidator struct{}
 
+func TestMain(m *testing.M) {
+	jsoniter.RegisterExtension(&jsonutil.RawMessageExtension{})
+	os.Exit(m.Run())
+}
+
 func (validator *testValidator) Validate(name openrtb_ext.BidderName, ext json.RawMessage) error {
 	return nil
 }
@@ -275,3 +281,23 @@ func TestValidateDefaultAliases(t *testing.T) {
 		}
 	}
 }
+
+func TestBidderParamsCompactedOutput(t *testing.T) {
+	expectedFormattedResponse := `{"appnexus":{"$schema":"http://json-schema.org/draft-04/schema#","title":"Sample schema","description":"A sample schema to test the bidder/params endpoint","type":"object","properties":{"integer_param":{"type":"integer","minimum":1,"description":"A customer id"},"string_param_1":{"type":"string","minLength":1,"description":"Text with blanks in between"},"string_param_2":{"type":"string","minLength":1,"description":"Text_with_no_blanks_in_between"}},"required":["integer_param","string_param_2"]}}`
+
+	// Setup
+	inSchemaDirectory := "bidder_params_tests"
+	paramsValidator, err := openrtb_ext.NewBidderParamsValidator(inSchemaDirectory)
+	assert.NoError(t, err, "Error initialing validator")
+
+	handler := newJsonDirectoryServer(inSchemaDirectory, paramsValidator, nil, nil)
+	recorder := httptest.NewRecorder()
+	request, err := http.NewRequest("GET", "/bidder/params", nil)
+	assert.NoError(t, err, "Error creating request")
+
+	// Run
+	handler(recorder, request, nil)
+
+	// Assertions
+	assert.Equal(t, expectedFormattedResponse, recorder.Body.String())
+}
diff --git a/stored_requests/backends/file_fetcher/fetcher_test.go b/stored_requests/backends/file_fetcher/fetcher_test.go
index 0155c1aa..b4a73870 100644
--- a/stored_requests/backends/file_fetcher/fetcher_test.go
+++ b/stored_requests/backends/file_fetcher/fetcher_test.go
@@ -36,7 +36,7 @@ func TestAccountFetcher(t *testing.T) {
 	_, errs = fetcher.FetchAccount(context.Background(), json.RawMessage(`{"events_enabled":true}`), "nonexistent")
 	assertErrorCount(t, 1, errs)
 	assert.Error(t, errs[0])
-	assert.Equal(t, stored_requests.NotFoundError{"nonexistent", "Account"}, errs[0])
+	assert.Equal(t, stored_requests.NotFoundError{ID: "nonexistent", DataType: "Account"}, errs[0])
 
 	_, errs = fetcher.FetchAccount(context.Background(), json.RawMessage(`{"events_enabled"}`), "valid")
 	assertErrorCount(t, 1, errs)
diff --git a/util/jsonutil/jsonutil_test.go b/util/jsonutil/jsonutil_test.go
index 09fb6727..96632d62 100644
--- a/util/jsonutil/jsonutil_test.go
+++ b/util/jsonutil/jsonutil_test.go
@@ -1,10 +1,15 @@
 package jsonutil
 
 import (
+	"bytes"
+	"encoding/json"
 	"errors"
 	"strings"
 	"testing"
+	"unsafe"
 
+	jsoniter "github.com/json-iterator/go"
+	"github.com/modern-go/reflect2"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -240,3 +245,80 @@ func TestTryExtractErrorMessage(t *testing.T) {
 		})
 	}
 }
+
+func TestCreateEncoder(t *testing.T) {
+	testCases := []struct {
+		desc               string
+		inType             reflect2.Type
+		expectedValEncoder jsoniter.ValEncoder
+	}{
+		{
+			desc:               "With_extension",
+			inType:             reflect2.TypeOfPtr((*jsoniter.Any)(nil)).Elem(),
+			expectedValEncoder: nil,
+		},
+		{
+			desc:               "No_extension",
+			inType:             reflect2.TypeOfPtr(&json.RawMessage{}).Elem(),
+			expectedValEncoder: &rawMessageCodec{},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.desc, func(t *testing.T) {
+			extension := &RawMessageExtension{}
+			encoder := extension.CreateEncoder(tc.inType)
+			assert.IsType(t, encoder, tc.expectedValEncoder)
+		})
+	}
+}
+
+func TestEncode(t *testing.T) {
+	jsonBlob := json.RawMessage(`{
+  "properties": {
+    "string": "Blanks spaces in between words to not be removed if compacted",
+    "integer": 5,
+    "string_array": [
+      "string array elem one",
+      "string array elem two"
+    ]
+  }
+}`)
+
+	t.Run(
+		"Nil_pointer",
+		func(t *testing.T) {
+			// set test
+			encoder := &rawMessageCodec{}
+			output := bytes.NewBuffer([]byte{})
+			stream := jsoniter.NewStream(jsonConfigValidationOn, output, len(jsonBlob))
+
+			// run
+			encoder.Encode(nil, stream)
+
+			// assertions
+			assert.Equal(t, "", output.String())
+			assert.Equal(t, true, encoder.IsEmpty(nil))
+		},
+	)
+	t.Run(
+		"json.RawMessage_compact_JSON",
+		func(t *testing.T) {
+			// set test
+			encoder := &rawMessageCodec{}
+			output := bytes.NewBuffer([]byte{})
+			stream := jsoniter.NewStream(jsonConfigValidationOn, output, len(jsonBlob))
+
+			// run
+			encoder.Encode(unsafe.Pointer(&jsonBlob), stream)
+
+			// assertions
+			assert.Equal(
+				t,
+				`{"properties":{"string":"Blanks spaces in between words to not be removed if compacted","integer":5,"string_array":["string array elem one","string array elem two"]}}`,
+				output.String(),
+			)
+			assert.Equal(t, false, encoder.IsEmpty(unsafe.Pointer(&jsonBlob)))
+		},
+	)
+}
diff --git a/util/stringutil/stringutil_test.go b/util/stringutil/stringutil_test.go
index 94988ee4..a7aa0010 100644
--- a/util/stringutil/stringutil_test.go
+++ b/util/stringutil/stringutil_test.go
@@ -30,7 +30,7 @@ func TestStrToInt8Slice(t *testing.T) {
 			in:   "malformed",
 			expected: testOutput{
 				arr: nil,
-				err: &strconv.NumError{"ParseInt", "malformed", strconv.ErrSyntax},
+				err: &strconv.NumError{Func: "ParseInt", Num: "malformed", Err: strconv.ErrSyntax},
 			},
 		},
 		{
@@ -38,7 +38,7 @@ func TestStrToInt8Slice(t *testing.T) {
 			in:   "malformed,2,malformed",
 			expected: testOutput{
 				arr: nil,
-				err: &strconv.NumError{"ParseInt", "malformed", strconv.ErrSyntax},
+				err: &strconv.NumError{Func: "ParseInt", Num: "malformed", Err: strconv.ErrSyntax},
 			},
 		},
 		{
@@ -46,7 +46,7 @@ func TestStrToInt8Slice(t *testing.T) {
 			in:   "128",
 			expected: testOutput{
 				arr: nil,
-				err: &strconv.NumError{"ParseInt", "128", strconv.ErrRange},
+				err: &strconv.NumError{Func: "ParseInt", Num: "128", Err: strconv.ErrRange},
 			},
 		},
 		{