Repository: prebid/prebid-server
Pull request #2416 (2022-10-11 16:03:28)

New Adapter: Bidstack
Related docs PR: https://github.com/prebid/prebid.github.io/pull/4071

AlexBVolcy: There is a PR https://github.com/prebid/prebid-server/pull/2370 that is being merged today that will cause conflicts to new adapter PRs. 

To resolve these conflicts, you'll need to do the following:

In `bidstack.go`, update the `Builder()` function signature to include a new parameter `server config.Server`

In `bidstack_test.go`, update any test that includes a call to `Builder()` to pass a `config.Server` object, to that call (i.e. `config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "datacenter"}`)

After the merge, you can look at other adapters to see how the server object is implemented as an example. 
arthurlataks: @VeronikaSolovei9 Hello, thank you for the review, it was very helpful. I have addressed all the comments.

Patch:
diff --git a/adapters/aja/aja.go b/adapters/aja/aja.go
index 476c5a99..66f331bf 100644
--- a/adapters/aja/aja.go
+++ b/adapters/aja/aja.go
@@ -124,6 +124,9 @@ func (a *AJAAdapter) MakeBids(bidReq *openrtb2.BidRequest, adapterReq *adapters.
 			}
 		}
 	}
+	if bidResp.Cur != "" {
+		bidderResp.Currency = bidResp.Cur
+	}
 	return bidderResp, errors
 }
 
diff --git a/adapters/andbeyondmedia/andbeyondmedia.go b/adapters/beyondmedia/beyondmedia.go
similarity index 89%
rename from adapters/andbeyondmedia/andbeyondmedia.go
rename to adapters/beyondmedia/beyondmedia.go
index c7249020..dd56d849 100644
--- a/adapters/andbeyondmedia/andbeyondmedia.go
+++ b/adapters/beyondmedia/beyondmedia.go
@@ -1,4 +1,4 @@
-package andbeyondmedia
+package beyondmedia
 
 import (
 	"encoding/json"
@@ -17,7 +17,7 @@ type adapter struct {
 }
 
 type reqBodyExt struct {
-	AndBeyondMediaBidderExt reqBodyExtBidder `json:"bidder"`
+	BeyondMediaBidderExt reqBodyExtBidder `json:"bidder"`
 }
 
 type reqBodyExtBidder struct {
@@ -41,18 +41,18 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E
 		reqCopy.Imp = []openrtb2.Imp{imp}
 
 		var bidderExt adapters.ExtImpBidder
-		var andBeyondMediaExt openrtb_ext.ImpExtAndBeyondMedia
+		var beyondMediaExt openrtb_ext.ImpExtBeyondMedia
 
 		if err = json.Unmarshal(reqCopy.Imp[0].Ext, &bidderExt); err != nil {
 			return nil, []error{err}
 		}
-		if err = json.Unmarshal(bidderExt.Bidder, &andBeyondMediaExt); err != nil {
+		if err = json.Unmarshal(bidderExt.Bidder, &beyondMediaExt); err != nil {
 			return nil, []error{err}
 		}
 
-		temp := reqBodyExt{AndBeyondMediaBidderExt: reqBodyExtBidder{}}
-		temp.AndBeyondMediaBidderExt.PlacementID = andBeyondMediaExt.PlacementID
-		temp.AndBeyondMediaBidderExt.Type = "publisher"
+		temp := reqBodyExt{BeyondMediaBidderExt: reqBodyExtBidder{}}
+		temp.BeyondMediaBidderExt.PlacementID = beyondMediaExt.PlacementID
+		temp.BeyondMediaBidderExt.Type = "publisher"
 
 		finalyImpExt, err := json.Marshal(temp)
 		if err != nil {
diff --git a/adapters/bidstack/bidstack.go b/adapters/bidstack/bidstack.go
new file mode 100644
index 00000000..55ce400a
--- /dev/null
+++ b/adapters/bidstack/bidstack.go
@@ -0,0 +1,126 @@
+package bidstack
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/prebid/openrtb/v17/openrtb2"
+
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+const (
+	currencyUSDISO4217 = "USD"
+
+	headerKeyAuthorization         = "Authorization"
+	headerValueAuthorizationBearer = "Bearer "
+	headerKeyContentType           = "Content-Type"
+
+	contentTypeApplicationJSON = "application/json"
+)
+
+type adapter struct {
+	endpoint string
+}
+
+// Builder builds a new instance of the Bidstack adapter for the given bidder with the given config.
+func Builder(_ openrtb_ext.BidderName, config config.Adapter, _ config.Server) (adapters.Bidder, error) {
+	bidder := &adapter{
+		endpoint: config.Endpoint,
+	}
+
+	return bidder, nil
+}
+
+func (a adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	headers, err := prepareHeaders(request)
+	if err != nil {
+		return nil, []error{fmt.Errorf("headers prepare: %v", err)}
+	}
+
+	for i := range request.Imp {
+		imp := &request.Imp[i]
+		if imp.BidFloor > 0 && imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != currencyUSDISO4217 {
+			convertedValue, err := reqInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, currencyUSDISO4217)
+			if err != nil {
+				return nil, []error{err}
+			}
+			imp.BidFloorCur = currencyUSDISO4217
+			imp.BidFloor = convertedValue
+		}
+	}
+
+	requestJSON, err := json.Marshal(request)
+	if err != nil {
+		return nil, []error{fmt.Errorf("bid request marshal: %v", err)}
+	}
+
+	requestData := &adapters.RequestData{
+		Method:  "POST",
+		Uri:     a.endpoint,
+		Headers: headers,
+		Body:    requestJSON,
+	}
+
+	return []*adapters.RequestData{requestData}, nil
+}
+
+func (a *adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	switch responseData.StatusCode {
+	case http.StatusNoContent:
+		return nil, nil
+	case http.StatusBadRequest:
+		return nil, []error{errors.New("bad request from publisher")}
+	case http.StatusOK:
+		break
+	default:
+		return nil, []error{fmt.Errorf("unexpected response status code: %v", responseData.StatusCode)}
+	}
+
+	var response openrtb2.BidResponse
+	if err := json.Unmarshal(responseData.Body, &response); err != nil {
+		return nil, []error{fmt.Errorf("bid response unmarshal: %v", err)}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp))
+	bidResponse.Currency = response.Cur
+	for _, seatBid := range response.SeatBid {
+		for i := range seatBid.Bid {
+			b := &adapters.TypedBid{
+				Bid:     &seatBid.Bid[i],
+				BidType: openrtb_ext.BidTypeVideo,
+			}
+			bidResponse.Bids = append(bidResponse.Bids, b)
+		}
+	}
+
+	return bidResponse, nil
+}
+
+func prepareHeaders(request *openrtb2.BidRequest) (headers http.Header, err error) {
+	bidderImpExt, err := getBidderExt(request.Imp[0])
+	if err != nil {
+		return nil, fmt.Errorf("get bidder ext: %v", err)
+	}
+
+	return http.Header{
+		headerKeyContentType:   {contentTypeApplicationJSON},
+		headerKeyAuthorization: {headerValueAuthorizationBearer + bidderImpExt.PublisherID},
+	}, nil
+}
+
+func getBidderExt(imp openrtb2.Imp) (bidderImpExt openrtb_ext.ImpExtBidstack, err error) {
+	var impExt adapters.ExtImpBidder
+	if err = json.Unmarshal(imp.Ext, &impExt); err != nil {
+		return bidderImpExt, fmt.Errorf("imp ext: %v", err)
+	}
+	if err = json.Unmarshal(impExt.Bidder, &bidderImpExt); err != nil {
+		return bidderImpExt, fmt.Errorf("bidder ext: %v", err)
+	}
+	return bidderImpExt, nil
+}
diff --git a/adapters/logicad/logicad.go b/adapters/logicad/logicad.go
index 7f37386c..17439ad8 100644
--- a/adapters/logicad/logicad.go
+++ b/adapters/logicad/logicad.go
@@ -146,6 +146,9 @@ func (adapter *LogicadAdapter) MakeBids(internalRequest *openrtb2.BidRequest, ex
 			BidType: openrtb_ext.BidTypeBanner,
 		})
 	}
+	if bidResp.Cur != "" {
+		bidResponse.Currency = bidResp.Cur
+	}
 	return bidResponse, nil
 }
 
diff --git a/adapters/pubmatic/pubmatic.go b/adapters/pubmatic/pubmatic.go
index 900ec68d..f00d0d24 100644
--- a/adapters/pubmatic/pubmatic.go
+++ b/adapters/pubmatic/pubmatic.go
@@ -470,6 +470,9 @@ func (a *PubmaticAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externa
 			bidResponse.Bids = append(bidResponse.Bids, typedBid)
 		}
 	}
+	if bidResp.Cur != "" {
+		bidResponse.Currency = bidResp.Cur
+	}
 	return bidResponse, errs
 }
 
diff --git a/adapters/rubicon/rubicon.go b/adapters/rubicon/rubicon.go
index 28879475..7bf80c75 100644
--- a/adapters/rubicon/rubicon.go
+++ b/adapters/rubicon/rubicon.go
@@ -12,6 +12,7 @@ import (
 	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/errortypes"
 	"github.com/prebid/prebid-server/openrtb_ext"
+	"github.com/prebid/prebid-server/util/maputil"
 
 	"github.com/buger/jsonparser"
 	"github.com/prebid/openrtb/v17/adcom1"
@@ -20,6 +21,8 @@ import (
 
 const badvLimitSize = 50
 
+var bannerExtContent = []byte(`{"rp":{"mime":"text/html"}}`)
+
 type RubiconAdapter struct {
 	URI          string
 	XAPIUsername string
@@ -88,22 +91,16 @@ type rubiconUserExtRP struct {
 	Target json.RawMessage `json:"target,omitempty"`
 }
 
-type rubiconExtUserTpID struct {
-	Source string `json:"source"`
-	UID    string `json:"uid"`
-}
-
 type rubiconDataExt struct {
 	SegTax int `json:"segtax"`
 }
 
 type rubiconUserExt struct {
-	Consent     string               `json:"consent,omitempty"`
-	Eids        []openrtb2.EID       `json:"eids,omitempty"`
-	TpID        []rubiconExtUserTpID `json:"tpid,omitempty"`
-	RP          rubiconUserExtRP     `json:"rp"`
-	LiverampIdl string               `json:"liveramp_idl,omitempty"`
-	Data        json.RawMessage      `json:"data,omitempty"`
+	Consent     string           `json:"consent,omitempty"`
+	Eids        []openrtb2.EID   `json:"eids,omitempty"`
+	RP          rubiconUserExtRP `json:"rp"`
+	LiverampIdl string           `json:"liveramp_idl,omitempty"`
+	Data        json.RawMessage  `json:"data,omitempty"`
 }
 
 type rubiconSiteExtRP struct {
@@ -124,9 +121,7 @@ type rubiconPubExt struct {
 }
 
 type rubiconBannerExtRP struct {
-	SizeID     int    `json:"size_id,omitempty"`
-	AltSizeIDs []int  `json:"alt_size_ids,omitempty"`
-	MIME       string `json:"mime"`
+	MIME string `json:"mime"`
 }
 
 type rubiconBannerExt struct {
@@ -160,7 +155,13 @@ type rubiconBidResponse struct {
 
 type rubiconSeatBid struct {
 	openrtb2.SeatBid
-	Buyer string `json:"buyer,omitempty"`
+	Buyer string       `json:"buyer,omitempty"`
+	Bid   []rubiconBid `json:"bid"`
+}
+
+type rubiconBid struct {
+	openrtb2.Bid
+	AdmObject json.RawMessage `json:"admobject,omitempty"`
 }
 
 type extPrebid struct {
@@ -173,94 +174,6 @@ type rubiSize struct {
 	h uint16
 }
 
-var rubiSizeMap = map[rubiSize]int{
-	{w: 468, h: 60}:    1,
-	{w: 728, h: 90}:    2,
-	{w: 728, h: 91}:    2,
-	{w: 120, h: 90}:    5,
-	{w: 125, h: 125}:   7,
-	{w: 120, h: 600}:   8,
-	{w: 160, h: 600}:   9,
-	{w: 300, h: 600}:   10,
-	{w: 200, h: 200}:   13,
-	{w: 250, h: 250}:   14,
-	{w: 300, h: 250}:   15,
-	{w: 300, h: 251}:   15,
-	{w: 336, h: 280}:   16,
-	{w: 240, h: 400}:   17,
-	{w: 300, h: 100}:   19,
-	{w: 980, h: 120}:   31,
-	{w: 250, h: 360}:   32,
-	{w: 180, h: 500}:   33,
-	{w: 980, h: 150}:   35,
-	{w: 468, h: 400}:   37,
-	{w: 930, h: 180}:   38,
-	{w: 750, h: 100}:   39,
-	{w: 750, h: 200}:   40,
-	{w: 750, h: 300}:   41,
-	{w: 320, h: 50}:    43,
-	{w: 300, h: 50}:    44,
-	{w: 300, h: 300}:   48,
-	{w: 1024, h: 768}:  53,
-	{w: 300, h: 1050}:  54,
-	{w: 970, h: 90}:    55,
-	{w: 970, h: 250}:   57,
-	{w: 1000, h: 90}:   58,
-	{w: 320, h: 80}:    59,
-	{w: 320, h: 150}:   60,
-	{w: 1000, h: 1000}: 61,
-	{w: 580, h: 500}:   64,
-	{w: 640, h: 480}:   65,
-	{w: 930, h: 600}:   66,
-	{w: 320, h: 480}:   67,
-	{w: 1800, h: 1000}: 68,
-	{w: 320, h: 320}:   72,
-	{w: 320, h: 160}:   73,
-	{w: 980, h: 240}:   78,
-	{w: 980, h: 300}:   79,
-	{w: 980, h: 400}:   80,
-	{w: 480, h: 300}:   83,
-	{w: 300, h: 120}:   85,
-	{w: 548, h: 150}:   90,
-	{w: 970, h: 310}:   94,
-	{w: 970, h: 100}:   95,
-	{w: 970, h: 210}:   96,
-	{w: 480, h: 320}:   101,
-	{w: 768, h: 1024}:  102,
-	{w: 480, h: 280}:   103,
-	{w: 250, h: 800}:   105,
-	{w: 320, h: 240}:   108,
-	{w: 1000, h: 300}:  113,
-	{w: 320, h: 100}:   117,
-	{w: 800, h: 250}:   125,
-	{w: 200, h: 600}:   126,
-	{w: 980, h: 600}:   144,
-	{w: 980, h: 150}:   145,
-	{w: 1000, h: 250}:  152,
-	{w: 640, h: 320}:   156,
-	{w: 320, h: 250}:   159,
-	{w: 250, h: 600}:   179,
-	{w: 600, h: 300}:   195,
-	{w: 640, h: 360}:   198,
-	{w: 640, h: 200}:   199,
-	{w: 1030, h: 590}:  213,
-	{w: 980, h: 360}:   214,
-	{w: 320, h: 180}:   229,
-	{w: 2000, h: 1400}: 230,
-	{w: 580, h: 400}:   232,
-	{w: 480, h: 820}:   256,
-	{w: 400, h: 600}:   257,
-	{w: 500, h: 200}:   258,
-	{w: 998, h: 200}:   259,
-	{w: 970, h: 1000}:  264,
-	{w: 1920, h: 1080}: 265,
-	{w: 1800, h: 200}:  274,
-	{w: 320, h: 500}:   278,
-	{w: 320, h: 400}:   282,
-	{w: 640, h: 380}:   288,
-	{w: 500, h: 1000}:  548,
-}
-
 // defines the contract for bidrequest.user.ext.eids[i].ext
 type rubiconUserExtEidExt struct {
 	Segments []string `json:"segments,omitempty"`
@@ -273,61 +186,10 @@ type rubiconUserExtEidUidExt struct {
 }
 
 type mappedRubiconUidsParam struct {
-	tpIds       []rubiconExtUserTpID
 	segments    []string
 	liverampIdl string
 }
 
-// MAS algorithm
-func findPrimary(alt []int) (int, []int) {
-	min, pos, primary := 0, 0, 0
-	for i, size := range alt {
-		if size == 15 {
-			primary = 15
-			pos = i
-			break
-		} else if size == 2 {
-			primary = 2
-			pos = i
-		} else if size == 9 && primary != 2 {
-			primary = 9
-			pos = i
-		} else if size < alt[min] {
-			min = i
-		}
-	}
-	if primary == 0 {
-		primary = alt[min]
-		pos = min
-	}
-
-	alt = append(alt[:pos], alt[pos+1:]...)
-	return primary, alt
-}
-
-func parseRubiconSizes(sizes []openrtb2.Format) (primary int, alt []int, err error) {
-	// Fixes #317
-	if len(sizes) < 1 {
-		err = &errortypes.BadInput{
-			Message: "rubicon imps must have at least one imp.format element",
-		}
-		return
-	}
-	for _, size := range sizes {
-		if rs, ok := rubiSizeMap[rubiSize{w: uint16(size.W), h: uint16(size.H)}]; ok {
-			alt = append(alt, rs)
-		}
-	}
-	if len(alt) > 0 {
-		primary, alt = findPrimary(alt)
-	} else {
-		err = &errortypes.BadInput{
-			Message: "No primary size found",
-		}
-	}
-	return
-}
-
 func resolveVideoSizeId(placement adcom1.VideoPlacementSubtype, instl int8, impId string) (sizeID int, err error) {
 	if placement != 0 {
 		if placement == 1 {
@@ -479,13 +341,13 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 						userBuyerUID = extractUserBuyerUID(userExt.Eids)
 					}
 
-					mappedRubiconUidsParam, errors := getTpIdsAndSegments(userExt.Eids)
+					mappedRubiconUidsParam, errors := getSegments(userExt.Eids)
 					if len(errors) > 0 {
 						errs = append(errs, errors...)
 						continue
 					}
 
-					if err := updateUserExtWithTpIdsAndSegments(&userExtRP, mappedRubiconUidsParam); err != nil {
+					if err := updateUserExtWithSegments(&userExtRP, mappedRubiconUidsParam); err != nil {
 						errs = append(errs, err)
 						continue
 					}
@@ -515,6 +377,8 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 		}
 
 		isVideo := isVideo(imp)
+		impType := openrtb_ext.BidTypeVideo
+		requestNative := make(map[string]interface{})
 		if isVideo {
 			videoCopy := *imp.Video
 
@@ -537,21 +401,33 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 			videoCopy.Ext, err = json.Marshal(&videoExt)
 			imp.Video = &videoCopy
 			imp.Banner = nil
-		} else {
-			primarySizeID, altSizeIDs, err := parseRubiconSizes(imp.Banner.Format)
+			imp.Native = nil
+		} else if imp.Banner != nil {
+			bannerCopy := *imp.Banner
+			if len(bannerCopy.Format) < 1 && (bannerCopy.W == nil || *bannerCopy.W == 0 && bannerCopy.H == nil || *bannerCopy.H == 0) {
+				errs = append(errs, &errortypes.BadInput{
+					Message: "rubicon imps must have at least one imp.format element",
+				})
+				continue
+			}
+			bannerCopy.Ext = bannerExtContent
 			if err != nil {
 				errs = append(errs, err)
 				continue
 			}
-			bannerExt := rubiconBannerExt{RP: rubiconBannerExtRP{SizeID: primarySizeID, AltSizeIDs: altSizeIDs, MIME: "text/html"}}
-			bannerCopy := *imp.Banner
-			bannerCopy.Ext, err = json.Marshal(&bannerExt)
+			imp.Banner = &bannerCopy
+			imp.Video = nil
+			imp.Native = nil
+			impType = openrtb_ext.BidTypeBanner
+		} else {
+			native, err := resolveNativeObject(imp.Native, requestNative)
 			if err != nil {
 				errs = append(errs, err)
 				continue
 			}
-			imp.Banner = &bannerCopy
+			imp.Native = native
 			imp.Video = nil
+			impType = openrtb_ext.BidTypeNative
 		}
 
 		accountId, err := rubiconExt.AccountId.Int64()
@@ -607,6 +483,10 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 		rubiconRequest.Ext = nil
 
 		reqJSON, err := json.Marshal(rubiconRequest)
+		if impType == openrtb_ext.BidTypeNative && len(requestNative) > 0 {
+			reqJSON, err = setImpNative(reqJSON, requestNative)
+		}
+
 		if err != nil {
 			errs = append(errs, err)
 			continue
@@ -921,42 +801,17 @@ func extractUserBuyerUID(eids []openrtb2.EID) string {
 	return ""
 }
 
-func getTpIdsAndSegments(eids []openrtb2.EID) (mappedRubiconUidsParam, []error) {
+func getSegments(eids []openrtb2.EID) (mappedRubiconUidsParam, []error) {
 	rubiconUidsParam := mappedRubiconUidsParam{
-		tpIds:    make([]rubiconExtUserTpID, 0),
 		segments: make([]string, 0),
 	}
 	errs := make([]error, 0)
 
 	for _, eid := range eids {
 		switch eid.Source {
-		case "adserver.org":
-			uids := eid.UIDs
-			if len(uids) > 0 {
-				uid := uids[0]
-
-				if uid.Ext != nil {
-					var eidUidExt rubiconUserExtEidUidExt
-					if err := json.Unmarshal(uid.Ext, &eidUidExt); err != nil {
-						errs = append(errs, &errortypes.BadInput{
-							Message: err.Error(),
-						})
-						continue
-					}
-
-					if eidUidExt.RtiPartner == "TDID" {
-						rubiconUidsParam.tpIds = append(rubiconUidsParam.tpIds, rubiconExtUserTpID{Source: "tdid", UID: uid.ID})
-					}
-				}
-			}
 		case "liveintent.com":
 			uids := eid.UIDs
 			if len(uids) > 0 {
-				uidId := uids[0].ID
-				if uidId != "" {
-					rubiconUidsParam.tpIds = append(rubiconUidsParam.tpIds, rubiconExtUserTpID{Source: "liveintent.com", UID: uidId})
-				}
-
 				if eid.Ext != nil {
 					var eidExt rubiconUserExtEidExt
 					if err := json.Unmarshal(eid.Ext, &eidExt); err != nil {
@@ -982,9 +837,8 @@ func getTpIdsAndSegments(eids []openrtb2.EID) (mappedRubiconUidsParam, []error)
 	return rubiconUidsParam, errs
 }
 
-func updateUserExtWithTpIdsAndSegments(userExtRP *rubiconUserExt, rubiconUidsParam mappedRubiconUidsParam) error {
-	if len(rubiconUidsParam.tpIds) > 0 {
-		userExtRP.TpID = rubiconUidsParam.tpIds
+func updateUserExtWithSegments(userExtRP *rubiconUserExt, rubiconUidsParam mappedRubiconUidsParam) error {
+	if len(rubiconUidsParam.segments) > 0 {
 
 		if rubiconUidsParam.segments != nil {
 			userExtRPTarget := make(map[string]interface{})
@@ -1021,6 +875,64 @@ func isFullyPopulatedVideo(video *openrtb2.Video) bool {
 	return video.MIMEs != nil && video.Protocols != nil && video.MaxDuration != 0 && video.Linearity != 0 && video.API != nil
 }
 
+func resolveNativeObject(native *openrtb2.Native, target map[string]interface{}) (*openrtb2.Native, error) {
+	if native == nil {
+		return nil, fmt.Errorf("Native object is not present for request")
+	}
+	ver := native.Ver
+	if ver == "1.0" || ver == "1.1" {
+		return native, nil
+	}
+
+	err := json.Unmarshal([]byte(native.Request), &target)
+	if err != nil {
+		return nil, err
+	}
+
+	if _, ok := target["eventtrackers"].([]interface{}); !ok {
+		return nil, fmt.Errorf("Eventtrackers are not present or not of array type")
+	}
+
+	if _, ok := target["context"].(float64); !ok {
+		return nil, fmt.Errorf("Context is not present or not of int type")
+	}
+
+	if _, ok := target["plcmttype"].(float64); !ok {
+		return nil, fmt.Errorf("Plcmttype is not present or not of int type")
+	}
+
+	return native, nil
+}
+
+func setImpNative(jsonData []byte, requestNative map[string]interface{}) ([]byte, error) {
+	var jsonMap map[string]interface{}
+	if err := json.Unmarshal(jsonData, &jsonMap); err != nil {
+		return jsonData, err
+	}
+
+	var impMap map[string]interface{}
+	if impSlice, ok := maputil.ReadEmbeddedSlice(jsonMap, "imp"); !ok {
+		return jsonData, fmt.Errorf("unable to find imp in json data")
+	} else if len(impSlice) == 0 {
+		return jsonData, fmt.Errorf("unable to find imp[0] in json data")
+	} else if impMap, ok = impSlice[0].(map[string]interface{}); !ok {
+		return jsonData, fmt.Errorf("unexpected type for imp[0] found in json data")
+	}
+
+	nativeMap, ok := maputil.ReadEmbeddedMap(impMap, "native")
+	if !ok {
+		return jsonData, fmt.Errorf("unable to find imp[0].native in json data")
+	}
+
+	nativeMap["request_native"] = requestNative
+
+	if jsonReEncoded, err := json.Marshal(jsonMap); err == nil {
+		return jsonReEncoded, nil
+	} else {
+		return nil, fmt.Errorf("unable to encode json data (%v)", err)
+	}
+}
+
 func (a *RubiconAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
 	if response.StatusCode == http.StatusNoContent {
 		return nil, nil
@@ -1052,11 +964,13 @@ func (a *RubiconAdapter) MakeBids(internalRequest *openrtb2.BidRequest, external
 
 	bidResponse := adapters.NewBidderResponseWithBidsCapacity(5)
 
-	bidType := openrtb_ext.BidTypeBanner
+	bidType := openrtb_ext.BidTypeNative
 
 	isVideo := isVideo(bidReq.Imp[0])
 	if isVideo {
 		bidType = openrtb_ext.BidTypeVideo
+	} else if bidReq.Imp[0].Banner != nil {
+		bidType = openrtb_ext.BidTypeBanner
 	}
 
 	impToCpmOverride := mapImpIdToCpmOverride(internalRequest.Imp)
@@ -1089,13 +1003,32 @@ func (a *RubiconAdapter) MakeBids(internalRequest *openrtb2.BidRequest, external
 				if bid.ID == "0" {
 					bid.ID = bidResp.BidID
 				}
+
+				resolvedAdm := resolveAdm(bid)
+				if len(resolvedAdm) > 0 {
+					bid.AdM = resolvedAdm
+				}
+
+				var ortbBid openrtb2.Bid // `targetStruct` can be anything of your choice
+
+				rubiconBidAsBytes, _ := json.Marshal(bid)
+				if len(rubiconBidAsBytes) > 0 {
+					err = json.Unmarshal(rubiconBidAsBytes, &ortbBid)
+					if err != nil {
+						return nil, []error{err}
+					}
+				}
+
 				bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
-					Bid:     &bid,
+					Bid:     &ortbBid,
 					BidType: bidType,
 				})
 			}
 		}
 	}
+	if bidResp.Cur != "" {
+		bidResponse.Currency = bidResp.Cur
+	}
 
 	return bidResponse, nil
 }
@@ -1118,6 +1051,21 @@ func mapImpIdToCpmOverride(imps []openrtb2.Imp) map[string]float64 {
 	return impIdToCmpOverride
 }
 
+func resolveAdm(bid rubiconBid) string {
+	var bidAdm = bid.AdM
+	if len(bidAdm) > 0 {
+		return bidAdm
+	}
+
+	admObject := bid.AdmObject
+	admObjectAsBytes, err := json.Marshal(&admObject)
+	if err != nil {
+		return ""
+	}
+
+	return string(admObjectAsBytes)
+}
+
 func cmpOverrideFromBidRequest(bidRequest *openrtb2.BidRequest) float64 {
 	var bidRequestExt bidRequestExt
 	if err := json.Unmarshal(bidRequest.Ext, &bidRequestExt); err != nil {
@@ -1127,7 +1075,7 @@ func cmpOverrideFromBidRequest(bidRequest *openrtb2.BidRequest) float64 {
 	return bidRequestExt.Prebid.Bidders.Rubicon.Debug.CpmOverride
 }
 
-func updateBidExtWithMetaNetworkId(bid openrtb2.Bid, buyer int) json.RawMessage {
+func updateBidExtWithMetaNetworkId(bid rubiconBid, buyer int) json.RawMessage {
 	if buyer <= 0 {
 		return nil
 	}
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 1d34708d..b757ea76 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -30,7 +30,6 @@ import (
 	"github.com/prebid/prebid-server/adapters/aja"
 	"github.com/prebid/prebid-server/adapters/algorix"
 	"github.com/prebid/prebid-server/adapters/amx"
-	"github.com/prebid/prebid-server/adapters/andbeyondmedia"
 	"github.com/prebid/prebid-server/adapters/apacdex"
 	"github.com/prebid/prebid-server/adapters/applogy"
 	"github.com/prebid/prebid-server/adapters/appnexus"
@@ -41,9 +40,11 @@ import (
 	"github.com/prebid/prebid-server/adapters/beachfront"
 	"github.com/prebid/prebid-server/adapters/beintoo"
 	"github.com/prebid/prebid-server/adapters/between"
+	"github.com/prebid/prebid-server/adapters/beyondmedia"
 	"github.com/prebid/prebid-server/adapters/bidmachine"
 	"github.com/prebid/prebid-server/adapters/bidmyadz"
 	"github.com/prebid/prebid-server/adapters/bidscube"
+	"github.com/prebid/prebid-server/adapters/bidstack"
 	"github.com/prebid/prebid-server/adapters/bizzclick"
 	"github.com/prebid/prebid-server/adapters/bliink"
 	"github.com/prebid/prebid-server/adapters/blue"
@@ -185,7 +186,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderAJA:               aja.Builder,
 		openrtb_ext.BidderAlgorix:           algorix.Builder,
 		openrtb_ext.BidderAMX:               amx.Builder,
-		openrtb_ext.BidderAndBeyondMedia:    andbeyondmedia.Builder,
 		openrtb_ext.BidderApacdex:           apacdex.Builder,
 		openrtb_ext.BidderApplogy:           applogy.Builder,
 		openrtb_ext.BidderAppnexus:          appnexus.Builder,
@@ -196,9 +196,11 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderBeachfront:        beachfront.Builder,
 		openrtb_ext.BidderBeintoo:           beintoo.Builder,
 		openrtb_ext.BidderBetween:           between.Builder,
+		openrtb_ext.BidderBeyondMedia:       beyondmedia.Builder,
 		openrtb_ext.BidderBidmachine:        bidmachine.Builder,
 		openrtb_ext.BidderBidmyadz:          bidmyadz.Builder,
 		openrtb_ext.BidderBidsCube:          bidscube.Builder,
+		openrtb_ext.BidderBidstack:          bidstack.Builder,
 		openrtb_ext.BidderBizzclick:         bizzclick.Builder,
 		openrtb_ext.BidderBliink:            bliink.Builder,
 		openrtb_ext.BidderBlue:              blue.Builder,
diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go
index bd252c0c..544fe936 100644
--- a/exchange/adapter_util.go
+++ b/exchange/adapter_util.go
@@ -85,10 +85,11 @@ func GetActiveBidders(infos config.BidderInfos) map[string]openrtb_ext.BidderNam
 // GetDisabledBiddersErrorMessages returns a map of error messages for disabled bidders.
 func GetDisabledBiddersErrorMessages(infos config.BidderInfos) map[string]string {
 	disabledBidders := map[string]string{
-		"lifestreet":   `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
-		"adagio":       `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
-		"somoaudience": `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-		"yssp":         `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+		"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
+		"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
+		"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
+		"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+		"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
 	}
 
 	for name, info := range infos {
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index a1795b32..aba2771b 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -110,7 +110,6 @@ const (
 	BidderAJA               BidderName = "aja"
 	BidderAlgorix           BidderName = "algorix"
 	BidderAMX               BidderName = "amx"
-	BidderAndBeyondMedia    BidderName = "andbeyondmedia"
 	BidderApacdex           BidderName = "apacdex"
 	BidderApplogy           BidderName = "applogy"
 	BidderAppnexus          BidderName = "appnexus"
@@ -121,9 +120,11 @@ const (
 	BidderBeachfront        BidderName = "beachfront"
 	BidderBeintoo           BidderName = "beintoo"
 	BidderBetween           BidderName = "between"
+	BidderBeyondMedia       BidderName = "beyondmedia"
 	BidderBidmachine        BidderName = "bidmachine"
 	BidderBidmyadz          BidderName = "bidmyadz"
 	BidderBidsCube          BidderName = "bidscube"
+	BidderBidstack          BidderName = "bidstack"
 	BidderBizzclick         BidderName = "bizzclick"
 	BidderBliink            BidderName = "bliink"
 	BidderBlue              BidderName = "blue"
@@ -273,7 +274,6 @@ func CoreBidderNames() []BidderName {
 		BidderAJA,
 		BidderAlgorix,
 		BidderAMX,
-		BidderAndBeyondMedia,
 		BidderApacdex,
 		BidderApplogy,
 		BidderAppnexus,
@@ -284,9 +284,11 @@ func CoreBidderNames() []BidderName {
 		BidderBeachfront,
 		BidderBeintoo,
 		BidderBetween,
+		BidderBeyondMedia,
 		BidderBidmachine,
 		BidderBidmyadz,
 		BidderBidsCube,
+		BidderBidstack,
 		BidderBizzclick,
 		BidderBliink,
 		BidderBlue,
diff --git a/openrtb_ext/imp_andbeyondmedia.go b/openrtb_ext/imp_beyondmedia.go
similarity index 64%
rename from openrtb_ext/imp_andbeyondmedia.go
rename to openrtb_ext/imp_beyondmedia.go
index 68b65a3c..d9cb1ef8 100644
--- a/openrtb_ext/imp_andbeyondmedia.go
+++ b/openrtb_ext/imp_beyondmedia.go
@@ -1,5 +1,5 @@
 package openrtb_ext
 
-type ImpExtAndBeyondMedia struct {
+type ImpExtBeyondMedia struct {
 	PlacementID string `json:"placementId"`
 }
diff --git a/openrtb_ext/imp_bidstack.go b/openrtb_ext/imp_bidstack.go
new file mode 100644
index 00000000..c3451c81
--- /dev/null
+++ b/openrtb_ext/imp_bidstack.go
@@ -0,0 +1,5 @@
+package openrtb_ext
+
+type ImpExtBidstack struct {
+	PublisherID string `json:"publisherId"`
+}
diff --git a/static/bidder-info/andbeyondmedia.yaml b/static/bidder-info/beyondmedia.yaml
similarity index 100%
rename from static/bidder-info/andbeyondmedia.yaml
rename to static/bidder-info/beyondmedia.yaml
diff --git a/static/bidder-info/bidstack.yaml b/static/bidder-info/bidstack.yaml
new file mode 100644
index 00000000..894d4fe2
--- /dev/null
+++ b/static/bidder-info/bidstack.yaml
@@ -0,0 +1,10 @@
+endpoint: "https://server.bidstack.com/openrtb"
+maintainer:
+  email: tech@bidstack.com
+endpointCompression: gzip
+gvlVendorID: 462
+modifyingVastXmlAllowed: true
+capabilities:
+  app:
+    mediaTypes:
+      - video
diff --git a/static/bidder-info/rubicon.yaml b/static/bidder-info/rubicon.yaml
index 21f59e9d..b3de838c 100644
--- a/static/bidder-info/rubicon.yaml
+++ b/static/bidder-info/rubicon.yaml
@@ -8,10 +8,12 @@ capabilities:
     mediaTypes:
       - banner
       - video
+      - native
   site:
     mediaTypes:
       - banner
       - video
+      - native
 userSync:
   # rubicon supports user syncing, but requires configuration by the host. contact this
   # bidder directly at the email address in this file to ask about enabling user sync.
diff --git a/static/bidder-params/andbeyondmedia.json b/static/bidder-params/beyondmedia.json
similarity index 100%
rename from static/bidder-params/andbeyondmedia.json
rename to static/bidder-params/beyondmedia.json
diff --git a/static/bidder-params/bidstack.json b/static/bidder-params/bidstack.json
new file mode 100644
index 00000000..6fd0f6b5
--- /dev/null
+++ b/static/bidder-params/bidstack.json
@@ -0,0 +1,15 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Bidstack Adapter Params",
+  "description": "A schema which validates params accepted by the Bidstack adapter",
+  "type": "object",
+  "properties": {
+    "publisherId": {
+      "type": "string",
+      "format": "uuid",
+      "minLength": 1,
+      "description": "An ID which identifies the publisher in Bidstack system"
+    }
+  },
+  "required" : [ "publisherId" ]
+}


Test patch:
diff --git a/adapters/andbeyondmedia/andbeyondmedia_test.go b/adapters/beyondmedia/beyondmedia_test.go
similarity index 72%
rename from adapters/andbeyondmedia/andbeyondmedia_test.go
rename to adapters/beyondmedia/beyondmedia_test.go
index 8b50aec8..9b22d1bb 100644
--- a/adapters/andbeyondmedia/andbeyondmedia_test.go
+++ b/adapters/beyondmedia/beyondmedia_test.go
@@ -1,4 +1,4 @@
-package andbeyondmedia
+package beyondmedia
 
 import (
 	"testing"
@@ -9,12 +9,12 @@ import (
 )
 
 func TestJsonSamples(t *testing.T) {
-	bidder, buildErr := Builder(openrtb_ext.BidderAndBeyondMedia, config.Adapter{
+	bidder, buildErr := Builder(openrtb_ext.BidderBeyondMedia, config.Adapter{
 		Endpoint: "http://backend.andbeyond.media/pserver"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
 
 	if buildErr != nil {
 		t.Fatalf("Builder returned unexpected error %v", buildErr)
 	}
 
-	adapterstest.RunJSONBidderTest(t, "andbeyondmediatest", bidder)
+	adapterstest.RunJSONBidderTest(t, "beyondmediatest", bidder)
 }
diff --git a/adapters/andbeyondmedia/andbeyondmediatest/exemplary/simple-banner.json b/adapters/beyondmedia/beyondmediatest/exemplary/simple-banner.json
similarity index 98%
rename from adapters/andbeyondmedia/andbeyondmediatest/exemplary/simple-banner.json
rename to adapters/beyondmedia/beyondmediatest/exemplary/simple-banner.json
index 136fc666..d53a5f1b 100644
--- a/adapters/andbeyondmedia/andbeyondmediatest/exemplary/simple-banner.json
+++ b/adapters/beyondmedia/beyondmediatest/exemplary/simple-banner.json
@@ -97,7 +97,7 @@
                                     }
                                 }
                             ],
-                            "seat": "andbeyondmedia"
+                            "seat": "beyondmedia"
                         }
                     ],
                     "cur": "USD"
diff --git a/adapters/andbeyondmedia/andbeyondmediatest/exemplary/simple-native.json b/adapters/beyondmedia/beyondmediatest/exemplary/simple-native.json
similarity index 98%
rename from adapters/andbeyondmedia/andbeyondmediatest/exemplary/simple-native.json
rename to adapters/beyondmedia/beyondmediatest/exemplary/simple-native.json
index 95f7f335..f0a62312 100644
--- a/adapters/andbeyondmedia/andbeyondmediatest/exemplary/simple-native.json
+++ b/adapters/beyondmedia/beyondmediatest/exemplary/simple-native.json
@@ -81,7 +81,7 @@
                                     }
                                 }
                             ],
-                            "seat": "andbeyondmedia"
+                            "seat": "beyondmedia"
                         }
                     ],
                     "cur": "USD"
diff --git a/adapters/andbeyondmedia/andbeyondmediatest/exemplary/simple-video.json b/adapters/beyondmedia/beyondmediatest/exemplary/simple-video.json
similarity index 99%
rename from adapters/andbeyondmedia/andbeyondmediatest/exemplary/simple-video.json
rename to adapters/beyondmedia/beyondmediatest/exemplary/simple-video.json
index e11129f4..0b650d62 100644
--- a/adapters/andbeyondmedia/andbeyondmediatest/exemplary/simple-video.json
+++ b/adapters/beyondmedia/beyondmediatest/exemplary/simple-video.json
@@ -93,7 +93,7 @@
                                     }
                                 }
                             ],
-                            "seat": "andbeyondmedia"
+                            "seat": "beyondmedia"
                         }
                     ],
                     "cur": "USD"
diff --git a/adapters/andbeyondmedia/andbeyondmediatest/exemplary/simple-web-banner.json b/adapters/beyondmedia/beyondmediatest/exemplary/simple-web-banner.json
similarity index 98%
rename from adapters/andbeyondmedia/andbeyondmediatest/exemplary/simple-web-banner.json
rename to adapters/beyondmedia/beyondmediatest/exemplary/simple-web-banner.json
index cdd905c5..0e04a25d 100644
--- a/adapters/andbeyondmedia/andbeyondmediatest/exemplary/simple-web-banner.json
+++ b/adapters/beyondmedia/beyondmediatest/exemplary/simple-web-banner.json
@@ -97,7 +97,7 @@
                                     }
                                 }
                             ],
-                            "seat": "andbeyondmedia"
+                            "seat": "beyondmedia"
                         }
                     ],
                     "cur": "USD"
diff --git a/adapters/andbeyondmedia/andbeyondmediatest/supplemental/bad_media_type.json b/adapters/beyondmedia/beyondmediatest/supplemental/bad_media_type.json
similarity index 98%
rename from adapters/andbeyondmedia/andbeyondmediatest/supplemental/bad_media_type.json
rename to adapters/beyondmedia/beyondmediatest/supplemental/bad_media_type.json
index e61b19b7..542529ab 100644
--- a/adapters/andbeyondmedia/andbeyondmediatest/supplemental/bad_media_type.json
+++ b/adapters/beyondmedia/beyondmediatest/supplemental/bad_media_type.json
@@ -70,7 +70,7 @@
                                 }
                             }
                         ],
-                        "seat": "andbeyondmedia"
+                        "seat": "beyondmedia"
                     }
                 ],
                 "cur": "USD"
diff --git a/adapters/andbeyondmedia/andbeyondmediatest/supplemental/bad_response.json b/adapters/beyondmedia/beyondmediatest/supplemental/bad_response.json
similarity index 100%
rename from adapters/andbeyondmedia/andbeyondmediatest/supplemental/bad_response.json
rename to adapters/beyondmedia/beyondmediatest/supplemental/bad_response.json
diff --git a/adapters/andbeyondmedia/andbeyondmediatest/supplemental/status-204.json b/adapters/beyondmedia/beyondmediatest/supplemental/status-204.json
similarity index 100%
rename from adapters/andbeyondmedia/andbeyondmediatest/supplemental/status-204.json
rename to adapters/beyondmedia/beyondmediatest/supplemental/status-204.json
diff --git a/adapters/andbeyondmedia/andbeyondmediatest/supplemental/status-not-200.json b/adapters/beyondmedia/beyondmediatest/supplemental/status-not-200.json
similarity index 100%
rename from adapters/andbeyondmedia/andbeyondmediatest/supplemental/status-not-200.json
rename to adapters/beyondmedia/beyondmediatest/supplemental/status-not-200.json
diff --git a/adapters/andbeyondmedia/params_test.go b/adapters/beyondmedia/params_test.go
similarity index 79%
rename from adapters/andbeyondmedia/params_test.go
rename to adapters/beyondmedia/params_test.go
index 6a09fdb6..9b0f8e8f 100644
--- a/adapters/andbeyondmedia/params_test.go
+++ b/adapters/beyondmedia/params_test.go
@@ -1,4 +1,4 @@
-package andbeyondmedia
+package beyondmedia
 
 import (
 	"encoding/json"
@@ -14,7 +14,7 @@ func TestValidParams(t *testing.T) {
 	}
 
 	for _, p := range validParams {
-		if err := validator.Validate(openrtb_ext.BidderAndBeyondMedia, json.RawMessage(p)); err != nil {
+		if err := validator.Validate(openrtb_ext.BidderBeyondMedia, json.RawMessage(p)); err != nil {
 			t.Errorf("Schema rejected valid params: %s", p)
 		}
 	}
@@ -27,7 +27,7 @@ func TestInvalidParams(t *testing.T) {
 	}
 
 	for _, p := range invalidParams {
-		if err := validator.Validate(openrtb_ext.BidderAndBeyondMedia, json.RawMessage(p)); err == nil {
+		if err := validator.Validate(openrtb_ext.BidderBeyondMedia, json.RawMessage(p)); err == nil {
 			t.Errorf("Schema allowed invalid params: %s", p)
 		}
 	}
diff --git a/adapters/bidstack/bidstack_test.go b/adapters/bidstack/bidstack_test.go
new file mode 100644
index 00000000..38ed711c
--- /dev/null
+++ b/adapters/bidstack/bidstack_test.go
@@ -0,0 +1,50 @@
+package bidstack
+
+import (
+	"net/http"
+	"testing"
+
+	"github.com/prebid/openrtb/v17/openrtb2"
+	"github.com/stretchr/testify/assert"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderBidstack, config.Adapter{Endpoint: "http://mock-adserver.url"}, config.Server{})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "bidstacktest", bidder)
+}
+
+func TestPrepareHeaders(t *testing.T) {
+	publisherID := "12345"
+	expected := http.Header{
+		"Content-Type":  {"application/json"},
+		"Authorization": {"Bearer " + publisherID},
+	}
+
+	actual, err := prepareHeaders(&openrtb2.BidRequest{Imp: []openrtb2.Imp{
+		{Ext: []byte(`{"bidder":{"publisherId":"` + publisherID + `"}}`)}},
+	})
+
+	assert.NoError(t, err)
+	assert.Equal(t, expected, actual)
+}
+
+func TestGetBidderExt(t *testing.T) {
+	publisherID := "12345"
+	expected := openrtb_ext.ImpExtBidstack{PublisherID: publisherID}
+
+	actual, err := getBidderExt(openrtb2.Imp{
+		Ext: []byte(`{"bidder":{"publisherId":"` + publisherID + `"}}`),
+	})
+
+	assert.NoError(t, err)
+	assert.Equal(t, expected, actual)
+}
diff --git a/adapters/bidstack/bidstacktest/exemplary/simple-app-video.json b/adapters/bidstack/bidstacktest/exemplary/simple-app-video.json
new file mode 100644
index 00000000..46729f9b
--- /dev/null
+++ b/adapters/bidstack/bidstacktest/exemplary/simple-app-video.json
@@ -0,0 +1,143 @@
+{
+  "mockBidRequest": {
+    "id": "bid-request-id",
+    "device": {
+      "ip": "0.0.0.0",
+      "ifa": "ce76100d-82cc-4491-a6c9-50e0e539454c"
+    },
+    "app": {
+      "id": "app-id",
+      "bundle": "com.app.id"
+    },
+    "imp": [
+      {
+        "id": "imp-id-1",
+        "bidfloor": 4.20,
+        "bidfloorcur": "GBP",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "protocols": [
+            2,
+            5
+          ],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "bidder": {
+            "publisherId": "225a4f40-1df1-48b2-b238-8774a638ce6e"
+          }
+        }
+      }
+    ],
+    "ext": {
+      "prebid": {
+        "currency": {
+          "rates": {
+            "GBP": {
+              "USD": 0.5
+            }
+          },
+          "usepbsrates": false
+        }
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://mock-adserver.url",
+        "body": {
+          "id": "bid-request-id",
+          "device": {
+            "ip": "0.0.0.0",
+            "ifa": "ce76100d-82cc-4491-a6c9-50e0e539454c"
+          },
+          "app": {
+            "id": "app-id",
+            "bundle": "com.app.id"
+          },
+          "imp": [
+            {
+              "id": "imp-id-1",
+              "bidfloor": 2.10,
+              "bidfloorcur": "USD",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "protocols": [
+                  2,
+                  5
+                ],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "publisherId": "225a4f40-1df1-48b2-b238-8774a638ce6e"
+                }
+              }
+            }
+          ],
+          "ext": {
+            "prebid": {
+              "currency": {
+                "rates": {
+                  "GBP": {
+                    "USD": 0.5
+                  }
+                },
+                "usepbsrates": false
+              }
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "bid-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "bid_id-1",
+                  "impid": "imp-id-1",
+                  "price": 0.27543,
+                  "adm": "<VAST version=\"3.0\"></VAST>",
+                  "cid": "cid",
+                  "crid": "crid",
+                  "dealid": "dealid"
+                }
+              ],
+              "seat": "seat"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "bid_id-1",
+            "impid": "imp-id-1",
+            "price": 0.27543,
+            "adm": "<VAST version=\"3.0\"></VAST>",
+            "cid": "cid",
+            "crid": "crid",
+            "dealid": "dealid"
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/bidstack/bidstacktest/supplemental/currency_rate_not_found.json b/adapters/bidstack/bidstacktest/supplemental/currency_rate_not_found.json
new file mode 100644
index 00000000..b8160c3e
--- /dev/null
+++ b/adapters/bidstack/bidstacktest/supplemental/currency_rate_not_found.json
@@ -0,0 +1,54 @@
+{
+  "mockBidRequest": {
+    "id": "bid-request-id",
+    "device": {
+      "ip": "0.0.0.0",
+      "ifa": "ce76100d-82cc-4491-a6c9-50e0e539454c"
+    },
+    "app": {
+      "id": "app-id",
+      "bundle": "com.app.id"
+    },
+    "imp": [
+      {
+        "id": "imp-id-1",
+        "bidfloor": 4.20,
+        "bidfloorcur": "JPY",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "protocols": [
+            2,
+            5
+          ],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "bidder": {
+            "publisherId": "225a4f40-1df1-48b2-b238-8774a638ce6e"
+          }
+        }
+      }
+    ],
+    "ext": {
+      "prebid": {
+        "currency": {
+          "rates": {
+            "MXN": {
+              "USD": 0.05
+            }
+          },
+          "usepbsrates": false
+        }
+      }
+    }
+  },
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "Currency conversion rate not found: 'JPY' => 'USD'",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/bidstack/bidstacktest/supplemental/status-204.json b/adapters/bidstack/bidstacktest/supplemental/status-204.json
new file mode 100644
index 00000000..2c84a354
--- /dev/null
+++ b/adapters/bidstack/bidstacktest/supplemental/status-204.json
@@ -0,0 +1,78 @@
+{
+  "mockBidRequest": {
+    "id": "bid-request-id",
+    "device": {
+      "ip": "0.0.0.0",
+      "ifa": "ce76100d-82cc-4491-a6c9-50e0e539454c"
+    },
+    "app": {
+      "id": "app-id",
+      "bundle": "com.app.id"
+    },
+    "imp": [
+      {
+        "id": "imp-id-1",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "protocols": [
+            2,
+            5
+          ],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "bidder": {
+            "publisherId": "225a4f40-1df1-48b2-b238-8774a638ce6e"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://mock-adserver.url",
+        "body": {
+          "id": "bid-request-id",
+          "device": {
+            "ip": "0.0.0.0",
+            "ifa": "ce76100d-82cc-4491-a6c9-50e0e539454c"
+          },
+          "app": {
+            "id": "app-id",
+            "bundle": "com.app.id"
+          },
+          "imp": [
+            {
+              "id": "imp-id-1",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "protocols": [
+                  2,
+                  5
+                ],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "publisherId": "225a4f40-1df1-48b2-b238-8774a638ce6e"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 204,
+        "body": {}
+      }
+    }
+  ],
+  "expectedBidResponses": []
+}
diff --git a/adapters/bidstack/bidstacktest/supplemental/status-400.json b/adapters/bidstack/bidstacktest/supplemental/status-400.json
new file mode 100644
index 00000000..eaf5b0e5
--- /dev/null
+++ b/adapters/bidstack/bidstacktest/supplemental/status-400.json
@@ -0,0 +1,83 @@
+{
+  "mockBidRequest": {
+    "id": "bid-request-id",
+    "device": {
+      "ip": "0.0.0.0",
+      "ifa": "ce76100d-82cc-4491-a6c9-50e0e539454c"
+    },
+    "app": {
+      "id": "app-id",
+      "bundle": "com.app.id"
+    },
+    "imp": [
+      {
+        "id": "imp-id-1",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "protocols": [
+            2,
+            5
+          ],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "bidder": {
+            "publisherId": "225a4f40-1df1-48b2-b238-8774a638ce6e"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://mock-adserver.url",
+        "body": {
+          "id": "bid-request-id",
+          "device": {
+            "ip": "0.0.0.0",
+            "ifa": "ce76100d-82cc-4491-a6c9-50e0e539454c"
+          },
+          "app": {
+            "id": "app-id",
+            "bundle": "com.app.id"
+          },
+          "imp": [
+            {
+              "id": "imp-id-1",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "protocols": [
+                  2,
+                  5
+                ],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "publisherId": "225a4f40-1df1-48b2-b238-8774a638ce6e"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 400,
+        "body": {}
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "bad request from publisher",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/bidstack/bidstacktest/supplemental/status-404.json b/adapters/bidstack/bidstacktest/supplemental/status-404.json
new file mode 100644
index 00000000..7bed7485
--- /dev/null
+++ b/adapters/bidstack/bidstacktest/supplemental/status-404.json
@@ -0,0 +1,83 @@
+{
+  "mockBidRequest": {
+    "id": "bid-request-id",
+    "device": {
+      "ip": "0.0.0.0",
+      "ifa": "ce76100d-82cc-4491-a6c9-50e0e539454c"
+    },
+    "app": {
+      "id": "app-id",
+      "bundle": "com.app.id"
+    },
+    "imp": [
+      {
+        "id": "imp-id-1",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "protocols": [
+            2,
+            5
+          ],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "bidder": {
+            "publisherId": "225a4f40-1df1-48b2-b238-8774a638ce6e"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://mock-adserver.url",
+        "body": {
+          "id": "bid-request-id",
+          "device": {
+            "ip": "0.0.0.0",
+            "ifa": "ce76100d-82cc-4491-a6c9-50e0e539454c"
+          },
+          "app": {
+            "id": "app-id",
+            "bundle": "com.app.id"
+          },
+          "imp": [
+            {
+              "id": "imp-id-1",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "protocols": [
+                  2,
+                  5
+                ],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "publisherId": "225a4f40-1df1-48b2-b238-8774a638ce6e"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 404,
+        "body": {}
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "unexpected response status code: 404",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/bidstack/params_test.go b/adapters/bidstack/params_test.go
new file mode 100644
index 00000000..90150f47
--- /dev/null
+++ b/adapters/bidstack/params_test.go
@@ -0,0 +1,43 @@
+package bidstack
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+var validParams = []string{
+	`{"publisherId": "355cf800-8348-433a-9d95-70345fa70afc"}`,
+}
+
+var invalidParams = []string{
+	`{"publisherId": ""}`,
+	`{"publisherId": "non-uuid"}`,
+}
+
+func TestValidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json schema. %v", err)
+	}
+
+	for _, p := range validParams {
+		if err := validator.Validate(openrtb_ext.BidderBidstack, json.RawMessage(p)); err != nil {
+			t.Errorf("Schema rejected valid params: %s", p)
+		}
+	}
+}
+
+func TestInvalidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json schema. %v", err)
+	}
+
+	for _, p := range invalidParams {
+		if err := validator.Validate(openrtb_ext.BidderBidstack, json.RawMessage(p)); err == nil {
+			t.Errorf("Schema allowed invalid params: %s", p)
+		}
+	}
+}
diff --git a/adapters/rubicon/rubicon_test.go b/adapters/rubicon/rubicon_test.go
index a485527e..f33b0531 100644
--- a/adapters/rubicon/rubicon_test.go
+++ b/adapters/rubicon/rubicon_test.go
@@ -3,6 +3,7 @@ package rubicon
 import (
 	"encoding/json"
 	"errors"
+	"fmt"
 	"net/http"
 	"strconv"
 	"testing"
@@ -50,208 +51,89 @@ type rubiBidInfo struct {
 
 var rubidata rubiBidInfo
 
-func getTestSizes() map[int]openrtb2.Format {
-	return map[int]openrtb2.Format{
-		15: {W: 300, H: 250},
-		10: {W: 300, H: 600},
-		2:  {W: 728, H: 91},
-		9:  {W: 160, H: 600},
-		8:  {W: 120, H: 600},
-		33: {W: 180, H: 500},
-		43: {W: 320, H: 50},
-	}
-}
-
-func TestParseSizes(t *testing.T) {
-	SIZE_ID := getTestSizes()
-
-	sizes := []openrtb2.Format{
-		SIZE_ID[10],
-		SIZE_ID[15],
-	}
-	primary, alt, err := parseRubiconSizes(sizes)
-	assert.Nil(t, err, "Parsing error: %v", err)
-	assert.Equal(t, 15, primary, "Primary %d != 15", primary)
-	assert.Equal(t, 1, len(alt), "Alt not len 1")
-	assert.Equal(t, 10, alt[0], "Alt not 10: %d", alt[0])
-
-	sizes = []openrtb2.Format{
+func TestAppendTracker(t *testing.T) {
+	testScenarios := []rubiAppendTrackerUrlTestScenario{
 		{
-			W: 1111,
-			H: 2222,
+			source:   "http://test.url/",
+			tracker:  "prebid",
+			expected: "http://test.url/?tk_xint=prebid",
 		},
-		SIZE_ID[15],
-	}
-	primary, alt, err = parseRubiconSizes(sizes)
-	assert.Nil(t, err, "Shouldn't have thrown error for invalid size 1111x1111 since we still have a valid one")
-	assert.Equal(t, 15, primary, "Primary %d != 15", primary)
-	assert.Equal(t, 0, len(alt), "Alt len %d != 0", len(alt))
-
-	sizes = []openrtb2.Format{
-		SIZE_ID[15],
-	}
-	primary, alt, err = parseRubiconSizes(sizes)
-	assert.Nil(t, err, "Parsing error: %v", err)
-	assert.Equal(t, 15, primary, "Primary %d != 15", primary)
-	assert.Equal(t, 0, len(alt), "Alt len %d != 0", len(alt))
-
-	sizes = []openrtb2.Format{
 		{
-			W: 1111,
-			H: 1222,
+			source:   "http://test.url/?hello=true",
+			tracker:  "prebid",
+			expected: "http://test.url/?hello=true&tk_xint=prebid",
 		},
 	}
-	primary, alt, err = parseRubiconSizes(sizes)
-	assert.NotNil(t, err, "Parsing error: %v", err)
-	assert.Equal(t, 0, primary, "Primary %d != 15", primary)
-	assert.Equal(t, 0, len(alt), "Alt len %d != 0", len(alt))
-}
 
-func TestMASAlgorithm(t *testing.T) {
-	SIZE_ID := getTestSizes()
-	type output struct {
-		primary int
-		alt     []int
-		ok      bool
-	}
-	type testStub struct {
-		input  []openrtb2.Format
-		output output
+	for _, scenario := range testScenarios {
+		res := appendTrackerToUrl(scenario.source, scenario.tracker)
+		assert.Equal(t, scenario.expected, res, "Failed to convert '%s' to '%s'", res, scenario.expected)
 	}
+}
 
-	testStubs := []testStub{
-		{
-			[]openrtb2.Format{
-				SIZE_ID[2],
-				SIZE_ID[9],
-			},
-			output{2, []int{9}, false},
-		},
-		{
-			[]openrtb2.Format{
-
-				SIZE_ID[9],
-				SIZE_ID[15],
-			},
-			output{15, []int{9}, false},
-		},
-		{
-			[]openrtb2.Format{
-				SIZE_ID[2],
-				SIZE_ID[15],
-			},
-			output{15, []int{2}, false},
-		},
-		{
-			[]openrtb2.Format{
-				SIZE_ID[15],
-				SIZE_ID[9],
-				SIZE_ID[2],
-			},
-			output{15, []int{2, 9}, false},
-		},
-		{
-			[]openrtb2.Format{
-				SIZE_ID[10],
-				SIZE_ID[9],
-				SIZE_ID[2],
-			},
-			output{2, []int{10, 9}, false},
-		},
-		{
-			[]openrtb2.Format{
-				SIZE_ID[33],
-				SIZE_ID[8],
-				SIZE_ID[15],
-			},
-			output{15, []int{33, 8}, false},
-		},
+func TestSetImpNative(t *testing.T) {
+	testScenarios := []struct {
+		request       string
+		impNative     map[string]interface{}
+		expectedError error
+	}{
 		{
-			[]openrtb2.Format{
-				SIZE_ID[33],
-				SIZE_ID[8],
-				SIZE_ID[9],
-				SIZE_ID[2],
-			},
-			output{2, []int{33, 8, 9}, false},
+			request:       "{}",
+			impNative:     map[string]interface{}{"somekey": "someValue"},
+			expectedError: fmt.Errorf("unable to find imp in json data"),
 		},
 		{
-			[]openrtb2.Format{
-				SIZE_ID[33],
-				SIZE_ID[8],
-				SIZE_ID[9],
-			},
-			output{9, []int{33, 8}, false},
+			request:       "{\"imp\":[]}",
+			impNative:     map[string]interface{}{"somekey": "someValue"},
+			expectedError: fmt.Errorf("unable to find imp[0] in json data"),
 		},
 		{
-			[]openrtb2.Format{
-				SIZE_ID[33],
-				SIZE_ID[8],
-				SIZE_ID[2],
-			},
-			output{2, []int{33, 8}, false},
-		},
-		{
-			[]openrtb2.Format{
-				SIZE_ID[33],
-				SIZE_ID[2],
-			},
-			output{2, []int{33}, false},
+			request:       "{\"imp\":[{}]}",
+			impNative:     map[string]interface{}{"somekey": "someValue"},
+			expectedError: fmt.Errorf("unable to find imp[0].native in json data"),
 		},
+	}
+	for _, scenario := range testScenarios {
+		_, err := setImpNative([]byte(scenario.request), scenario.impNative)
+		assert.Equal(t, scenario.expectedError, err)
+	}
+}
+
+func TestResolveNativeObject(t *testing.T) {
+	testScenarios := []struct {
+		nativeObject  openrtb2.Native
+		target        map[string]interface{}
+		expectedError error
+	}{
 		{
-			[]openrtb2.Format{
-				SIZE_ID[8],
-			},
-			output{8, []int{}, false},
+			nativeObject:  openrtb2.Native{Ver: "1.0", Request: "{\"eventtrackers\": \"someWrongValue\"}"},
+			target:        map[string]interface{}{},
+			expectedError: nil,
 		},
 		{
-			[]openrtb2.Format{},
-			output{0, []int{}, true},
+			nativeObject:  openrtb2.Native{Ver: "1.1", Request: "{\"eventtrackers\": \"someWrongValue\"}"},
+			target:        map[string]interface{}{},
+			expectedError: nil,
 		},
 		{
-			[]openrtb2.Format{
-				{W: 1111,
-					H: 2345,
-				},
-			},
-			output{0, []int{}, true},
+			nativeObject:  openrtb2.Native{Ver: "1", Request: "{\"eventtrackers\": \"someWrongValue\"}"},
+			target:        map[string]interface{}{},
+			expectedError: fmt.Errorf("Eventtrackers are not present or not of array type"),
 		},
-	}
-
-	for _, test := range testStubs {
-		prim, alt, err := parseRubiconSizes(test.input)
-
-		assert.Equal(t, test.output.primary, prim,
-			"Error in parsing rubicon sizes: MAS algorithm fail at primary: testcase %v", test.input)
-
-		assert.Equal(t, len(test.output.alt), len(alt),
-			"Error in parsing rubicon sizes: MAS Algorithm fail at alt: testcase %v", test.input)
-
-		assert.False(t, err != nil && !test.output.ok,
-			"Error in parsing rubicon sizes: MAS Algorithm fail at throwing error: testcase %v", test.input)
-
-		assert.False(t, err == nil && test.output.ok,
-			"Error in parsing rubicon sizes: MAS Algorithm fail at throwing error: testcase %v", test.input)
-	}
-}
-
-func TestAppendTracker(t *testing.T) {
-	testScenarios := []rubiAppendTrackerUrlTestScenario{
 		{
-			source:   "http://test.url/",
-			tracker:  "prebid",
-			expected: "http://test.url/?tk_xint=prebid",
+			nativeObject:  openrtb2.Native{Ver: "1", Request: "{\"eventtrackers\": [], \"context\": \"someWrongValue\"}"},
+			target:        map[string]interface{}{},
+			expectedError: fmt.Errorf("Context is not present or not of int type"),
 		},
 		{
-			source:   "http://test.url/?hello=true",
-			tracker:  "prebid",
-			expected: "http://test.url/?hello=true&tk_xint=prebid",
+			nativeObject:  openrtb2.Native{Ver: "1", Request: "{\"eventtrackers\": [], \"context\": 1}"},
+			target:        map[string]interface{}{},
+			expectedError: fmt.Errorf("Plcmttype is not present or not of int type"),
 		},
 	}
-
 	for _, scenario := range testScenarios {
-		res := appendTrackerToUrl(scenario.source, scenario.tracker)
-		assert.Equal(t, scenario.expected, res, "Failed to convert '%s' to '%s'", res, scenario.expected)
+		_, err := resolveNativeObject(&scenario.nativeObject, scenario.target)
+		assert.Equal(t, scenario.expectedError, err)
 	}
 }
 
@@ -362,7 +244,6 @@ func TestOpenRTBRequestWithDifferentBidFloorAttributes(t *testing.T) {
 			CurrencyConversions: mockConversions,
 		}
 
-		SIZE_ID := getTestSizes()
 		bidder := new(RubiconAdapter)
 
 		request := &openrtb2.BidRequest{
@@ -373,8 +254,7 @@ func TestOpenRTBRequestWithDifferentBidFloorAttributes(t *testing.T) {
 				BidFloor:    scenario.bidFloor,
 				Banner: &openrtb2.Banner{
 					Format: []openrtb2.Format{
-						SIZE_ID[15],
-						SIZE_ID[10],
+						{W: 300, H: 250},
 					},
 				},
 				Ext: json.RawMessage(`{"bidder": {
@@ -421,7 +301,6 @@ func (m mockCurrencyConversion) GetRates() *map[string]map[string]float64 {
 }
 
 func TestOpenRTBRequest(t *testing.T) {
-	SIZE_ID := getTestSizes()
 	bidder := new(RubiconAdapter)
 
 	rubidata = rubiBidInfo{
@@ -439,8 +318,8 @@ func TestOpenRTBRequest(t *testing.T) {
 			ID: "test-imp-banner-id",
 			Banner: &openrtb2.Banner{
 				Format: []openrtb2.Format{
-					SIZE_ID[15],
-					SIZE_ID[10],
+					{W: 300, H: 250},
+					{W: 300, H: 600},
 				},
 			},
 			Ext: json.RawMessage(`{"bidder": {
@@ -564,7 +443,6 @@ func TestOpenRTBRequest(t *testing.T) {
 }
 
 func TestOpenRTBRequestWithBannerImpEvenIfImpHasVideo(t *testing.T) {
-	SIZE_ID := getTestSizes()
 	bidder := new(RubiconAdapter)
 
 	request := &openrtb2.BidRequest{
@@ -573,8 +451,7 @@ func TestOpenRTBRequestWithBannerImpEvenIfImpHasVideo(t *testing.T) {
 			ID: "test-imp-id",
 			Banner: &openrtb2.Banner{
 				Format: []openrtb2.Format{
-					SIZE_ID[15],
-					SIZE_ID[10],
+					{W: 300, H: 250},
 				},
 			},
 			Video: &openrtb2.Video{
@@ -615,7 +492,6 @@ func TestOpenRTBRequestWithBannerImpEvenIfImpHasVideo(t *testing.T) {
 }
 
 func TestOpenRTBRequestWithImpAndAdSlotIncluded(t *testing.T) {
-	SIZE_ID := getTestSizes()
 	bidder := new(RubiconAdapter)
 
 	request := &openrtb2.BidRequest{
@@ -624,8 +500,7 @@ func TestOpenRTBRequestWithImpAndAdSlotIncluded(t *testing.T) {
 			ID: "test-imp-id",
 			Banner: &openrtb2.Banner{
 				Format: []openrtb2.Format{
-					SIZE_ID[15],
-					SIZE_ID[10],
+					{W: 300, H: 250},
 				},
 			},
 			Ext: json.RawMessage(`{
@@ -720,7 +595,6 @@ func TestOpenRTBFirstPartyDataPopulating(t *testing.T) {
 }
 
 func TestOpenRTBRequestWithBadvOverflowed(t *testing.T) {
-	SIZE_ID := getTestSizes()
 	bidder := new(RubiconAdapter)
 
 	badvOverflowed := make([]string, 100)
@@ -735,7 +609,7 @@ func TestOpenRTBRequestWithBadvOverflowed(t *testing.T) {
 			ID: "test-imp-id",
 			Banner: &openrtb2.Banner{
 				Format: []openrtb2.Format{
-					SIZE_ID[15],
+					{W: 300, H: 250},
 				},
 			},
 			Ext: json.RawMessage(`{
@@ -766,7 +640,6 @@ func TestOpenRTBRequestWithBadvOverflowed(t *testing.T) {
 }
 
 func TestOpenRTBRequestWithSpecificExtUserEids(t *testing.T) {
-	SIZE_ID := getTestSizes()
 	bidder := new(RubiconAdapter)
 
 	request := &openrtb2.BidRequest{
@@ -775,8 +648,7 @@ func TestOpenRTBRequestWithSpecificExtUserEids(t *testing.T) {
 			ID: "test-imp-id",
 			Banner: &openrtb2.Banner{
 				Format: []openrtb2.Format{
-					SIZE_ID[15],
-					SIZE_ID[10],
+					{W: 300, H: 250},
 				},
 			},
 			Ext: json.RawMessage(`{"bidder": {
@@ -845,15 +717,6 @@ func TestOpenRTBRequestWithSpecificExtUserEids(t *testing.T) {
 	assert.NotNil(t, userExt.Eids)
 	assert.Equal(t, 4, len(userExt.Eids), "Eids values are not as expected!")
 
-	assert.NotNil(t, userExt.TpID)
-	assert.Equal(t, 2, len(userExt.TpID), "TpID values are not as expected!")
-
-	// adserver.org
-	assert.Equal(t, "tdid", userExt.TpID[0].Source, "TpID source value is not as expected!")
-
-	// liveintent.com
-	assert.Equal(t, "liveintent.com", userExt.TpID[1].Source, "TpID source value is not as expected!")
-
 	// liveramp.com
 	assert.Equal(t, "LIVERAMPID", userExt.LiverampIdl, "Liveramp_idl value is not as expected!")
 
@@ -868,7 +731,6 @@ func TestOpenRTBRequestWithSpecificExtUserEids(t *testing.T) {
 }
 
 func TestOpenRTBRequestWithVideoImpEvenIfImpHasBannerButAllRequiredVideoFields(t *testing.T) {
-	SIZE_ID := getTestSizes()
 	bidder := new(RubiconAdapter)
 
 	request := &openrtb2.BidRequest{
@@ -877,8 +739,7 @@ func TestOpenRTBRequestWithVideoImpEvenIfImpHasBannerButAllRequiredVideoFields(t
 			ID: "test-imp-id",
 			Banner: &openrtb2.Banner{
 				Format: []openrtb2.Format{
-					SIZE_ID[15],
-					SIZE_ID[10],
+					{W: 300, H: 250},
 				},
 			},
 			Video: &openrtb2.Video{
@@ -1165,10 +1026,11 @@ func TestOpenRTBResponseSettingOfNetworkId(t *testing.T) {
 		} else {
 			givenBidExt = nil
 		}
+
 		givenBidResponse := rubiconBidResponse{
 			SeatBid: []rubiconSeatBid{{Buyer: scenario.buyer,
-				SeatBid: openrtb2.SeatBid{
-					Bid: []openrtb2.Bid{{Price: 123.2, ImpID: "test-imp-id", Ext: givenBidExt}}}}},
+				Bid: []rubiconBid{{
+					Bid: openrtb2.Bid{Price: 123.2, ImpID: "test-imp-id", Ext: givenBidExt}}}}},
 		}
 		body, _ := json.Marshal(&givenBidResponse)
 		httpResp := &adapters.ResponseData{
diff --git a/adapters/rubicon/rubicontest/exemplary/simple-banner.json b/adapters/rubicon/rubicontest/exemplary/simple-banner.json
new file mode 100644
index 00000000..a37c0ae9
--- /dev/null
+++ b/adapters/rubicon/rubicontest/exemplary/simple-banner.json
@@ -0,0 +1,380 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    },
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "site": {
+      "pagecat": [
+        "val1",
+        "val2"
+      ],
+      "content": {
+        "data": [
+          {
+            "ext": {
+              "segtax": 1
+            },
+            "segment": [
+              {
+                "id": "segmentId1"
+              },
+              {
+                "id": "segmentId2"
+              }
+            ]
+          },
+          {
+            "ext": {
+              "segtax": "1"
+            },
+            "segment": [
+              {
+                "id": "shouldNotBeCopied"
+              }
+            ]
+          },
+          {
+            "ext": {
+              "segtax": 2
+            },
+            "segment": [
+              {
+                "id": "segmentId3"
+              }
+            ]
+          }
+        ]
+      }
+    },
+    "user": {
+      "yob": 2000,
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "gender": "f",
+      "data": [
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "someValue"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "4"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": [
+              4
+            ]
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied3"
+            }
+          ]
+        }
+      ]
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "instl": 1,
+        "banner": {
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "data": {
+            "pbadslot": "pbadslot"
+          },
+          "bidder": {
+            "accountId": 1001,
+            "siteId": 113932,
+            "zoneId": 535510
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "uri?tk_xint=pbs-test-tracker",
+        "body": {
+          "id": "test-request-id",
+          "device": {
+            "ext": {
+              "rp": {
+                "pixelratio": 0
+              }
+            },
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          },
+          "site": {
+            "pagecat": [
+              "val1",
+              "val2"
+            ],
+            "content": {
+              "data": [
+                {
+                  "ext": {
+                    "segtax": 1
+                  },
+                  "segment": [
+                    {
+                      "id": "segmentId1"
+                    },
+                    {
+                      "id": "segmentId2"
+                    }
+                  ]
+                },
+                {
+                  "ext": {
+                    "segtax": "1"
+                  },
+                  "segment": [
+                    {
+                      "id": "shouldNotBeCopied"
+                    }
+                  ]
+                },
+                {
+                  "ext": {
+                    "segtax": 2
+                  },
+                  "segment": [
+                    {
+                      "id": "segmentId3"
+                    }
+                  ]
+                }
+              ]
+            },
+            "ext": {
+              "rp": {
+                "site_id": 113932,
+                "target": {
+                  "iab": [
+                    "segmentId1",
+                    "segmentId2",
+                    "segmentId3"
+                  ]
+                }
+              }
+            },
+            "publisher": {
+              "ext": {
+                "rp": {
+                  "account_id": 1001
+                }
+              }
+            }
+          },
+          "user": {
+            "data": [
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "someValue"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "4"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": [
+                    4
+                  ]
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied3"
+                  }
+                ]
+              }
+            ],
+            "ext": {
+              "rp": {
+                "target": {
+                  "iab": [
+                    "idToCopy",
+                    "idToCopy2"
+                  ]
+                }
+              }
+            }
+          },
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "instl": 1,
+              "banner": {
+                "ext": {
+                  "rp": {
+                    "mime": "text/html"
+                  }
+                },
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "rp": {
+                  "target": {
+                    "pbadslot": "pbadslot",
+                    "pagecat": [
+                      "val1",
+                      "val2"
+                    ]
+                  },
+                  "track": {
+                    "mint": "",
+                    "mint_version": ""
+                  },
+                  "zone_id": 535510
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "buyer": "123",
+              "bid": [
+                {
+                  "id": "test_bid_id",
+                  "impid": "test-imp-id",
+                  "price": 0.27543,
+                  "adm": "some-test-ad",
+                  "cid": "test_cid",
+                  "crid": "test_crid",
+                  "dealid": "test_dealid",
+                  "ext": {
+                    "prebid": {
+                      "meta": {
+                        "networkId": 123
+                      },
+                      "type": "banner"
+                    }
+                  }
+                }
+              ],
+              "seat": "adman"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "some-test-ad",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "ext": {
+              "prebid": {
+                "meta": {
+                  "networkId": 123
+                },
+                "type": "banner"
+              }
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/rubicon/rubicontest/exemplary/simple-native.json b/adapters/rubicon/rubicontest/exemplary/simple-native.json
new file mode 100644
index 00000000..39f6295a
--- /dev/null
+++ b/adapters/rubicon/rubicontest/exemplary/simple-native.json
@@ -0,0 +1,385 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    },
+    "app": {
+      "id": "1",
+      "bundle": "com.wls.testwlsapplication"
+    },
+    "site": {
+      "pagecat": [
+        "val1",
+        "val2"
+      ],
+      "content": {
+        "data": [
+          {
+            "ext": {
+              "segtax": 1
+            },
+            "segment": [
+              {
+                "id": "segmentId1"
+              },
+              {
+                "id": "segmentId2"
+              }
+            ]
+          },
+          {
+            "ext": {
+              "segtax": "1"
+            },
+            "segment": [
+              {
+                "id": "shouldNotBeCopied"
+              }
+            ]
+          },
+          {
+            "ext": {
+              "segtax": 2
+            },
+            "segment": [
+              {
+                "id": "segmentId3"
+              }
+            ]
+          }
+        ]
+      }
+    },
+    "user": {
+      "yob": 2000,
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "gender": "f",
+      "data": [
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "someValue"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "4"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": [
+              4
+            ]
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied3"
+            }
+          ]
+        }
+      ]
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "instl": 1,
+        "native": {
+          "ver": "1.2",
+          "request": "{\"eventtrackers\":[],\"context\":1,\"plcmttype\":2}"
+        },
+        "ext": {
+          "data": {
+            "pbadslot": "pbadslot"
+          },
+          "bidder": {
+            "video": {
+            },
+            "accountId": 1001,
+            "siteId": 113932,
+            "zoneId": 535510
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "uri?tk_xint=pbs-test-tracker",
+        "body": {
+          "id": "test-request-id",
+          "device": {
+            "ext": {
+              "rp": {
+                "pixelratio": 0
+              }
+            },
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          },
+          "site": {
+            "pagecat": [
+              "val1",
+              "val2"
+            ],
+            "content": {
+              "data": [
+                {
+                  "ext": {
+                    "segtax": 1
+                  },
+                  "segment": [
+                    {
+                      "id": "segmentId1"
+                    },
+                    {
+                      "id": "segmentId2"
+                    }
+                  ]
+                },
+                {
+                  "ext": {
+                    "segtax": "1"
+                  },
+                  "segment": [
+                    {
+                      "id": "shouldNotBeCopied"
+                    }
+                  ]
+                },
+                {
+                  "ext": {
+                    "segtax": 2
+                  },
+                  "segment": [
+                    {
+                      "id": "segmentId3"
+                    }
+                  ]
+                }
+              ]
+            },
+            "ext": {
+              "rp": {
+                "site_id": 113932,
+                "target": {
+                  "iab": [
+                    "segmentId1",
+                    "segmentId2",
+                    "segmentId3"
+                  ]
+                }
+              }
+            },
+            "publisher": {
+              "ext": {
+                "rp": {
+                  "account_id": 1001
+                }
+              }
+            }
+          },
+          "user": {
+            "data": [
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "someValue"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "4"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": [
+                    4
+                  ]
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied3"
+                  }
+                ]
+              }
+            ],
+            "ext": {
+              "rp": {
+                "target": {
+                  "iab": [
+                    "idToCopy",
+                    "idToCopy2"
+                  ]
+                }
+              }
+            }
+          },
+          "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "instl": 1,
+              "native": {
+                "ver": "1.2",
+                "request": "{\"eventtrackers\":[],\"context\":1,\"plcmttype\":2}",
+                "request_native": {
+                  "context": 1,
+                  "eventtrackers": [
+                  ],
+                  "plcmttype": 2
+                }
+              },
+              "ext": {
+                "rp": {
+                  "target": {
+                    "pbadslot": "pbadslot",
+                    "pagecat": [
+                      "val1",
+                      "val2"
+                    ]
+                  },
+                  "track": {
+                    "mint": "",
+                    "mint_version": ""
+                  },
+                  "zone_id": 535510
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "buyer": "123",
+              "bid": [
+                {
+                  "id": "test_bid_id",
+                  "impid": "test-imp-id",
+                  "price": 0.27543,
+                  "cid": "test_cid",
+                  "crid": "test_crid",
+                  "dealid": "test_dealid",
+                  "admobject": {
+                    "property1": "value1"
+                  },
+                  "ext": {
+                    "prebid": {
+                      "meta": {
+                        "networkId": 123
+                      },
+                      "type": "native"
+                    }
+                  }
+                }
+              ],
+              "seat": "adman"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "{\"property1\":\"value1\"}",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "ext": {
+              "prebid": {
+                "meta": {
+                  "networkId": 123
+                },
+                "type": "native"
+              }
+            }
+          },
+          "type": "native"
+        }
+      ]
+    }
+  ]
+}
diff --git a/exchange/adapter_util_test.go b/exchange/adapter_util_test.go
index 01f11044..d98b1e11 100644
--- a/exchange/adapter_util_test.go
+++ b/exchange/adapter_util_test.go
@@ -207,42 +207,46 @@ func TestGetDisabledBiddersErrorMessages(t *testing.T) {
 			description: "None",
 			bidderInfos: map[string]config.BidderInfo{},
 			expected: map[string]string{
-				"lifestreet":   `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
-				"adagio":       `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
-				"somoaudience": `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-				"yssp":         `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+				"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
+				"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
+				"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
+				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+				"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
 			},
 		},
 		{
 			description: "Enabled",
 			bidderInfos: map[string]config.BidderInfo{"appnexus": infoEnabled},
 			expected: map[string]string{
-				"lifestreet":   `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
-				"adagio":       `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
-				"somoaudience": `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-				"yssp":         `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+				"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
+				"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
+				"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
+				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+				"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
 			},
 		},
 		{
 			description: "Disabled",
 			bidderInfos: map[string]config.BidderInfo{"appnexus": infoDisabled},
 			expected: map[string]string{
-				"lifestreet":   `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
-				"adagio":       `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
-				"somoaudience": `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-				"yssp":         `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
-				"appnexus":     `Bidder "appnexus" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`,
+				"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
+				"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
+				"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
+				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+				"appnexus":       `Bidder "appnexus" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`,
+				"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
 			},
 		},
 		{
 			description: "Mixed",
 			bidderInfos: map[string]config.BidderInfo{"appnexus": infoDisabled, "openx": infoEnabled},
 			expected: map[string]string{
-				"lifestreet":   `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
-				"adagio":       `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
-				"somoaudience": `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
-				"yssp":         `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
-				"appnexus":     `Bidder "appnexus" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`,
+				"lifestreet":     `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
+				"adagio":         `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
+				"somoaudience":   `Bidder "somoaudience" is no longer available in Prebid Server. Please update your configuration.`,
+				"yssp":           `Bidder "yssp" is no longer available in Prebid Server. If you're looking to use the Yahoo SSP adapter, please rename it to "yahoossp" in your configuration.`,
+				"appnexus":       `Bidder "appnexus" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`,
+				"andbeyondmedia": `Bidder "andbeyondmedia" is no longer available in Prebid Server. If you're looking to use the AndBeyond.Media SSP adapter, please rename it to "beyondmedia" in your configuration.`,
 			},
 		},
 	}