Repository: prebid/prebid-server
Pull request #3355 (2023-12-15 01:07:59)

AdView: support multi imps request & formattype tag for bid response
1. support multi imps from request.
2. add formattype tag for bid response, use this to handle resp bid-type.

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, 6401e820ebc7b18379296678f6e5a0cb396ec993 
#### adview 
Refer [here](https://htmlpreview.github.io/?https://github.com/prebid/prebid-server/coverage-preview/.github/preview/7216591723_1702602523/adview.html) for heat map coverage report 
``` 
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:27:	Builder			100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:39:	MakeRequests		74.4%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:114:	MakeBids		90.9%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:162:	buildEndpointURL	100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:167:	getMediaTypeForImp	0.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:182:	getMediaTypeForBid	72.7%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:202:	getBidType		87.5%
total:									(statements)		74.0%

 ``` 

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, b6988f168bbd86fa1f612bd49761e25e7e1082df 
#### adview 
Refer [here](https://htmlpreview.github.io/?https://github.com/prebid/prebid-server/coverage-preview/.github/preview/7523974812_1705289405/adview.html) for heat map coverage report 
``` 
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:27:	Builder			100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:39:	MakeRequests		74.4%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:114:	MakeBids		90.9%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:162:	buildEndpointURL	100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:167:	getMediaTypeForImp	0.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:182:	getMediaTypeForBid	72.7%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:202:	getBidType		87.5%
total:									(statements)		74.0%

 ``` 

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, f2697d81bd30c8c45a18a2a38efc5f742641cbe0 
#### adview 
Refer [here](https://htmlpreview.github.io/?https://github.com/prebid/prebid-server/coverage-preview/.github/preview/7524013546_1705289767/adview.html) for heat map coverage report 
``` 
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:27:	Builder			100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:39:	MakeRequests		74.4%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:114:	MakeBids		90.9%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:161:	buildEndpointURL	100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:166:	getMediaTypeForImp	0.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:181:	getMediaTypeForBid	81.8%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:201:	getBidType		87.5%
total:									(statements)		75.0%

 ``` 

AdviewOpen: Hi, I committed the changes, pls check it again. 
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, 41dc7319fde0be57cd7528487979c46614c561d3 
#### adview 
Refer [here](https://htmlpreview.github.io/?https://github.com/prebid/prebid-server/coverage-preview/.github/preview/7607834476_1705908705/adview.html) for heat map coverage report 
``` 
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:27:	Builder			100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:39:	MakeRequests		74.4%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:114:	MakeBids		90.9%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:161:	buildEndpointURL	100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:166:	getMediaTypeForImp	0.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:181:	getMediaTypeForBid	81.8%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:201:	getBidType		87.5%
total:									(statements)		75.0%

 ``` 

AdviewOpen: new changes for default cases error process in getBidType. pls check it & thx.
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, 188fcfcc3bf1992200748863c845470fead0e66c 
#### adview 
Refer [here](https://htmlpreview.github.io/?https://github.com/prebid/prebid-server/coverage-preview/.github/preview/7650491783_1706162322/adview.html) for heat map coverage report 
``` 
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:27:	Builder			100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:39:	MakeRequests		74.4%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:114:	MakeBids		90.9%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:161:	buildEndpointURL	100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:166:	getMediaTypeForImp	0.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:181:	getMediaTypeForBid	81.8%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:201:	getBidType		87.5%
total:									(statements)		75.0%

 ``` 

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, ed5fec3da091534b0568b10fe97205fa53a2a687 
#### adview 
Refer [here](https://htmlpreview.github.io/?https://github.com/prebid/prebid-server/coverage-preview/.github/preview/7650504189_1706162461/adview.html) for heat map coverage report 
``` 
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:27:	Builder			100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:39:	MakeRequests		74.4%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:114:	MakeBids		90.9%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:161:	buildEndpointURL	100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:166:	getMediaTypeForImp	0.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:181:	getMediaTypeForBid	66.7%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:197:	getBidType		0.0%
total:									(statements)		65.9%

 ``` 

AdviewOpen: Based on reviews, and I got the confirmation that adview server already support mtype in response, after test, i change getMediaTypeForBid(), pls review it. 
Thanks.
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, 1d0d0f9b4183a498f4d6f83db847955386a277c6 
#### adview 
Refer [here](https://htmlpreview.github.io/?https://github.com/prebid/prebid-server/coverage-preview/.github/preview/7690229872_1706494172/adview.html) for heat map coverage report 
``` 
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:27:	Builder			100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:39:	MakeRequests		74.4%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:114:	MakeBids		90.9%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:161:	buildEndpointURL	100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:166:	getMediaTypeForImp	0.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:181:	getMediaTypeForBid	66.7%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:197:	getBidType		0.0%
total:									(statements)		65.9%

 ``` 

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, 21372b8a26693ffb0e1c14d7abaedc34e6f20efc 
#### adview 
Refer [here](https://htmlpreview.github.io/?https://github.com/prebid/prebid-server/coverage-preview/.github/preview/7690333829_1706494958/adview.html) for heat map coverage report 
``` 
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:27:	Builder			100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:39:	MakeRequests		74.4%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:114:	MakeBids		90.9%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:161:	buildEndpointURL	100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:166:	getMediaTypeForBid	66.7%
total:									(statements)		81.1%

 ``` 

AdviewOpen: Hi, I add mtype in error output & removed no used codes. 
pls check it and thx.
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, 2711af57bc85219167c6808e5c41b8559c89dda7 
#### adview 
Refer [here](https://htmlpreview.github.io/?https://github.com/prebid/prebid-server/coverage-preview/.github/preview/7720190494_1706666806/adview.html) for heat map coverage report 
``` 
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:27:	Builder			100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:39:	MakeRequests		74.4%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:114:	MakeBids		90.9%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:161:	buildEndpointURL	100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:166:	getMediaTypeForBid	66.7%
total:									(statements)		81.1%

 ``` 

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, 57af4f6365798ba58e18d0b76b0b3391280f2f22 
#### adview 
Refer [here](https://htmlpreview.github.io/?https://github.com/prebid/prebid-server/coverage-preview/.github/preview/7720259516_1706667277/adview.html) for heat map coverage report 
``` 
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:27:	Builder			100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:39:	MakeRequests		74.4%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:114:	MakeBids		90.9%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:161:	buildEndpointURL	100.0%
github.com/prebid/prebid-server/v2/adapters/adview/adview.go:166:	getMediaTypeForBid	80.0%
total:									(statements)		82.2%

 ``` 

AdviewOpen: Remove audio type cause not supporting now. thx.

Patch:
diff --git a/adapters/adview/adview.go b/adapters/adview/adview.go
index 88a236dc..d880cc49 100644
--- a/adapters/adview/adview.go
+++ b/adapters/adview/adview.go
@@ -19,6 +19,10 @@ type adapter struct {
 	endpoint *template.Template
 }
 
+type adviewBidExt struct {
+	BidType int `json:"formattype,omitempty"`
+}
+
 // Builder builds a new instance of the adview adapter for the given bidder with the given config.
 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
 	endpointTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint)
@@ -33,63 +37,78 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co
 }
 
 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
-	var bidderExt adapters.ExtImpBidder
-	imp := &request.Imp[0]
-	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
-		return nil, []error{&errortypes.BadInput{
-			Message: fmt.Sprintf("invalid imp.ext, %s", err.Error()),
-		}}
-	}
-	//use adview
-	var advImpExt openrtb_ext.ExtImpAdView
-	if err := json.Unmarshal(bidderExt.Bidder, &advImpExt); err != nil {
-		return nil, []error{&errortypes.BadInput{
-			Message: fmt.Sprintf("invalid bidderExt.Bidder, %s", err.Error()),
-		}}
-	}
 
-	imp.TagID = advImpExt.MasterTagID //tagid means posid
-	//for adview bid request
-	if imp.Banner != nil {
-		if len(imp.Banner.Format) != 0 {
-			bannerCopy := *imp.Banner
-			bannerCopy.H = &imp.Banner.Format[0].H
-			bannerCopy.W = &imp.Banner.Format[0].W
-			imp.Banner = &bannerCopy
+	var requests []*adapters.RequestData
+	var errors []error
+
+	//must copy the original request.
+	requestCopy := *request
+	for _, imp := range request.Imp {
+		var bidderExt adapters.ExtImpBidder
+		if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
+			errors = append(errors, &errortypes.BadInput{
+				Message: fmt.Sprintf("invalid imp.ext, %s", err.Error()),
+			})
+			continue
+		}
+		//use adview
+		var advImpExt openrtb_ext.ExtImpAdView
+		if err := json.Unmarshal(bidderExt.Bidder, &advImpExt); err != nil {
+			errors = append(errors, &errortypes.BadInput{
+				Message: fmt.Sprintf("invalid bidderExt.Bidder, %s", err.Error()),
+			})
+			continue
 		}
-	}
 
-	// Check if imp comes with bid floor amount defined in a foreign currency
-	if imp.BidFloor > 0 && imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != "USD" {
-		// Convert to US dollars
-		convertedValue, err := requestInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD")
-		if err != nil {
-			return nil, []error{err}
+		imp.TagID = advImpExt.MasterTagID //tagid means posid
+		//for adview bid request
+		if imp.Banner != nil {
+			if len(imp.Banner.Format) != 0 {
+				bannerCopy := *imp.Banner
+				bannerCopy.H = &imp.Banner.Format[0].H
+				bannerCopy.W = &imp.Banner.Format[0].W
+				imp.Banner = &bannerCopy
+			}
 		}
-		// Update after conversion. All imp elements inside request.Imp are shallow copies
-		// therefore, their non-pointer values are not shared memory and are safe to modify.
-		imp.BidFloorCur = "USD"
-		imp.BidFloor = convertedValue
-	}
 
-	// Set the CUR of bid to USD after converting all floors
-	request.Cur = []string{"USD"}
+		// Check if imp comes with bid floor amount defined in a foreign currency
+		if imp.BidFloor > 0 && imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != "USD" {
+			// Convert to US dollars
+			convertedValue, err := requestInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD")
+			if err != nil {
+				errors = append(errors, err)
+				continue
+			}
+			// Update after conversion. All imp elements inside request.Imp are shallow copies
+			// therefore, their non-pointer values are not shared memory and are safe to modify.
+			imp.BidFloorCur = "USD"
+			imp.BidFloor = convertedValue
+		}
 
-	url, err := a.buildEndpointURL(&advImpExt)
-	if err != nil {
-		return nil, []error{err}
-	}
+		// Set the CUR of bid to USD after converting all floors
+		requestCopy.Cur = []string{"USD"}
+		requestCopy.Imp = []openrtb2.Imp{imp}
 
-	reqJSON, err := json.Marshal(request)
-	if err != nil {
-		return nil, []error{err}
-	}
+		url, err := a.buildEndpointURL(&advImpExt)
+		if err != nil {
+			errors = append(errors, err)
+			continue
+		}
+
+		reqJSON, err := json.Marshal(requestCopy) //request
+		if err != nil {
+			errors = append(errors, err)
+			continue
+		}
 
-	return []*adapters.RequestData{{
-		Method: http.MethodPost,
-		Body:   reqJSON,
-		Uri:    url,
-	}}, nil
+		requestData := &adapters.RequestData{
+			Method: http.MethodPost,
+			Uri:    url,
+			Body:   reqJSON,
+		}
+		requests = append(requests, requestData)
+	}
+	return requests, errors
 }
 
 func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
@@ -117,12 +136,13 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R
 	}
 
 	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp))
-	bidResponse.Currency = "USD" //we just support USD for resp
+	//we just support USD for resp
+	bidResponse.Currency = "USD"
 
 	var errors []error
 	for _, seatBid := range response.SeatBid {
 		for i, bid := range seatBid.Bid {
-			bidType, err := getMediaTypeForImp(bid.ImpID, request.Imp)
+			bidType, err := getMediaTypeForBid(bid)
 			if err != nil {
 				errors = append(errors, err)
 				continue
@@ -143,17 +163,15 @@ func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtImpAdView) (string, er
 	return macros.ResolveMacros(a.endpoint, endpointParams)
 }
 
-func getMediaTypeForImp(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {
-	mediaType := openrtb_ext.BidTypeBanner
-	for _, imp := range imps {
-		if imp.ID == impID {
-			if imp.Video != nil {
-				mediaType = openrtb_ext.BidTypeVideo
-			} else if imp.Native != nil {
-				mediaType = openrtb_ext.BidTypeNative
-			}
-			return mediaType, nil
-		}
+func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
+	switch bid.MType {
+	case openrtb2.MarkupBanner:
+		return openrtb_ext.BidTypeBanner, nil
+	case openrtb2.MarkupVideo:
+		return openrtb_ext.BidTypeVideo, nil
+	case openrtb2.MarkupNative:
+		return openrtb_ext.BidTypeNative, nil
+	default:
+		return "", fmt.Errorf("Unable to fetch mediaType in impID: %s, mType: %d", bid.ImpID, bid.MType)
 	}
-	return mediaType, nil
 }
diff --git a/adapters/boldwin/boldwin.go b/adapters/boldwin/boldwin.go
index 1754423f..96a9aaec 100644
--- a/adapters/boldwin/boldwin.go
+++ b/adapters/boldwin/boldwin.go
@@ -118,7 +118,7 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R
 	bidResponse.Currency = response.Cur
 	for _, seatBid := range response.SeatBid {
 		for i := range seatBid.Bid {
-			bidType, err := getMediaTypeForImp(seatBid.Bid[i].ImpID, request.Imp)
+			bidType, err := getBidMediaType(&seatBid.Bid[i])
 			if err != nil {
 				return nil, []error{err}
 			}
@@ -133,22 +133,15 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R
 	return bidResponse, nil
 }
 
-func getMediaTypeForImp(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {
-	for _, imp := range imps {
-		if imp.ID == impID {
-			if imp.Banner != nil {
-				return openrtb_ext.BidTypeBanner, nil
-			}
-			if imp.Video != nil {
-				return openrtb_ext.BidTypeVideo, nil
-			}
-			if imp.Native != nil {
-				return openrtb_ext.BidTypeNative, nil
-			}
-		}
-	}
-
-	return "", &errortypes.BadInput{
-		Message: fmt.Sprintf("Failed to find impression \"%s\"", impID),
+func getBidMediaType(bid *openrtb2.Bid) (openrtb_ext.BidType, error) {
+	switch bid.MType {
+	case openrtb2.MarkupBanner:
+		return openrtb_ext.BidTypeBanner, nil
+	case openrtb2.MarkupVideo:
+		return openrtb_ext.BidTypeVideo, nil
+	case openrtb2.MarkupNative:
+		return openrtb_ext.BidTypeNative, nil
+	default:
+		return "", fmt.Errorf("Unable to fetch mediaType in multi-format: %s", bid.ImpID)
 	}
 }
diff --git a/exchange/exchange.go b/exchange/exchange.go
index 349611e8..7c604886 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -494,7 +494,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog
 	e.bidValidationEnforcement.SetBannerCreativeMaxSize(r.Account.Validations)
 
 	// Build the response
-	bidResponse := e.buildBidResponse(ctx, liveAdapters, adapterBids, r.BidRequestWrapper.BidRequest, adapterExtra, auc, bidResponseExt, cacheInstructions.returnCreative, r.ImpExtInfoMap, r.PubID, errs)
+	bidResponse := e.buildBidResponse(ctx, liveAdapters, adapterBids, r.BidRequestWrapper.BidRequest, adapterExtra, auc, bidResponseExt, cacheInstructions.returnCreative, r.ImpExtInfoMap, r.PubID, errs, &seatNonBids)
 	bidResponse = adservertargeting.Apply(r.BidRequestWrapper, r.ResolvedBidRequest, bidResponse, r.QueryParams, bidResponseExt, r.Account.TruncateTargetAttribute)
 
 	bidResponse.Ext, err = encodeBidResponseExt(bidResponseExt)
@@ -890,7 +890,7 @@ func errsToBidderWarnings(errs []error) []openrtb_ext.ExtBidderMessage {
 }
 
 // This piece takes all the bids supplied by the adapters and crafts an openRTB response to send back to the requester
-func (e *exchange) buildBidResponse(ctx context.Context, liveAdapters []openrtb_ext.BidderName, adapterSeatBids map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid, bidRequest *openrtb2.BidRequest, adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra, auc *auction, bidResponseExt *openrtb_ext.ExtBidResponse, returnCreative bool, impExtInfoMap map[string]ImpExtInfo, pubID string, errList []error) *openrtb2.BidResponse {
+func (e *exchange) buildBidResponse(ctx context.Context, liveAdapters []openrtb_ext.BidderName, adapterSeatBids map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid, bidRequest *openrtb2.BidRequest, adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra, auc *auction, bidResponseExt *openrtb_ext.ExtBidResponse, returnCreative bool, impExtInfoMap map[string]ImpExtInfo, pubID string, errList []error, seatNonBids *nonBids) *openrtb2.BidResponse {
 	bidResponse := new(openrtb2.BidResponse)
 
 	bidResponse.ID = bidRequest.ID
@@ -905,7 +905,7 @@ func (e *exchange) buildBidResponse(ctx context.Context, liveAdapters []openrtb_
 	for a, adapterSeatBids := range adapterSeatBids {
 		//while processing every single bib, do we need to handle categories here?
 		if adapterSeatBids != nil && len(adapterSeatBids.Bids) > 0 {
-			sb := e.makeSeatBid(adapterSeatBids, a, adapterExtra, auc, returnCreative, impExtInfoMap, bidResponseExt, pubID)
+			sb := e.makeSeatBid(adapterSeatBids, a, adapterExtra, auc, returnCreative, impExtInfoMap, bidResponseExt, pubID, seatNonBids)
 			seatBids = append(seatBids, *sb)
 			bidResponse.Cur = adapterSeatBids.Currency
 		}
@@ -1224,14 +1224,14 @@ func (e *exchange) makeExtBidResponse(adapterBids map[openrtb_ext.BidderName]*en
 
 // Return an openrtb seatBid for a bidder
 // buildBidResponse is responsible for ensuring nil bid seatbids are not included
-func (e *exchange) makeSeatBid(adapterBid *entities.PbsOrtbSeatBid, adapter openrtb_ext.BidderName, adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra, auc *auction, returnCreative bool, impExtInfoMap map[string]ImpExtInfo, bidResponseExt *openrtb_ext.ExtBidResponse, pubID string) *openrtb2.SeatBid {
+func (e *exchange) makeSeatBid(adapterBid *entities.PbsOrtbSeatBid, adapter openrtb_ext.BidderName, adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra, auc *auction, returnCreative bool, impExtInfoMap map[string]ImpExtInfo, bidResponseExt *openrtb_ext.ExtBidResponse, pubID string, seatNonBids *nonBids) *openrtb2.SeatBid {
 	seatBid := &openrtb2.SeatBid{
 		Seat:  adapter.String(),
 		Group: 0, // Prebid cannot support roadblocking
 	}
 
 	var errList []error
-	seatBid.Bid, errList = e.makeBid(adapterBid.Bids, auc, returnCreative, impExtInfoMap, bidResponseExt, adapter, pubID)
+	seatBid.Bid, errList = e.makeBid(adapterBid.Bids, auc, returnCreative, impExtInfoMap, bidResponseExt, adapter, pubID, seatNonBids)
 	if len(errList) > 0 {
 		adapterExtra[adapter].Errors = append(adapterExtra[adapter].Errors, errsToBidderErrors(errList)...)
 	}
@@ -1239,13 +1239,14 @@ func (e *exchange) makeSeatBid(adapterBid *entities.PbsOrtbSeatBid, adapter open
 	return seatBid
 }
 
-func (e *exchange) makeBid(bids []*entities.PbsOrtbBid, auc *auction, returnCreative bool, impExtInfoMap map[string]ImpExtInfo, bidResponseExt *openrtb_ext.ExtBidResponse, adapter openrtb_ext.BidderName, pubID string) ([]openrtb2.Bid, []error) {
+func (e *exchange) makeBid(bids []*entities.PbsOrtbBid, auc *auction, returnCreative bool, impExtInfoMap map[string]ImpExtInfo, bidResponseExt *openrtb_ext.ExtBidResponse, adapter openrtb_ext.BidderName, pubID string, seatNonBids *nonBids) ([]openrtb2.Bid, []error) {
 	result := make([]openrtb2.Bid, 0, len(bids))
 	errs := make([]error, 0, 1)
 
 	for _, bid := range bids {
 		if e.bidValidationEnforcement.BannerCreativeMaxSize == config.ValidationEnforce && bid.BidType == openrtb_ext.BidTypeBanner {
 			if !e.validateBannerCreativeSize(bid, bidResponseExt, adapter, pubID, e.bidValidationEnforcement.BannerCreativeMaxSize) {
+				seatNonBids.addBid(bid, int(ResponseRejectedCreativeSizeNotAllowed), adapter.String())
 				continue // Don't add bid to result
 			}
 		} else if e.bidValidationEnforcement.BannerCreativeMaxSize == config.ValidationWarn && bid.BidType == openrtb_ext.BidTypeBanner {
@@ -1254,6 +1255,7 @@ func (e *exchange) makeBid(bids []*entities.PbsOrtbBid, auc *auction, returnCrea
 		if _, ok := impExtInfoMap[bid.Bid.ImpID]; ok {
 			if e.bidValidationEnforcement.SecureMarkup == config.ValidationEnforce && (bid.BidType == openrtb_ext.BidTypeBanner || bid.BidType == openrtb_ext.BidTypeVideo) {
 				if !e.validateBidAdM(bid, bidResponseExt, adapter, pubID, e.bidValidationEnforcement.SecureMarkup) {
+					seatNonBids.addBid(bid, int(ResponseRejectedCreativeNotSecure), adapter.String())
 					continue // Don't add bid to result
 				}
 			} else if e.bidValidationEnforcement.SecureMarkup == config.ValidationWarn && (bid.BidType == openrtb_ext.BidTypeBanner || bid.BidType == openrtb_ext.BidTypeVideo) {
diff --git a/exchange/non_bid_reason.go b/exchange/non_bid_reason.go
index 9a6f1f6b..4d817a67 100644
--- a/exchange/non_bid_reason.go
+++ b/exchange/non_bid_reason.go
@@ -8,6 +8,8 @@ type NonBidReason int
 const (
 	NoBidUnknownError                      NonBidReason = 0   // No Bid - General
 	ResponseRejectedCategoryMappingInvalid NonBidReason = 303 // Response Rejected - Category Mapping Invalid
+	ResponseRejectedCreativeSizeNotAllowed NonBidReason = 351 // Response Rejected - Invalid Creative (Size Not Allowed)
+	ResponseRejectedCreativeNotSecure      NonBidReason = 352 // Response Rejected - Invalid Creative (Not Secure)
 )
 
 // Ptr returns pointer to own value.


Test patch:
diff --git a/adapters/adview/adviewtest/exemplary/banner-app-format.json b/adapters/adview/adviewtest/exemplary/banner-app-format.json
index 0ab49515..f35f9db7 100644
--- a/adapters/adview/adviewtest/exemplary/banner-app-format.json
+++ b/adapters/adview/adviewtest/exemplary/banner-app-format.json
@@ -115,7 +115,11 @@
                   ],
                   "crid": "20",
                   "w": 320,
-                  "h": 50
+                  "h": 50,
+                  "mtype": 1,
+                  "ext": {
+                    "formattype": 0
+                  }
                 }
               ],
               "type": "banner",
@@ -148,7 +152,11 @@
             ],
             "crid": "20",
             "w": 320,
-            "h": 50
+            "h": 50,
+            "mtype": 1,
+            "ext": {
+              "formattype": 0
+            }
           },
           "type": "banner"
         }
diff --git a/adapters/adview/adviewtest/exemplary/banner-app-resp-no-formattype.json b/adapters/adview/adviewtest/exemplary/banner-app-resp-no-formattype.json
new file mode 100644
index 00000000..e3b92913
--- /dev/null
+++ b/adapters/adview/adviewtest/exemplary/banner-app-resp-no-formattype.json
@@ -0,0 +1,150 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "ifa":"00000000-0000-0000-0000-000000000000",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "app": {
+      "publisher": {
+        "id": "123456789"
+      },
+      "cat": [
+        "IAB22-1"
+      ],
+      "bundle": "com.app.awesome",
+      "name": "Awesome App",
+      "domain": "awesomeapp.com",
+      "id": "123456789"
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "banner": {
+          "w": 320,
+          "h": 50
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "posid00001",
+            "accountId": "accountid01"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://bid.adview.com/agent/thirdAdxService/accountid01",
+        "body": {
+          "id": "some-request-id",
+          "cur": ["USD"],
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "ifa":"00000000-0000-0000-0000-000000000000",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "posid00001",
+              "ext": {
+                 "bidder": {
+                   "placementId": "posid00001",
+                   "accountId": "accountid01"
+                 }
+              }
+            }
+          ],
+          "app": {
+            "id": "123456789",
+            "name": "Awesome App",
+            "bundle": "com.app.awesome",
+            "domain": "awesomeapp.com",
+            "cat": [
+              "IAB22-1"
+            ],
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "some-impression-id",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50,
+                  "mtype": 1
+                }
+              ],
+              "type": "banner",
+              "seat": "adview"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "adview": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 320,
+            "h": 50,
+            "mtype": 1
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adview/adviewtest/exemplary/banner-app.json b/adapters/adview/adviewtest/exemplary/banner-app.json
index 6aad1e8d..2c740504 100644
--- a/adapters/adview/adviewtest/exemplary/banner-app.json
+++ b/adapters/adview/adviewtest/exemplary/banner-app.json
@@ -105,7 +105,11 @@
                   ],
                   "crid": "20",
                   "w": 320,
-                  "h": 50
+                  "h": 50,
+                  "mtype": 1,
+                  "ext": {
+                    "formattype": 0
+                  }
                 }
               ],
               "type": "banner",
@@ -138,7 +142,11 @@
             ],
             "crid": "20",
             "w": 320,
-            "h": 50
+            "h": 50,
+            "mtype": 1,
+            "ext": {
+              "formattype": 0
+            }
           },
           "type": "banner"
         }
diff --git a/adapters/adview/adviewtest/exemplary/native-app.json b/adapters/adview/adviewtest/exemplary/native-app.json
index 804494e5..aea0f58d 100644
--- a/adapters/adview/adviewtest/exemplary/native-app.json
+++ b/adapters/adview/adviewtest/exemplary/native-app.json
@@ -103,7 +103,11 @@
                   "adomain": [
                     "awesome.com"
                   ],
-                  "crid": "20"
+                  "crid": "20",
+                  "mtype": 4,
+                  "ext": {
+                    "formattype": 2
+                  }
                 }
               ],
               "type": "native",
@@ -132,9 +136,13 @@
             "price": 3.5,
             "adm": "awesome-markup",
             "crid": "20",
+            "mtype": 4,
             "adomain": [
               "awesome.com"
-            ]
+            ],
+            "ext": {
+              "formattype": 2
+            }
           },
           "type": "native"
         }
diff --git a/adapters/adview/adviewtest/exemplary/video-app.json b/adapters/adview/adviewtest/exemplary/video-app.json
index 57c9b855..8697fc0f 100644
--- a/adapters/adview/adviewtest/exemplary/video-app.json
+++ b/adapters/adview/adviewtest/exemplary/video-app.json
@@ -115,7 +115,11 @@
                   ],
                   "crid": "20",
                   "w": 1280,
-                  "h": 720
+                  "h": 720,
+                  "mtype": 2,
+                  "ext": {
+                    "formattype": 1
+                  }
                 }
               ],
               "seat": "adview"
@@ -147,7 +151,11 @@
               "awesome.com"
             ],
             "w": 1280,
-            "h": 720
+            "h": 720,
+            "mtype": 2,
+            "ext": {
+              "formattype": 1
+            }
           },
           "type": "video"
         }
diff --git a/adapters/boldwin/boldwintest/exemplary/endpointId.json b/adapters/boldwin/boldwintest/exemplary/endpointId.json
index 442dce7d..65a0274a 100644
--- a/adapters/boldwin/boldwintest/exemplary/endpointId.json
+++ b/adapters/boldwin/boldwintest/exemplary/endpointId.json
@@ -90,6 +90,7 @@
                                     "dealid": "test_dealid",
                                     "w": 300,
                                     "h": 250,
+                                    "mtype": 1,
                                     "ext": {
                                         "prebid": {
                                             "type": "banner"
@@ -119,6 +120,7 @@
                         "dealid": "test_dealid",
                         "w": 300,
                         "h": 250,
+                        "mtype": 1,
                         "ext": {
                             "prebid": {
                                 "type": "banner"
diff --git a/adapters/boldwin/boldwintest/exemplary/simple-banner.json b/adapters/boldwin/boldwintest/exemplary/simple-banner.json
index ef7d9cc5..5032d716 100644
--- a/adapters/boldwin/boldwintest/exemplary/simple-banner.json
+++ b/adapters/boldwin/boldwintest/exemplary/simple-banner.json
@@ -90,6 +90,7 @@
                                     "dealid": "test_dealid",
                                     "w": 300,
                                     "h": 250,
+                                    "mtype": 1,
                                     "ext": {
                                         "prebid": {
                                             "type": "banner"
@@ -119,6 +120,7 @@
                         "dealid": "test_dealid",
                         "w": 300,
                         "h": 250,
+                        "mtype": 1,
                         "ext": {
                             "prebid": {
                                 "type": "banner"
diff --git a/adapters/boldwin/boldwintest/exemplary/simple-native.json b/adapters/boldwin/boldwintest/exemplary/simple-native.json
index f4da8bde..aad2426a 100644
--- a/adapters/boldwin/boldwintest/exemplary/simple-native.json
+++ b/adapters/boldwin/boldwintest/exemplary/simple-native.json
@@ -74,6 +74,7 @@
                                     "dealid": "test_dealid",
                                     "w": 300,
                                     "h": 250,
+                                    "mtype": 4,
                                     "ext": {
                                         "prebid": {
                                             "type": "native"
@@ -103,6 +104,7 @@
                         "dealid": "test_dealid",
                         "w": 300,
                         "h": 250,
+                        "mtype": 4,
                         "ext": {
                             "prebid": {
                                 "type": "native"
diff --git a/adapters/boldwin/boldwintest/exemplary/simple-video.json b/adapters/boldwin/boldwintest/exemplary/simple-video.json
index d7ae55b2..c754659c 100644
--- a/adapters/boldwin/boldwintest/exemplary/simple-video.json
+++ b/adapters/boldwin/boldwintest/exemplary/simple-video.json
@@ -86,6 +86,7 @@
                                     "cid": "test_cid",
                                     "crid": "test_crid",
                                     "dealid": "test_dealid",
+                                    "mtype": 2,
                                     "ext": {
                                         "prebid": {
                                             "type": "video"
@@ -114,6 +115,7 @@
                         "cid": "test_cid",
                         "crid": "test_crid",
                         "dealid": "test_dealid",
+                        "mtype": 2,
                         "ext": {
                             "prebid": {
                                 "type": "video"
diff --git a/adapters/boldwin/boldwintest/exemplary/simple-web-banner.json b/adapters/boldwin/boldwintest/exemplary/simple-web-banner.json
index 3ec17883..2ffb9a0c 100644
--- a/adapters/boldwin/boldwintest/exemplary/simple-web-banner.json
+++ b/adapters/boldwin/boldwintest/exemplary/simple-web-banner.json
@@ -90,6 +90,7 @@
                                     "dealid": "test_dealid",
                                     "w": 468,
                                     "h": 60,
+                                    "mtype": 1,
                                     "ext": {
                                         "prebid": {
                                             "type": "banner"
@@ -119,6 +120,7 @@
                         "dealid": "test_dealid",
                         "w": 468,
                         "h": 60,
+                        "mtype": 1,
                         "ext": {
                             "prebid": {
                                 "type": "banner"
diff --git a/adapters/boldwin/boldwintest/supplemental/bad_media_type.json b/adapters/boldwin/boldwintest/supplemental/bad_media_type.json
index 5c6dc24d..ea40993f 100644
--- a/adapters/boldwin/boldwintest/supplemental/bad_media_type.json
+++ b/adapters/boldwin/boldwintest/supplemental/bad_media_type.json
@@ -79,7 +79,7 @@
     }],
     "expectedMakeBidsErrors": [
         {
-          "value": "Failed to find impression \"test-imp-id\"",
+          "value": "Unable to fetch mediaType in multi-format: test-imp-id",
           "comparison": "literal"
         }
     ]
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 839c2f6b..ee2e0f6e 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -168,7 +168,7 @@ func TestCharacterEscape(t *testing.T) {
 	var errList []error
 
 	// 	4) Build bid response
-	bidResp := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, adapterExtra, nil, nil, true, nil, "", errList)
+	bidResp := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, adapterExtra, nil, nil, true, nil, "", errList, &nonBids{})
 
 	// 	5) Assert we have no errors and one '&' character as we are supposed to
 	if len(errList) > 0 {
@@ -1336,7 +1336,7 @@ func TestGetBidCacheInfoEndToEnd(t *testing.T) {
 	var errList []error
 
 	// 	4) Build bid response
-	bid_resp := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, adapterExtra, auc, nil, true, nil, "", errList)
+	bid_resp := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, adapterExtra, auc, nil, true, nil, "", errList, &nonBids{})
 
 	expectedBidResponse := &openrtb2.BidResponse{
 		SeatBid: []openrtb2.SeatBid{
@@ -1426,7 +1426,7 @@ func TestBidReturnsCreative(t *testing.T) {
 
 	//Run tests
 	for _, test := range testCases {
-		resultingBids, resultingErrs := e.makeBid(sampleBids, sampleAuction, test.inReturnCreative, nil, nil, "", "")
+		resultingBids, resultingErrs := e.makeBid(sampleBids, sampleAuction, test.inReturnCreative, nil, nil, "", "", &nonBids{})
 
 		assert.Equal(t, 0, len(resultingErrs), "%s. Test should not return errors \n", test.description)
 		assert.Equal(t, test.expectedCreativeMarkup, resultingBids[0].AdM, "%s. Ad markup string doesn't match expected \n", test.description)
@@ -1709,7 +1709,7 @@ func TestBidResponseCurrency(t *testing.T) {
 	}
 	// Run tests
 	for i := range testCases {
-		actualBidResp := e.buildBidResponse(context.Background(), liveAdapters, testCases[i].adapterBids, bidRequest, adapterExtra, nil, bidResponseExt, true, nil, "", errList)
+		actualBidResp := e.buildBidResponse(context.Background(), liveAdapters, testCases[i].adapterBids, bidRequest, adapterExtra, nil, bidResponseExt, true, nil, "", errList, &nonBids{})
 		assert.Equalf(t, testCases[i].expectedBidResponse, actualBidResp, fmt.Sprintf("[TEST_FAILED] Objects must be equal for test: %s \n Expected: >>%s<< \n Actual: >>%s<< ", testCases[i].description, testCases[i].expectedBidResponse.Ext, actualBidResp.Ext))
 	}
 }
@@ -1775,7 +1775,7 @@ func TestBidResponseImpExtInfo(t *testing.T) {
 
 	expectedBidResponseExt := `{"origbidcpm":0,"prebid":{"meta":{"adaptercode":"appnexus"},"type":"video","passthrough":{"imp_passthrough_val":1}},"storedrequestattributes":{"h":480,"mimes":["video/mp4"]}}`
 
-	actualBidResp := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, nil, nil, nil, true, impExtInfo, "", errList)
+	actualBidResp := e.buildBidResponse(context.Background(), liveAdapters, adapterBids, bidRequest, nil, nil, nil, true, impExtInfo, "", errList, &nonBids{})
 
 	resBidExt := string(actualBidResp.SeatBid[0].Bid[0].Ext)
 	assert.Equalf(t, expectedBidResponseExt, resBidExt, "Expected bid response extension is incorrect")
@@ -2212,8 +2212,10 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) {
 
 	aucResponse, err := ex.HoldAuction(ctx, auctionRequest, debugLog)
 	var bid *openrtb2.BidResponse
+	var bidExt *openrtb_ext.ExtBidResponse
 	if aucResponse != nil {
 		bid = aucResponse.BidResponse
+		bidExt = aucResponse.ExtBidResponse
 	}
 	if len(spec.Response.Error) > 0 && spec.Response.Bids == nil {
 		if err.Error() != spec.Response.Error {
@@ -2296,20 +2298,24 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) {
 		assert.JSONEq(t, string(spec.Response.Ext), string(bid.Ext), "ext mismatch")
 	}
 
+	expectedBidRespExt := &openrtb_ext.ExtBidResponse{}
+	if spec.Response.Ext != nil {
+		if err := jsonutil.UnmarshalValid(spec.Response.Ext, expectedBidRespExt); err != nil {
+			assert.NoError(t, err, fmt.Sprintf("Error when unmarshalling: %s", err))
+		}
+	}
 	if spec.HostConfigBidValidation.BannerCreativeMaxSize == config.ValidationEnforce || spec.HostConfigBidValidation.SecureMarkup == config.ValidationEnforce {
 		actualBidRespExt := &openrtb_ext.ExtBidResponse{}
-		expectedBidRespExt := &openrtb_ext.ExtBidResponse{}
 		if bid.Ext != nil {
 			if err := jsonutil.UnmarshalValid(bid.Ext, actualBidRespExt); err != nil {
 				assert.NoError(t, err, fmt.Sprintf("Error when unmarshalling: %s", err))
 			}
 		}
-		if err := jsonutil.UnmarshalValid(spec.Response.Ext, expectedBidRespExt); err != nil {
-			assert.NoError(t, err, fmt.Sprintf("Error when unmarshalling: %s", err))
-		}
-
 		assert.Equal(t, expectedBidRespExt.Errors, actualBidRespExt.Errors, "Expected errors from response ext do not match")
 	}
+	if expectedBidRespExt.Prebid != nil {
+		assert.ElementsMatch(t, expectedBidRespExt.Prebid.SeatNonBid, bidExt.Prebid.SeatNonBid, "Expected seatNonBids from response ext do not match")
+	}
 }
 
 func findBiddersInAuction(t *testing.T, context string, req *openrtb2.BidRequest) []string {
@@ -4734,43 +4740,82 @@ func TestMakeBidWithValidation(t *testing.T) {
 		description       string
 		givenValidations  config.Validations
 		givenBids         []*entities.PbsOrtbBid
+		givenSeat         openrtb_ext.BidderName
 		expectedNumOfBids int
+		expectedNonBids   *nonBids
 	}{
 		{
 			description:       "Validation is enforced, and one bid out of the two is invalid based on dimensions",
 			givenValidations:  config.Validations{BannerCreativeMaxSize: config.ValidationEnforce, MaxCreativeWidth: 100, MaxCreativeHeight: 100},
 			givenBids:         []*entities.PbsOrtbBid{{Bid: &openrtb2.Bid{W: 200, H: 200}, BidType: openrtb_ext.BidTypeBanner}, {Bid: &openrtb2.Bid{W: 50, H: 50}, BidType: openrtb_ext.BidTypeBanner}},
+			givenSeat:         "pubmatic",
 			expectedNumOfBids: 1,
+			expectedNonBids: &nonBids{
+				seatNonBidsMap: map[string][]openrtb_ext.NonBid{
+					"pubmatic": {
+						{
+							StatusCode: 351,
+							Ext: openrtb_ext.NonBidExt{
+								Prebid: openrtb_ext.ExtResponseNonBidPrebid{
+									Bid: openrtb_ext.NonBidObject{
+										W: 200,
+										H: 200,
+									},
+								},
+							},
+						},
+					},
+				},
+			},
 		},
 		{
 			description:       "Validation is warned, so no bids should be removed (Validating CreativeMaxSize) ",
 			givenValidations:  config.Validations{BannerCreativeMaxSize: config.ValidationWarn, MaxCreativeWidth: 100, MaxCreativeHeight: 100},
 			givenBids:         []*entities.PbsOrtbBid{{Bid: &openrtb2.Bid{W: 200, H: 200}, BidType: openrtb_ext.BidTypeBanner}, {Bid: &openrtb2.Bid{W: 50, H: 50}, BidType: openrtb_ext.BidTypeBanner}},
+			givenSeat:         "pubmatic",
 			expectedNumOfBids: 2,
+			expectedNonBids:   &nonBids{},
 		},
 		{
 			description:       "Validation is enforced, and one bid out of the two is invalid based on AdM",
 			givenValidations:  config.Validations{SecureMarkup: config.ValidationEnforce},
 			givenBids:         []*entities.PbsOrtbBid{{Bid: &openrtb2.Bid{AdM: "http://domain.com/invalid", ImpID: "1"}, BidType: openrtb_ext.BidTypeBanner}, {Bid: &openrtb2.Bid{AdM: "https://domain.com/valid", ImpID: "2"}, BidType: openrtb_ext.BidTypeBanner}},
+			givenSeat:         "pubmatic",
 			expectedNumOfBids: 1,
+			expectedNonBids: &nonBids{
+				seatNonBidsMap: map[string][]openrtb_ext.NonBid{
+					"pubmatic": {
+						{
+							ImpId:      "1",
+							StatusCode: 352,
+						},
+					},
+				},
+			},
 		},
 		{
 			description:       "Validation is warned so no bids should be removed (Validating SecureMarkup)",
 			givenValidations:  config.Validations{SecureMarkup: config.ValidationWarn},
 			givenBids:         []*entities.PbsOrtbBid{{Bid: &openrtb2.Bid{AdM: "http://domain.com/invalid", ImpID: "1"}, BidType: openrtb_ext.BidTypeBanner}, {Bid: &openrtb2.Bid{AdM: "https://domain.com/valid", ImpID: "2"}, BidType: openrtb_ext.BidTypeBanner}},
+			givenSeat:         "pubmatic",
 			expectedNumOfBids: 2,
+			expectedNonBids:   &nonBids{},
 		},
 		{
 			description:       "Adm validation is skipped, creative size validation is enforced, one Adm is invalid, but because we skip, no bids should be removed",
 			givenValidations:  config.Validations{SecureMarkup: config.ValidationSkip, BannerCreativeMaxSize: config.ValidationEnforce},
 			givenBids:         []*entities.PbsOrtbBid{{Bid: &openrtb2.Bid{AdM: "http://domain.com/invalid"}, BidType: openrtb_ext.BidTypeBanner}, {Bid: &openrtb2.Bid{AdM: "https://domain.com/valid"}, BidType: openrtb_ext.BidTypeBanner}},
+			givenSeat:         "pubmatic",
 			expectedNumOfBids: 2,
+			expectedNonBids:   &nonBids{},
 		},
 		{
 			description:       "Creative Size Validation is skipped, Adm Validation is enforced, one Creative Size is invalid, but because we skip, no bids should be removed",
 			givenValidations:  config.Validations{BannerCreativeMaxSize: config.ValidationWarn, MaxCreativeWidth: 100, MaxCreativeHeight: 100},
 			givenBids:         []*entities.PbsOrtbBid{{Bid: &openrtb2.Bid{W: 200, H: 200}, BidType: openrtb_ext.BidTypeBanner}, {Bid: &openrtb2.Bid{W: 50, H: 50}, BidType: openrtb_ext.BidTypeBanner}},
+			givenSeat:         "pubmatic",
 			expectedNumOfBids: 2,
+			expectedNonBids:   &nonBids{},
 		},
 	}
 
@@ -4807,12 +4852,16 @@ func TestMakeBidWithValidation(t *testing.T) {
 
 	//Run tests
 	for _, test := range testCases {
-		e.bidValidationEnforcement = test.givenValidations
-		sampleBids := test.givenBids
-		resultingBids, resultingErrs := e.makeBid(sampleBids, sampleAuction, true, ImpExtInfoMap, bidExtResponse, "", "")
-
-		assert.Equal(t, 0, len(resultingErrs), "%s. Test should not return errors \n", test.description)
-		assert.Equal(t, test.expectedNumOfBids, len(resultingBids), "%s. Test returns more valid bids than expected\n", test.description)
+		t.Run(test.description, func(t *testing.T) {
+			e.bidValidationEnforcement = test.givenValidations
+			sampleBids := test.givenBids
+			nonBids := &nonBids{}
+			resultingBids, resultingErrs := e.makeBid(sampleBids, sampleAuction, true, ImpExtInfoMap, bidExtResponse, test.givenSeat, "", nonBids)
+
+			assert.Equal(t, 0, len(resultingErrs), "%s. Test should not return errors \n", test.description)
+			assert.Equal(t, test.expectedNumOfBids, len(resultingBids), "%s. Test returns more valid bids than expected\n", test.description)
+			assert.Equal(t, test.expectedNonBids, nonBids, "%s. Test returns incorrect nonBids\n", test.description)
+		})
 	}
 }
 
diff --git a/exchange/exchangetest/bid_response_validation_enforce_one_bid_rejected.json b/exchange/exchangetest/bid_response_validation_enforce_one_bid_rejected.json
index a6e0de46..90484317 100644
--- a/exchange/exchangetest/bid_response_validation_enforce_one_bid_rejected.json
+++ b/exchange/exchangetest/bid_response_validation_enforce_one_bid_rejected.json
@@ -192,6 +192,30 @@
                         "message": "bidResponse rejected: size WxH"
                     }
                 ]
+            },
+            "prebid": {
+                "seatnonbid": [
+                    {
+                        "nonbid": [
+                            {
+                                "impid": "some-imp-id",
+                                "statuscode": 351,
+                                "ext": {
+                                    "prebid": {
+                                        "bid": {
+                                            "price": 0.3,
+                                            "w": 200,
+                                            "h": 500,
+                                            "origbidcpm": 0.3
+                                        }
+                                    }
+                                }
+                            }
+                        ],
+                        "seat": "appnexus",
+                        "ext": null
+                    }
+                ]
             }
         }
     }
diff --git a/exchange/exchangetest/bid_response_validation_enforce_secure.json b/exchange/exchangetest/bid_response_validation_enforce_secure.json
index e036f82a..773f9b98 100644
--- a/exchange/exchangetest/bid_response_validation_enforce_secure.json
+++ b/exchange/exchangetest/bid_response_validation_enforce_secure.json
@@ -183,6 +183,50 @@
                     }
                 ]
             }
+        },
+        "prebid": {
+          "seatnonbid": [
+            {
+              "nonbid": [
+                {
+                  "impid": "some-imp-id",
+                  "statuscode": 352,
+                  "ext": {
+                    "prebid": {
+                      "bid": {
+                        "price": 0.3,
+                        "w": 20,
+                        "h": 50,
+                        "origbidcpm": 0.3
+                      }
+                    }
+                  }
+                }
+              ],
+              "seat": "appnexus",
+              "ext": null
+            },
+            {
+              "nonbid": [
+                {
+                  "impid": "some-imp-id",
+                  "statuscode": 352,
+                  "ext": {
+                    "prebid": {
+                      "bid": {
+                        "price": 0.4,
+                        "w": 20,
+                        "h": 50,
+                        "origbidcpm": 0.4
+                      }
+                    }
+                  }
+                }
+              ],
+              "seat": "rubicon",
+              "ext": null
+            }
+          ]
         }
     }
 }
\ No newline at end of file