Repository: prebid/prebid-server
Pull request #1938 (2021-07-26 19:16:52)

Generate Unique Bidrequest IDs for Amp Auctions
Addressing this issue here https://github.com/prebid/prebid-server/issues/1507

I've added a configuration boolean flag, `GenerateRequestId`, which when set to true, will generate a uuid for auction bid requests, which can be used to solve the amp auction issue found here https://github.com/prebid/prebid-server/issues/1507

This generation can occur in two different functions:
1. In amp_auction.go/loadRequestJSONForAmp( ) -- where we load the stored openRTB request for an incoming AMP request. Here we can check our boolean flag, and generate an ID if necessary.
2. In auction.go/processStoredRequests() -- we check here if `GenerateRequestId` is true, and if so, we generate a uuid and patch it into the request


Patch:
diff --git a/Dockerfile b/Dockerfile
index defb64c8..6ce9a7df 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -20,7 +20,7 @@ RUN go mod vendor
 RUN go mod tidy
 ARG TEST="true"
 RUN if [ "$TEST" != "false" ]; then ./validate.sh ; fi
-RUN go build -mod=vendor .
+RUN go build -mod=vendor -ldflags "-X github.com/prebid/prebid-server/version.Ver=`git describe --tags | sed 's/^v//'` -X github.com/prebid/prebid-server/version.Rev=`git rev-parse HEAD`" .
 
 FROM ubuntu:18.04 AS release
 LABEL maintainer="hans.hjort@xandr.com" 
diff --git a/adapters/adprime/adprime.go b/adapters/adprime/adprime.go
index 70fbd6b3..c907380d 100644
--- a/adapters/adprime/adprime.go
+++ b/adapters/adprime/adprime.go
@@ -4,8 +4,8 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
+	"strings"
 
-	"github.com/buger/jsonparser"
 	"github.com/mxmCherry/openrtb/v15/openrtb2"
 	"github.com/prebid/prebid-server/adapters"
 	"github.com/prebid/prebid-server/config"
@@ -30,22 +30,63 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters
 func (a *AdprimeAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
 	var errs []error
 	var err error
-	var tagID string
 
 	var adapterRequests []*adapters.RequestData
 
+	var bidderExt adapters.ExtImpBidder
+	var adprimeExt openrtb_ext.ExtImpAdprime
+
 	reqCopy := *request
 	for _, imp := range request.Imp {
 		reqCopy.Imp = []openrtb2.Imp{imp}
 
-		tagID, err = jsonparser.GetString(reqCopy.Imp[0].Ext, "bidder", "TagID")
+		err = json.Unmarshal(reqCopy.Imp[0].Ext, &bidderExt)
+		if err != nil {
+			errs = append(errs, err)
+			return nil, errs
+		}
+
+		err = json.Unmarshal(bidderExt.Bidder, &adprimeExt)
 		if err != nil {
 			errs = append(errs, err)
-			continue
+			return nil, errs
 		}
 
+		// tagId
+		tagID := adprimeExt.TagID
 		reqCopy.Imp[0].TagID = tagID
 
+		// placementId
+		newExt, err := json.Marshal(
+			map[string]interface{}{
+				"bidder": map[string]interface{}{
+					"TagID":       tagID,
+					"placementId": tagID,
+				},
+			})
+		if err != nil {
+			errs = append(errs, err)
+			return nil, errs
+		}
+		reqCopy.Imp[0].Ext = newExt
+
+		// keywords
+		if reqCopy.Site != nil && len(adprimeExt.Keywords) > 0 {
+			siteCopy := *reqCopy.Site
+			siteCopy.Keywords = strings.Join(adprimeExt.Keywords, ",")
+			reqCopy.Site = &siteCopy
+		}
+
+		// audiences
+		if reqCopy.Site != nil && len(adprimeExt.Audiences) > 0 {
+			if reqCopy.User == nil {
+				reqCopy.User = &openrtb2.User{}
+			}
+			userCopy := *reqCopy.User
+			userCopy.CustomData = strings.Join(adprimeExt.Audiences, ",")
+			reqCopy.User = &userCopy
+		}
+
 		adapterReq, errors := a.makeRequest(&reqCopy)
 		if adapterReq != nil {
 			adapterRequests = append(adapterRequests, adapterReq)
@@ -123,18 +164,21 @@ func (a *AdprimeAdapter) MakeBids(internalRequest *openrtb2.BidRequest, external
 }
 
 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.Banner == nil && imp.Video != nil {
-				mediaType = openrtb_ext.BidTypeVideo
+			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 mediaType, nil
 		}
 	}
 
-	// This shouldnt happen. Lets handle it just incase by returning an error.
 	return "", &errortypes.BadInput{
-		Message: fmt.Sprintf("Failed to find impression \"%s\" ", impID),
+		Message: fmt.Sprintf("Failed to find impression \"%s\"", impID),
 	}
 }
diff --git a/adapters/adview/adview.go b/adapters/adview/adview.go
new file mode 100644
index 00000000..c3e78b42
--- /dev/null
+++ b/adapters/adview/adview.go
@@ -0,0 +1,141 @@
+package adview
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"text/template"
+
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/macros"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+type adapter struct {
+	endpoint *template.Template
+}
+
+// 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) (adapters.Bidder, error) {
+	endpointTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint)
+	if err != nil {
+		return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
+	}
+
+	bidder := &adapter{
+		endpoint: endpointTemplate,
+	}
+	return bidder, nil
+}
+
+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
+		}
+	}
+
+	url, err := a.buildEndpointURL(&advImpExt)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	reqJSON, err := json.Marshal(request)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	return []*adapters.RequestData{{
+		Method: http.MethodPost,
+		Body:   reqJSON,
+		Uri:    url,
+	}}, nil
+}
+
+func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	if responseData.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if responseData.StatusCode == http.StatusBadRequest {
+		err := &errortypes.BadInput{
+			Message: "Unexpected status code: 400. Bad request from publisher.",
+		}
+		return nil, []error{err}
+	}
+
+	if responseData.StatusCode != http.StatusOK {
+		err := &errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Unexpected status code: %d.", responseData.StatusCode),
+		}
+		return nil, []error{err}
+	}
+
+	var response openrtb2.BidResponse
+	if err := json.Unmarshal(responseData.Body, &response); err != nil {
+		return nil, []error{err}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp))
+	bidResponse.Currency = response.Cur
+	var errors []error
+	for _, seatBid := range response.SeatBid {
+		for i, bid := range seatBid.Bid {
+			bidType, err := getMediaTypeForImp(bid.ImpID, request.Imp)
+			if err != nil {
+				errors = append(errors, err)
+				continue
+			}
+			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+				Bid:     &seatBid.Bid[i],
+				BidType: bidType,
+			})
+		}
+	}
+
+	return bidResponse, errors
+}
+
+// Builds endpoint url based on adapter-specific pub settings from imp.ext
+func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtImpAdView) (string, error) {
+	endpointParams := macros.EndpointTemplateParams{AccountID: params.AccountID}
+	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
+		}
+	}
+	return mediaType, nil
+}
diff --git a/adapters/improvedigital/improvedigital.go b/adapters/improvedigital/improvedigital.go
index 9b2d571d..d6318223 100644
--- a/adapters/improvedigital/improvedigital.go
+++ b/adapters/improvedigital/improvedigital.go
@@ -18,23 +18,38 @@ type ImprovedigitalAdapter struct {
 
 // MakeRequests makes the HTTP requests which should be made to fetch bids.
 func (a *ImprovedigitalAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
-	var errors = make([]error, 0)
+	numRequests := len(request.Imp)
+	errors := make([]error, 0)
+	adapterRequests := make([]*adapters.RequestData, 0, numRequests)
+
+	// Split multi-imp request into multiple ad server requests. SRA is currently not recommended.
+	for i := 0; i < numRequests; i++ {
+		if adapterReq, err := a.makeRequest(*request, request.Imp[i]); err == nil {
+			adapterRequests = append(adapterRequests, adapterReq)
+		} else {
+			errors = append(errors, err)
+		}
+	}
+
+	return adapterRequests, errors
+}
 
+func (a *ImprovedigitalAdapter) makeRequest(request openrtb2.BidRequest, imp openrtb2.Imp) (*adapters.RequestData, error) {
+	request.Imp = []openrtb2.Imp{imp}
 	reqJSON, err := json.Marshal(request)
 	if err != nil {
-		errors = append(errors, err)
-		return nil, errors
+		return nil, err
 	}
 
 	headers := http.Header{}
 	headers.Add("Content-Type", "application/json;charset=utf-8")
 
-	return []*adapters.RequestData{{
+	return &adapters.RequestData{
 		Method:  "POST",
 		Uri:     a.endpoint,
 		Body:    reqJSON,
 		Headers: headers,
-	}}, errors
+	}, nil
 }
 
 // MakeBids unpacks the server's response into Bids.
diff --git a/adapters/visx/visx.go b/adapters/visx/visx.go
index 8e2b10f7..f0b25b4a 100644
--- a/adapters/visx/visx.go
+++ b/adapters/visx/visx.go
@@ -102,9 +102,14 @@ func (a *VisxAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalReq
 			bid.ADomain = sb.Bid[i].ADomain
 			bid.DealID = sb.Bid[i].DealID
 
+			bidType, err := getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp)
+			if err != nil {
+				return nil, []error{err}
+			}
+
 			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
 				Bid:     &bid,
-				BidType: "banner",
+				BidType: bidType,
 			})
 		}
 	}
@@ -112,6 +117,29 @@ func (a *VisxAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalReq
 
 }
 
+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
+			}
+
+			return "", &errortypes.BadServerResponse{
+				Message: fmt.Sprintf("Unknown impression type for ID: \"%s\"", impID),
+			}
+		}
+	}
+
+	// This shouldnt happen. Lets handle it just incase by returning an error.
+	return "", &errortypes.BadServerResponse{
+		Message: fmt.Sprintf("Failed to find impression for ID: \"%s\"", impID),
+	}
+}
+
 // Builder builds a new instance of the Visx adapter for the given bidder with the given config.
 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
 	bidder := &VisxAdapter{
diff --git a/config/config.go b/config/config.go
index 20a53108..f6f6f187 100644
--- a/config/config.go
+++ b/config/config.go
@@ -83,6 +83,8 @@ type Configuration struct {
 	AutoGenSourceTID bool `mapstructure:"auto_gen_source_tid"`
 	//When true, new bid id will be generated in seatbid[].bid[].ext.prebid.bidid and used in event urls instead
 	GenerateBidID bool `mapstructure:"generate_bid_id"`
+	// GenerateRequestID overrides the bidrequest.id in an AMP Request or an App Stored Request with a generated UUID if set to true. The default is false.
+	GenerateRequestID bool `mapstructure:"generate_request_id"`
 }
 
 const MIN_COOKIE_SIZE_BYTES = 500
@@ -148,7 +150,7 @@ func (data *ExternalCache) validate(errs []error) []error {
 	if strings.HasSuffix(data.Host, "/") {
 		return append(errs, errors.New(fmt.Sprintf("External cache Host '%s' must not end with a path separator", data.Host)))
 	}
-	if strings.ContainsAny(data.Host, "://") {
+	if strings.Contains(data.Host, "://") {
 		return append(errs, errors.New(fmt.Sprintf("External cache Host must not specify a protocol. '%s'", data.Host)))
 	}
 	if !strings.HasPrefix(data.Path, "/") {
@@ -753,10 +755,11 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.adoppler.endpoint", "http://{{.AccountID}}.trustedmarketplace.io/ads/processHeaderBid/{{.AdUnit}}")
 	v.SetDefault("adapters.adot.endpoint", "https://dsp.adotmob.com/headerbidding/bidrequest")
 	v.SetDefault("adapters.adpone.endpoint", "http://rtb.adpone.com/bid-request?src=prebid_server")
-	v.SetDefault("adapters.adprime.endpoint", "http://delta.adprime.com/?c=o&m=ortb")
+	v.SetDefault("adapters.adprime.endpoint", "http://delta.adprime.com/pserver")
 	v.SetDefault("adapters.adtarget.endpoint", "http://ghb.console.adtarget.com.tr/pbs/ortb")
 	v.SetDefault("adapters.adtelligent.endpoint", "http://ghb.adtelligent.com/pbs/ortb")
 	v.SetDefault("adapters.advangelists.endpoint", "http://nep.advangelists.com/xp/get?pubid={{.PublisherID}}")
+	v.SetDefault("adapters.adview.endpoint", "https://bid.adview.com/agent/thirdAdxService/{{.AccountID}}")
 	v.SetDefault("adapters.adxcg.disabled", true)
 	v.SetDefault("adapters.adyoulike.endpoint", "https://broker.omnitagjs.com/broker/bid?partnerId=19340f4f097d16f41f34fc0274981ca4")
 	v.SetDefault("adapters.aja.endpoint", "https://ad.as.amanad.adtdp.com/v1/bid/4")
@@ -864,7 +867,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.valueimpression.endpoint", "https://rtb.valueimpression.com/endpoint")
 	v.SetDefault("adapters.verizonmedia.disabled", true)
 	v.SetDefault("adapters.viewdeos.endpoint", "http://ghb.sync.viewdeos.com/pbs/ortb")
-	v.SetDefault("adapters.visx.endpoint", "https://t.visx.net/s2s_bid?wrapperType=s2s_prebid_standard")
+	v.SetDefault("adapters.visx.endpoint", "https://t.visx.net/s2s_bid?wrapperType=s2s_prebid_standard:0.1.0")
 	v.SetDefault("adapters.vrtcal.endpoint", "http://rtb.vrtcal.com/bidder_prebid.vap?ssp=1804")
 	v.SetDefault("adapters.yeahmobi.endpoint", "https://{{.Host}}/prebid/bid")
 	v.SetDefault("adapters.yieldlab.endpoint", "https://ad.yieldlab.net/yp/")
@@ -943,6 +946,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("certificates_file", "")
 	v.SetDefault("auto_gen_source_tid", true)
 	v.SetDefault("generate_bid_id", false)
+	v.SetDefault("generate_request_id", false)
 
 	v.SetDefault("request_timeout_headers.request_time_in_queue", "")
 	v.SetDefault("request_timeout_headers.request_timeout_in_queue", "")
diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go
index 7a0afb0d..159e8a15 100644
--- a/endpoints/openrtb2/amp_auction.go
+++ b/endpoints/openrtb2/amp_auction.go
@@ -31,6 +31,7 @@ import (
 	"github.com/golang/glog"
 	"github.com/julienschmidt/httprouter"
 	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/prebid/prebid-server/util/uuidutil"
 )
 
 const defaultAmpRequestTimeoutMillis = 900
@@ -45,6 +46,7 @@ type AmpResponse struct {
 // NewAmpEndpoint modifies the OpenRTB endpoint to handle AMP requests. This will basically modify the parsing
 // of the request, and the return value, using the OpenRTB machinery to handle everything in between.
 func NewAmpEndpoint(
+	uuidGenerator uuidutil.UUIDGenerator,
 	ex exchange.Exchange,
 	validator openrtb_ext.BidderParamValidator,
 	requestsById stored_requests.Fetcher,
@@ -69,6 +71,7 @@ func NewAmpEndpoint(
 	}
 
 	return httprouter.Handle((&endpointDeps{
+		uuidGenerator,
 		ex,
 		validator,
 		requestsById,
@@ -345,6 +348,15 @@ func (deps *endpointDeps) loadRequestJSONForAmp(httpRequest *http.Request) (req
 		return
 	}
 
+	if deps.cfg.GenerateRequestID {
+		newBidRequestId, err := deps.uuidGenerator.Generate()
+		if err != nil {
+			errs = []error{err}
+			return
+		}
+		req.ID = newBidRequestId
+	}
+
 	if ampParams.Debug {
 		req.Test = 1
 	}
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index 1d879443..579d6687 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -14,7 +14,7 @@ import (
 	"time"
 
 	"github.com/buger/jsonparser"
-	"github.com/evanphx/json-patch"
+	jsonpatch "github.com/evanphx/json-patch"
 	"github.com/gofrs/uuid"
 	"github.com/golang/glog"
 	"github.com/julienschmidt/httprouter"
@@ -36,6 +36,7 @@ import (
 	"github.com/prebid/prebid-server/usersync"
 	"github.com/prebid/prebid-server/util/httputil"
 	"github.com/prebid/prebid-server/util/iputil"
+	"github.com/prebid/prebid-server/util/uuidutil"
 	"golang.org/x/net/publicsuffix"
 	"golang.org/x/text/currency"
 )
@@ -49,6 +50,7 @@ var (
 )
 
 func NewEndpoint(
+	uuidGenerator uuidutil.UUIDGenerator,
 	ex exchange.Exchange,
 	validator openrtb_ext.BidderParamValidator,
 	requestsById stored_requests.Fetcher,
@@ -72,6 +74,7 @@ func NewEndpoint(
 	}
 
 	return httprouter.Handle((&endpointDeps{
+		uuidGenerator,
 		ex,
 		validator,
 		requestsById,
@@ -90,6 +93,7 @@ func NewEndpoint(
 }
 
 type endpointDeps struct {
+	uuidGenerator             uuidutil.UUIDGenerator
 	ex                        exchange.Exchange
 	paramsValidator           openrtb_ext.BidderParamValidator
 	storedReqFetcher          stored_requests.Fetcher
@@ -1354,21 +1358,34 @@ func (deps *endpointDeps) processStoredRequests(ctx context.Context, requestJson
 
 	// Apply the Stored BidRequest, if it exists
 	resolvedRequest := requestJson
-	if hasStoredBidRequest {
-		resolvedRequest, err = jsonpatch.MergePatch(storedRequests[storedBidRequestId], requestJson)
+
+	if deps.cfg.GenerateRequestID {
+		isAppRequest, err := checkIfAppRequest(requestJson)
 		if err != nil {
-			hasErr, Err := getJsonSyntaxError(requestJson)
-			if hasErr {
-				err = fmt.Errorf("Invalid JSON in Incoming Request: %s", Err)
-			} else {
-				hasErr, Err = getJsonSyntaxError(storedRequests[storedBidRequestId])
-				if hasErr {
-					err = fmt.Errorf("Invalid JSON in Stored Request with ID %s: %s", storedBidRequestId, Err)
-					err = fmt.Errorf("ext.prebid.storedrequest.id refers to Stored Request %s which contains Invalid JSON: %s", storedBidRequestId, Err)
-				}
-			}
 			return nil, nil, []error{err}
 		}
+		if isAppRequest && hasStoredBidRequest {
+			uuidPatch, err := generateUuidForBidRequest(deps.uuidGenerator)
+			if err != nil {
+				return nil, nil, []error{err}
+			}
+			uuidPatch, err = jsonpatch.MergePatch(storedRequests[storedBidRequestId], uuidPatch)
+			if err != nil {
+				errL := storedRequestErrorChecker(requestJson, storedRequests, storedBidRequestId)
+				return nil, nil, errL
+			}
+			resolvedRequest, err = jsonpatch.MergePatch(requestJson, uuidPatch)
+			if err != nil {
+				errL := storedRequestErrorChecker(requestJson, storedRequests, storedBidRequestId)
+				return nil, nil, errL
+			}
+		}
+	} else if hasStoredBidRequest {
+		resolvedRequest, err = jsonpatch.MergePatch(storedRequests[storedBidRequestId], requestJson)
+		if err != nil {
+			errL := storedRequestErrorChecker(requestJson, storedRequests, storedBidRequestId)
+			return nil, nil, errL
+		}
 	}
 
 	// Apply default aliases, if they are provided
@@ -1471,7 +1488,8 @@ type ImpExtPrebidData struct {
 // (e.g. malformed json, id not a string, etc).
 func getStoredRequestId(data []byte) (string, bool, error) {
 	// These keys must be kept in sync with openrtb_ext.ExtStoredRequest
-	value, dataType, _, err := jsonparser.Get(data, "ext", openrtb_ext.PrebidExtKey, "storedrequest", "id")
+	storedRequestId, dataType, _, err := jsonparser.Get(data, "ext", openrtb_ext.PrebidExtKey, "storedrequest", "id")
+
 	if dataType == jsonparser.NotExist {
 		return "", false, nil
 	}
@@ -1481,8 +1499,7 @@ func getStoredRequestId(data []byte) (string, bool, error) {
 	if dataType != jsonparser.String {
 		return "", true, errors.New("ext.prebid.storedrequest.id must be a string")
 	}
-
-	return string(value), true, nil
+	return string(storedRequestId), true, nil
 }
 
 // setIPImplicitly sets the IP address on bidReq, if it's not explicitly defined and we can figure it out.
@@ -1584,3 +1601,35 @@ func getAccountID(pub *openrtb2.Publisher) string {
 	}
 	return metrics.PublisherUnknown
 }
+
+func storedRequestErrorChecker(requestJson []byte, storedRequests map[string]json.RawMessage, storedBidRequestId string) []error {
+	if hasErr, syntaxErr := getJsonSyntaxError(requestJson); hasErr {
+		return []error{fmt.Errorf("Invalid JSON in Incoming Request: %s", syntaxErr)}
+	}
+	if hasErr, syntaxErr := getJsonSyntaxError(storedRequests[storedBidRequestId]); hasErr {
+		return []error{fmt.Errorf("ext.prebid.storedrequest.id refers to Stored Request %s which contains Invalid JSON: %s", storedBidRequestId, syntaxErr)}
+	}
+	return nil
+}
+
+func generateUuidForBidRequest(uuidGenerator uuidutil.UUIDGenerator) ([]byte, error) {
+	newBidRequestID, err := uuidGenerator.Generate()
+	if err != nil {
+		return nil, err
+	}
+	return []byte(`{"id":"` + newBidRequestID + `"}`), nil
+}
+
+func checkIfAppRequest(request []byte) (bool, error) {
+	requestApp, dataType, _, err := jsonparser.Get(request, "app")
+	if dataType == jsonparser.NotExist {
+		return false, nil
+	}
+	if err != nil {
+		return false, err
+	}
+	if requestApp != nil {
+		return true, nil
+	}
+	return false, nil
+}
diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go
index c7e3dfbd..56c67c4d 100644
--- a/endpoints/openrtb2/video_auction.go
+++ b/endpoints/openrtb2/video_auction.go
@@ -20,6 +20,7 @@ import (
 	"github.com/mxmCherry/openrtb/v15/openrtb2"
 	"github.com/prebid/prebid-server/errortypes"
 	"github.com/prebid/prebid-server/util/iputil"
+	"github.com/prebid/prebid-server/util/uuidutil"
 
 	"github.com/golang/glog"
 	"github.com/julienschmidt/httprouter"
@@ -37,6 +38,7 @@ import (
 var defaultRequestTimeout int64 = 5000
 
 func NewVideoEndpoint(
+	uuidGenerator uuidutil.UUIDGenerator,
 	ex exchange.Exchange,
 	validator openrtb_ext.BidderParamValidator,
 	requestsById stored_requests.Fetcher,
@@ -65,6 +67,7 @@ func NewVideoEndpoint(
 	videoEndpointRegexp := regexp.MustCompile(`[<>]`)
 
 	return httprouter.Handle((&endpointDeps{
+		uuidGenerator,
 		ex,
 		validator,
 		requestsById,
diff --git a/endpoints/version.go b/endpoints/version.go
index d3cda6b6..514791e2 100644
--- a/endpoints/version.go
+++ b/endpoints/version.go
@@ -8,18 +8,23 @@ import (
 )
 
 type versionModel struct {
+	Version  string `json:"version"`
 	Revision string `json:"revision"`
 }
 
-// NewVersionEndpoint returns the latest commit sha1 from which the binary was built
-func NewVersionEndpoint(version string) http.HandlerFunc {
+// NewVersionEndpoint returns the latest git tag as the version and commit hash as the revision from which the binary was built
+func NewVersionEndpoint(version string, revision string) http.HandlerFunc {
 	if version == "" {
 		version = "not-set"
 	}
+	if revision == "" {
+		revision = "not-set"
+	}
 
 	return func(w http.ResponseWriter, _ *http.Request) {
 		jsonOutput, err := json.Marshal(versionModel{
-			Revision: version,
+			Version:  version,
+			Revision: revision,
 		})
 		if err != nil {
 			glog.Errorf("/version Critical error when trying to marshal versionModel: %v", err)
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 894b6754..630f18b6 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -22,6 +22,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/adtarget"
 	"github.com/prebid/prebid-server/adapters/adtelligent"
 	"github.com/prebid/prebid-server/adapters/advangelists"
+	"github.com/prebid/prebid-server/adapters/adview"
 	"github.com/prebid/prebid-server/adapters/adxcg"
 	"github.com/prebid/prebid-server/adapters/adyoulike"
 	"github.com/prebid/prebid-server/adapters/aja"
@@ -153,6 +154,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderAdtarget:          adtarget.Builder,
 		openrtb_ext.BidderAdtelligent:       adtelligent.Builder,
 		openrtb_ext.BidderAdvangelists:      advangelists.Builder,
+		openrtb_ext.BidderAdView:            adview.Builder,
 		openrtb_ext.BidderAdxcg:             adxcg.Builder,
 		openrtb_ext.BidderAdyoulike:         adyoulike.Builder,
 		openrtb_ext.BidderAJA:               aja.Builder,
diff --git a/exchange/bidder.go b/exchange/bidder.go
index 895cff93..28be854c 100644
--- a/exchange/bidder.go
+++ b/exchange/bidder.go
@@ -15,6 +15,7 @@ import (
 	"github.com/golang/glog"
 	"github.com/prebid/prebid-server/config/util"
 	"github.com/prebid/prebid-server/currency"
+	"github.com/prebid/prebid-server/version"
 
 	nativeRequests "github.com/mxmCherry/openrtb/v15/native1/request"
 	nativeResponse "github.com/mxmCherry/openrtb/v15/native1/response"
@@ -138,17 +139,17 @@ func (bidder *bidderAdapter) requestBid(ctx context.Context, request *openrtb2.B
 		}
 		return nil, errs
 	}
+	xPrebidHeader := buildXPrebidHeader(request, version.Ver)
 
-	if reqInfo.GlobalPrivacyControlHeader == "1" {
-		for i := 0; i < len(reqData); i++ {
-			if reqData[i].Headers != nil {
-				reqHeader := reqData[i].Headers.Clone()
-				reqHeader.Add("Sec-GPC", reqInfo.GlobalPrivacyControlHeader)
-				reqData[i].Headers = reqHeader
-			} else {
-				reqData[i].Headers = http.Header{}
-				reqData[i].Headers.Add("Sec-GPC", reqInfo.GlobalPrivacyControlHeader)
-			}
+	for i := 0; i < len(reqData); i++ {
+		if reqData[i].Headers != nil {
+			reqData[i].Headers = reqData[i].Headers.Clone()
+		} else {
+			reqData[i].Headers = http.Header{}
+		}
+		reqData[i].Headers.Add("X-Prebid", xPrebidHeader)
+		if reqInfo.GlobalPrivacyControlHeader == "1" {
+			reqData[i].Headers.Add("Sec-GPC", reqInfo.GlobalPrivacyControlHeader)
 		}
 	}
 
diff --git a/exchange/exchange.go b/exchange/exchange.go
index c612a35b..f6ec713f 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -24,6 +24,7 @@ import (
 	"github.com/prebid/prebid-server/prebid_cache_client"
 	"github.com/prebid/prebid-server/stored_requests"
 	"github.com/prebid/prebid-server/usersync"
+	"github.com/prebid/prebid-server/util/maputil"
 
 	"github.com/buger/jsonparser"
 	"github.com/gofrs/uuid"
@@ -966,9 +967,6 @@ func (e *exchange) makeBid(bids []*pbsOrtbBid, auc *auction, returnCreative bool
 }
 
 func makeBidExtJSON(ext json.RawMessage, prebid *openrtb_ext.ExtBidPrebid, impExtInfoMap map[string]ImpExtInfo, impId string) (json.RawMessage, error) {
-	// update existing bid.ext with prebid section
-	// if bid.ext.prebid already exists, it will be overwritten.
-	// if echoVideoAttrs set to true stored video attributes will be added to bid.ext.storedrequestattributes
 	var extMap map[string]interface{}
 
 	if len(ext) != 0 {
@@ -979,10 +977,22 @@ func makeBidExtJSON(ext json.RawMessage, prebid *openrtb_ext.ExtBidPrebid, impEx
 		extMap = make(map[string]interface{})
 	}
 
+	// ext.prebid
+	if prebid.Meta == nil && maputil.HasElement(extMap, "prebid", "meta") {
+		metaContainer := struct {
+			Prebid struct {
+				Meta openrtb_ext.ExtBidPrebidMeta `json:"meta"`
+			} `json:"prebid"`
+		}{}
+		if err := json.Unmarshal(ext, &metaContainer); err != nil {
+			return nil, fmt.Errorf("error validaing response from server, %s", err)
+		}
+		prebid.Meta = &metaContainer.Prebid.Meta
+	}
 	extMap[openrtb_ext.PrebidExtKey] = prebid
 
+	// ext.storedrequestattributes
 	if impExtInfo, ok := impExtInfoMap[impId]; ok && impExtInfo.EchoVideoAttrs {
-
 		videoData, _, _, err := jsonparser.Get(impExtInfo.StoredImp, "video")
 		if err != nil && err != jsonparser.KeyPathNotFoundError {
 			return nil, err
diff --git a/exchange/utils.go b/exchange/utils.go
index f33f1b91..1277cffd 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -5,6 +5,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"math/rand"
+	"strings"
 
 	"github.com/mxmCherry/openrtb/v15/openrtb2"
 	"github.com/prebid/go-gdpr/vendorconsent"
@@ -700,3 +701,39 @@ func getExtBidAdjustmentFactors(requestExt *openrtb_ext.ExtRequest) map[string]f
 	}
 	return bidAdjustmentFactors
 }
+
+func buildXPrebidHeader(bidRequest *openrtb2.BidRequest, version string) string {
+	req := &openrtb_ext.RequestWrapper{BidRequest: bidRequest}
+
+	sb := &strings.Builder{}
+	writeNameVersionRecord(sb, "pbs-go", version)
+
+	if reqExt, err := req.GetRequestExt(); err == nil && reqExt != nil {
+		if prebidExt := reqExt.GetPrebid(); prebidExt != nil {
+			if channel := prebidExt.Channel; channel != nil {
+				writeNameVersionRecord(sb, channel.Name, channel.Version)
+			}
+		}
+	}
+	if appExt, err := req.GetAppExt(); err == nil && appExt != nil {
+		if prebidExt := appExt.GetPrebid(); prebidExt != nil {
+			writeNameVersionRecord(sb, prebidExt.Source, prebidExt.Version)
+		}
+	}
+	return sb.String()
+}
+
+func writeNameVersionRecord(sb *strings.Builder, name, version string) {
+	if name == "" {
+		return
+	}
+	if version == "" {
+		version = "unknown"
+	}
+	if sb.Len() != 0 {
+		sb.WriteString(",")
+	}
+	sb.WriteString(name)
+	sb.WriteString("/")
+	sb.WriteString(version)
+}
diff --git a/main.go b/main.go
index 5c5a2a46..6087c3d6 100644
--- a/main.go
+++ b/main.go
@@ -17,14 +17,6 @@ import (
 	"github.com/spf13/viper"
 )
 
-// Rev holds binary revision string
-// Set manually at build time using:
-//    go build -ldflags "-X main.Rev=`git rev-parse --short HEAD`"
-// Populated automatically at build / releases
-//   `gox -os="linux" -arch="386" -output="{{.Dir}}_{{.OS}}_{{.Arch}}" -ldflags "-X main.Rev=`git rev-parse --short HEAD`" -verbose ./...;`
-// See issue #559
-var Rev string
-
 func init() {
 	rand.Seed(time.Now().UnixNano())
 }
@@ -37,7 +29,7 @@ func main() {
 		glog.Exitf("Configuration could not be loaded or did not pass validation: %v", err)
 	}
 
-	err = serve(Rev, cfg)
+	err = serve(cfg)
 	if err != nil {
 		glog.Exitf("prebid-server failed: %v", err)
 	}
@@ -51,7 +43,7 @@ func loadConfig() (*config.Configuration, error) {
 	return config.New(v)
 }
 
-func serve(revision string, cfg *config.Configuration) error {
+func serve(cfg *config.Configuration) error {
 	fetchingInterval := time.Duration(cfg.CurrencyConverter.FetchIntervalSeconds) * time.Second
 	staleRatesThreshold := time.Duration(cfg.CurrencyConverter.StaleRatesSeconds) * time.Second
 	currencyConverter := currency.NewRateConverter(&http.Client{}, cfg.CurrencyConverter.FetchURL, staleRatesThreshold)
@@ -67,7 +59,7 @@ func serve(revision string, cfg *config.Configuration) error {
 	pbc.InitPrebidCache(cfg.CacheURL.GetBaseURL())
 
 	corsRouter := router.SupportCORS(r)
-	server.Listen(cfg, router.NoCache{Handler: corsRouter}, router.Admin(revision, currencyConverter, fetchingInterval), r.MetricsEngine)
+	server.Listen(cfg, router.NoCache{Handler: corsRouter}, router.Admin(currencyConverter, fetchingInterval), r.MetricsEngine)
 
 	r.Shutdown()
 	return nil
diff --git a/openrtb_ext/bid.go b/openrtb_ext/bid.go
index ce6e25fd..7c73fb0d 100644
--- a/openrtb_ext/bid.go
+++ b/openrtb_ext/bid.go
@@ -1,6 +1,7 @@
 package openrtb_ext
 
 import (
+	"encoding/json"
 	"fmt"
 )
 
@@ -38,18 +39,20 @@ type ExtBidPrebidCacheBids struct {
 
 // ExtBidPrebidMeta defines the contract for bidresponse.seatbid.bid[i].ext.prebid.meta
 type ExtBidPrebidMeta struct {
-	AdvertiserDomains    []string `json:"advertiserDomains,omitempty"` // or advertiserDomain?
-	AdvertiserID         int      `json:"advertiserId,omitempty"`
-	AdvertiserName       string   `json:"advertiserName,omitempty"`
-	AgencyID             int      `json:"agencyId,omitempty"`
-	AgencyName           string   `json:"agencyName,omitempty"`
-	BrandID              int      `json:"brandId,omitempty"`
-	BrandName            string   `json:"brandName,omitempty"`
-	MediaType            string   `json:"mediaType,omitempty"`
-	NetworkID            int      `json:"networkId,omitempty"`
-	NetworkName          string   `json:"networkName,omitempty"`
-	PrimaryCategoryID    string   `json:"primaryCatId,omitempty"`
-	SecondaryCategoryIDs []string `json:"secondaryCatIds,omitempty"`
+	AdvertiserDomains    []string        `json:"advertiserDomains,omitempty"`
+	AdvertiserID         int             `json:"advertiserId,omitempty"`
+	AdvertiserName       string          `json:"advertiserName,omitempty"`
+	AgencyID             int             `json:"agencyId,omitempty"`
+	AgencyName           string          `json:"agencyName,omitempty"`
+	BrandID              int             `json:"brandId,omitempty"`
+	BrandName            string          `json:"brandName,omitempty"`
+	DemandSource         string          `json:"demandSource,omitempty"`
+	DChain               json.RawMessage `json:"dchain,omitempty"`
+	MediaType            string          `json:"mediaType,omitempty"`
+	NetworkID            int             `json:"networkId,omitempty"`
+	NetworkName          string          `json:"networkName,omitempty"`
+	PrimaryCategoryID    string          `json:"primaryCatId,omitempty"`
+	SecondaryCategoryIDs []string        `json:"secondaryCatIds,omitempty"`
 }
 
 // ExtBidPrebidVideo defines the contract for bidresponse.seatbid.bid[i].ext.prebid.video
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index f03ce21c..88f816c2 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -93,6 +93,7 @@ const (
 	BidderAdtarget          BidderName = "adtarget"
 	BidderAdtelligent       BidderName = "adtelligent"
 	BidderAdvangelists      BidderName = "advangelists"
+	BidderAdView            BidderName = "adview"
 	BidderAdxcg             BidderName = "adxcg"
 	BidderAdyoulike         BidderName = "adyoulike"
 	BidderAJA               BidderName = "aja"
@@ -225,6 +226,7 @@ func CoreBidderNames() []BidderName {
 		BidderAdtarget,
 		BidderAdtelligent,
 		BidderAdvangelists,
+		BidderAdView,
 		BidderAdxcg,
 		BidderAdyoulike,
 		BidderAJA,
diff --git a/openrtb_ext/imp_adprime.go b/openrtb_ext/imp_adprime.go
index a089b818..608f5670 100644
--- a/openrtb_ext/imp_adprime.go
+++ b/openrtb_ext/imp_adprime.go
@@ -2,5 +2,7 @@ package openrtb_ext
 
 // ExtImpAdprime defines adprime specifiec param
 type ExtImpAdprime struct {
-	TagID string `json:"TagID"`
+	TagID     string   `json:"TagID"`
+	Keywords  []string `json:"keywords"`
+	Audiences []string `json:"audiences"`
 }
diff --git a/openrtb_ext/imp_adview.go b/openrtb_ext/imp_adview.go
new file mode 100644
index 00000000..adaa59f3
--- /dev/null
+++ b/openrtb_ext/imp_adview.go
@@ -0,0 +1,6 @@
+package openrtb_ext
+
+type ExtImpAdView struct {
+	MasterTagID string `json:"placementId"`
+	AccountID   string `json:"accountId"`
+}
diff --git a/openrtb_ext/request.go b/openrtb_ext/request.go
index 606874f1..bf875123 100644
--- a/openrtb_ext/request.go
+++ b/openrtb_ext/request.go
@@ -29,6 +29,7 @@ type ExtRequestPrebid struct {
 	Aliases              map[string]string         `json:"aliases,omitempty"`
 	BidAdjustmentFactors map[string]float64        `json:"bidadjustmentfactors,omitempty"`
 	Cache                *ExtRequestPrebidCache    `json:"cache,omitempty"`
+	Channel              *ExtRequestPrebidChannel  `json:"channel,omitempty"`
 	Data                 *ExtRequestPrebidData     `json:"data,omitempty"`
 	Debug                bool                      `json:"debug,omitempty"`
 	Events               json.RawMessage           `json:"events,omitempty"`
@@ -80,6 +81,12 @@ type SourceExt struct {
 	SChain ExtRequestPrebidSChainSChain `json:"schain"`
 }
 
+// ExtRequestPrebidChannel defines the contract for bidrequest.ext.prebid.channel
+type ExtRequestPrebidChannel struct {
+	Name    string `json:"name"`
+	Version string `json:"version"`
+}
+
 // ExtRequestPrebidCache defines the contract for bidrequest.ext.prebid.cache
 type ExtRequestPrebidCache struct {
 	Bids    *ExtRequestPrebidCacheBids `json:"bids"`
diff --git a/router/admin.go b/router/admin.go
index b66bf55a..29cdbbe5 100644
--- a/router/admin.go
+++ b/router/admin.go
@@ -7,9 +7,10 @@ import (
 
 	"github.com/prebid/prebid-server/currency"
 	"github.com/prebid/prebid-server/endpoints"
+	"github.com/prebid/prebid-server/version"
 )
 
-func Admin(revision string, rateConverter *currency.RateConverter, rateConverterFetchingInterval time.Duration) *http.ServeMux {
+func Admin(rateConverter *currency.RateConverter, rateConverterFetchingInterval time.Duration) *http.ServeMux {
 	// Add endpoints to the admin server
 	// Making sure to add pprof routes
 	mux := http.NewServeMux()
@@ -21,6 +22,6 @@ func Admin(revision string, rateConverter *currency.RateConverter, rateConverter
 	mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
 	// Register prebid-server defined admin handlers
 	mux.HandleFunc("/currency/rates", endpoints.NewCurrencyRatesEndpoint(rateConverter, rateConverterFetchingInterval))
-	mux.HandleFunc("/version", endpoints.NewVersionEndpoint(revision))
+	mux.HandleFunc("/version", endpoints.NewVersionEndpoint(version.Ver, version.Rev))
 	return mux
 }
diff --git a/router/router.go b/router/router.go
index 446d4280..73265920 100644
--- a/router/router.go
+++ b/router/router.go
@@ -12,6 +12,13 @@ import (
 	"strings"
 	"time"
 
+	"github.com/prebid/prebid-server/currency"
+	"github.com/prebid/prebid-server/endpoints/events"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/util/uuidutil"
+
+	"github.com/prebid/prebid-server/metrics"
+
 	"github.com/prebid/prebid-server/adapters"
 	"github.com/prebid/prebid-server/adapters/adform"
 	"github.com/prebid/prebid-server/adapters/appnexus"
@@ -27,15 +34,11 @@ import (
 	"github.com/prebid/prebid-server/cache/filecache"
 	"github.com/prebid/prebid-server/cache/postgrescache"
 	"github.com/prebid/prebid-server/config"
-	"github.com/prebid/prebid-server/currency"
 	"github.com/prebid/prebid-server/endpoints"
-	"github.com/prebid/prebid-server/endpoints/events"
 	infoEndpoints "github.com/prebid/prebid-server/endpoints/info"
 	"github.com/prebid/prebid-server/endpoints/openrtb2"
-	"github.com/prebid/prebid-server/errortypes"
 	"github.com/prebid/prebid-server/exchange"
 	"github.com/prebid/prebid-server/gdpr"
-	"github.com/prebid/prebid-server/metrics"
 	metricsConf "github.com/prebid/prebid-server/metrics/config"
 	"github.com/prebid/prebid-server/openrtb_ext"
 	"github.com/prebid/prebid-server/pbs"
@@ -276,18 +279,18 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R
 	}
 
 	theExchange := exchange.NewExchange(adapters, cacheClient, cfg, syncersByBidder, r.MetricsEngine, bidderInfos, gdprPerms, rateConvertor, categoriesFetcher)
-
-	openrtbEndpoint, err := openrtb2.NewEndpoint(theExchange, paramsValidator, fetcher, accounts, cfg, r.MetricsEngine, pbsAnalytics, disabledBidders, defReqJSON, activeBidders)
+	var uuidGenerator uuidutil.UUIDRandomGenerator
+	openrtbEndpoint, err := openrtb2.NewEndpoint(uuidGenerator, theExchange, paramsValidator, fetcher, accounts, cfg, r.MetricsEngine, pbsAnalytics, disabledBidders, defReqJSON, activeBidders)
 	if err != nil {
 		glog.Fatalf("Failed to create the openrtb2 endpoint handler. %v", err)
 	}
 
-	ampEndpoint, err := openrtb2.NewAmpEndpoint(theExchange, paramsValidator, ampFetcher, accounts, cfg, r.MetricsEngine, pbsAnalytics, disabledBidders, defReqJSON, activeBidders)
+	ampEndpoint, err := openrtb2.NewAmpEndpoint(uuidGenerator, theExchange, paramsValidator, ampFetcher, accounts, cfg, r.MetricsEngine, pbsAnalytics, disabledBidders, defReqJSON, activeBidders)
 	if err != nil {
 		glog.Fatalf("Failed to create the amp endpoint handler. %v", err)
 	}
 
-	videoEndpoint, err := openrtb2.NewVideoEndpoint(theExchange, paramsValidator, fetcher, videoFetcher, accounts, cfg, r.MetricsEngine, pbsAnalytics, disabledBidders, defReqJSON, activeBidders, cacheClient)
+	videoEndpoint, err := openrtb2.NewVideoEndpoint(uuidGenerator, theExchange, paramsValidator, fetcher, videoFetcher, accounts, cfg, r.MetricsEngine, pbsAnalytics, disabledBidders, defReqJSON, activeBidders, cacheClient)
 	if err != nil {
 		glog.Fatalf("Failed to create the video endpoint handler. %v", err)
 	}
diff --git a/static/bidder-info/adprime.yaml b/static/bidder-info/adprime.yaml
index d702521e..4e5ff75f 100644
--- a/static/bidder-info/adprime.yaml
+++ b/static/bidder-info/adprime.yaml
@@ -5,7 +5,9 @@ capabilities:
     mediaTypes:
       - banner
       - video
+      - native
   site:
     mediaTypes:
       - banner
       - video 
+      - native 
diff --git a/static/bidder-info/adview.yaml b/static/bidder-info/adview.yaml
new file mode 100644
index 00000000..077bce62
--- /dev/null
+++ b/static/bidder-info/adview.yaml
@@ -0,0 +1,9 @@
+maintainer:
+  email: "partner@adview.com"
+gvlVendorID: 1022
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - native
+      - video
diff --git a/static/bidder-info/algorix.yaml b/static/bidder-info/algorix.yaml
index b8301d6c..75ab4c09 100644
--- a/static/bidder-info/algorix.yaml
+++ b/static/bidder-info/algorix.yaml
@@ -1,8 +1,8 @@
 maintainer:
-  email: "xunyunbo@algorix.co"
+  email: "prebid@algorix.co"
 capabilities:
   app:
     mediaTypes:
       - banner
       - video
-      - native
\ No newline at end of file
+      - native
diff --git a/static/bidder-info/visx.yaml b/static/bidder-info/visx.yaml
index 77d4463a..7faf1b94 100644
--- a/static/bidder-info/visx.yaml
+++ b/static/bidder-info/visx.yaml
@@ -5,9 +5,11 @@ capabilities:
   site:
     mediaTypes:
       - banner
+      - video
   app:
     mediaTypes:
       - banner
+      - video
 userSync:
   redirect:
     url: "https://t.visx.net/s2s_sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir={{.RedirectURL}}"
diff --git a/static/bidder-params/adprime.json b/static/bidder-params/adprime.json
index d5270565..23f7cb94 100644
--- a/static/bidder-params/adprime.json
+++ b/static/bidder-params/adprime.json
@@ -2,13 +2,28 @@
     "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "Adprime Adapter Params",
     "description": "A schema which validates params accepted by the Adprime adapter",
-
     "type": "object",
     "properties": {
-      "TagID": {
-        "type": "string",
-        "description": "An ID which identifies the adprime ad tag"
-      }
+        "TagID": {
+            "type": "string",
+            "description": "An ID which identifies the adprime ad tag"
+        },
+        "keywords": {
+            "type": "array",
+            "description": "page context keywords",
+            "items": {
+                "type": "string"
+            }
+        },
+        "audiences": {
+            "type": "array",
+            "description": "publisher audiences",
+            "items": {
+                "type": "string"
+            }
+        }
     },
-    "required" : [ "TagID" ]
-  }
\ No newline at end of file
+    "required": [
+        "TagID"
+    ]
+}
\ No newline at end of file
diff --git a/static/bidder-params/adview.json b/static/bidder-params/adview.json
new file mode 100644
index 00000000..b5c927aa
--- /dev/null
+++ b/static/bidder-params/adview.json
@@ -0,0 +1,19 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "AdView Adapter Params",
+  "description": "A schema which validates params accepted by the adview adapter",
+  "type": "object",
+  "properties": {
+    "placementId": {
+      "type": "string",
+      "description": "An ID which identifies the placement selling the impression",
+      "minLength": 1
+    },
+    "accountId": {
+      "type": "string",
+      "description": "Account id",
+      "minLength": 1
+    } 
+  },
+  "required": ["placementId", "accountId"]
+}
diff --git a/util/maputil/maputil.go b/util/maputil/maputil.go
index 595e9321..49df0772 100644
--- a/util/maputil/maputil.go
+++ b/util/maputil/maputil.go
@@ -20,7 +20,7 @@ func ReadEmbeddedSlice(m map[string]interface{}, k string) ([]interface{}, bool)
 	return nil, false
 }
 
-// ReadEmbeddedString reads element k from the map m as a string
+// ReadEmbeddedString reads element k from the map m as a string.
 func ReadEmbeddedString(m map[string]interface{}, k string) (string, bool) {
 	if v, ok := m[k]; ok {
 		vCasted, ok := v.(string)
@@ -28,3 +28,23 @@ func ReadEmbeddedString(m map[string]interface{}, k string) (string, bool) {
 	}
 	return "", false
 }
+
+// HasElement returns true if nested element k exists.
+func HasElement(m map[string]interface{}, k ...string) bool {
+	exists := false
+	kLastIndex := len(k) - 1
+
+	for i, k := range k {
+		isLastKey := i == kLastIndex
+
+		if isLastKey {
+			_, exists = m[k]
+		} else {
+			if m, exists = ReadEmbeddedMap(m, k); !exists {
+				break
+			}
+		}
+	}
+
+	return exists
+}
diff --git a/util/uuidutil/uuidutil.go b/util/uuidutil/uuidutil.go
new file mode 100644
index 00000000..6e4848f6
--- /dev/null
+++ b/util/uuidutil/uuidutil.go
@@ -0,0 +1,19 @@
+package uuidutil
+
+import (
+	"github.com/gofrs/uuid"
+)
+
+type UUIDGenerator interface {
+	Generate() (string, error)
+}
+
+type UUIDRandomGenerator struct{}
+
+func (UUIDRandomGenerator) Generate() (string, error) {
+	id, err := uuid.NewV4()
+	if err != nil {
+		return "", err
+	}
+	return id.String(), nil
+}
diff --git a/version/version.go b/version/version.go
new file mode 100644
index 00000000..e9310276
--- /dev/null
+++ b/version/version.go
@@ -0,0 +1,14 @@
+package version
+
+// Ver holds the version derived from the latest git tag
+// Populated using:
+//    go build -ldflags "-X github.com/prebid/prebid-server/version.Ver=`git describe --tags | sed 's/^v//`"
+// Populated automatically at build / releases in the Docker image
+var Ver string
+
+// Rev holds binary revision string
+// Populated using:
+//    go build -ldflags "-X github.com/prebid/prebid-server/version.Rev=`git rev-parse --short HEAD`"
+// Populated automatically at build / releases in the Docker image
+// See issue #559
+var Rev string


Test patch:
diff --git a/adapters/adprime/adprime_test.go b/adapters/adprime/adprime_test.go
index ff12381d..113233ee 100644
--- a/adapters/adprime/adprime_test.go
+++ b/adapters/adprime/adprime_test.go
@@ -10,7 +10,7 @@ import (
 
 func TestJsonSamples(t *testing.T) {
 	bidder, buildErr := Builder(openrtb_ext.BidderAdprime, config.Adapter{
-		Endpoint: "http://delta.adprime.com/?c=o&m=ortb"})
+		Endpoint: "http://delta.adprime.com/pserver"})
 
 	if buildErr != nil {
 		t.Fatalf("Builder returned unexpected error %v", buildErr)
diff --git a/adapters/adprime/adprimetest/exemplary/simple-banner.json b/adapters/adprime/adprimetest/exemplary/simple-banner.json
index 076175c6..e96abe5c 100644
--- a/adapters/adprime/adprimetest/exemplary/simple-banner.json
+++ b/adapters/adprime/adprimetest/exemplary/simple-banner.json
@@ -1,134 +1,134 @@
 {
-  "mockBidRequest": {
-    "id": "test-request-id",
-    "imp": [
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "device": {
+            "ip": "123.123.123.123",
+            "ua": "iPad"
+        },
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "tagid": "test",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placementId": "test",
+                        "TagID": "test"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
         {
-            "id": "test-imp-id",
-            "banner": {
-                "format": [
-                    {
-                        "w": 300,
-                        "h": 250
+            "expectedRequest": {
+                "uri": "http://delta.adprime.com/pserver",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "tagid": "test",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ]
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": "test",
+                                    "TagID": "test"
+                                }
+                            }
+                        }
+                    ],
+                    "app": {
+                        "id": "1",
+                        "bundle": "com.wls.testwlsapplication"
                     },
-                    {
-                        "w": 300,
-                        "h": 600
+                    "device": {
+                        "ip": "123.123.123.123",
+                        "ua": "iPad"
                     }
-                ]
+                }
             },
-            "tagid": "1",
-            "ext": {
-                "bidder": {
-                    "TagID": "1"
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "bid": [
+                                {
+                                    "id": "test_bid_id",
+                                    "impid": "test-imp-id",
+                                    "price": 0.27543,
+                                    "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                                    "cid": "test_cid",
+                                    "crid": "test_crid",
+                                    "dealid": "test_dealid",
+                                    "w": 300,
+                                    "h": 250,
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "banner"
+                                        }
+                                    }
+                                }
+                            ],
+                            "seat": "adprime"
+                        }
+                    ],
+                    "cur": "USD"
                 }
             }
         }
     ],
-    "app": {
-        "id": "1",
-        "bundle": "com.wls.testwlsapplication"
-    },
-    "device": {
-        "ip": "123.123.123.123",
-        "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
-    }
-},
-
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "uri": "http://delta.adprime.com/?c=o&m=ortb",
-        "body": {
-          "id": "test-request-id",
-          "imp": [
-              {
-                  "id": "test-imp-id",
-                  "banner": {
-                      "format": [
-                          {
-                              "w": 300,
-                              "h": 250
-                          },
-                          {
-                              "w": 300,
-                              "h": 600
-                          }
-                      ]
-                  },
-                  "tagid": "1",
-                  "ext": {
-                      "bidder": {
-                          "TagID": "1"
-                      }
-                  }
-              }
-          ],
-          "app": {
-              "id": "1",
-              "bundle": "com.wls.testwlsapplication"
-          },
-          "device": {
-              "ip": "123.123.123.123",
-              "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
-          }
-      }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "test-request-id",
-          "seatbid": [
-              {
-                  "bid": [
-                      {
-                          "id": "test_bid_id",
-                          "impid": "test-imp-id",
-                          "price": 0.27543,
-                          "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
-                          "cid": "test_cid",
-                          "crid": "test_crid",
-                          "dealid": "test_dealid",
-                          "w": 300,
-                          "h": 250,
-                          "ext": {
-                              "prebid": {
-                                  "type": "banner"
-                              }
-                          }
-                      }
-                  ],
-                  "seat": "adprime"
-              }
-          ],
-          "cur": "USD"
-        }
-      }
-    }
-  ],
-
-  "expectedBidResponses": [
-    {
-      "bids":[
+    "expectedBidResponses": [
         {
-          "bid":  {
-            "id": "test_bid_id",
-            "impid": "test-imp-id",
-            "price": 0.27543,
-            "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
-            "cid": "test_cid",
-            "crid": "test_crid",
-            "dealid": "test_dealid",
-            "w": 300,
-            "h": 250,
-            "ext": {
-              "prebid": {
-                "type": "banner"
-              }
-            }
-          },
-          "type": "banner"
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test_bid_id",
+                        "impid": "test-imp-id",
+                        "price": 0.27543,
+                        "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                        "cid": "test_cid",
+                        "crid": "test_crid",
+                        "dealid": "test_dealid",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "prebid": {
+                                "type": "banner"
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
         }
-      ]
-    }
-  ]
-}
+    ]
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/exemplary/simple-native.json b/adapters/adprime/adprimetest/exemplary/simple-native.json
new file mode 100644
index 00000000..0ea8a0a1
--- /dev/null
+++ b/adapters/adprime/adprimetest/exemplary/simple-native.json
@@ -0,0 +1,118 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "device": {
+            "ip": "123.123.123.123",
+            "ua": "iPad"
+        },
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "tagid": "test",
+                "native": {
+                    "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}",
+                    "ver": "1.1"
+                },
+                "ext": {
+                    "bidder": {
+                        "placementId": "test",
+                        "TagID": "test"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://delta.adprime.com/pserver",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "tagid": "test",
+                            "native": {
+                                "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}",
+                                "ver": "1.1"
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": "test",
+                                    "TagID": "test"
+                                }
+                            }
+                        }
+                    ],
+                    "app": {
+                        "id": "1",
+                        "bundle": "com.wls.testwlsapplication"
+                    },
+                    "device": {
+                        "ip": "123.123.123.123",
+                        "ua": "iPad"
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "bid": [
+                                {
+                                    "id": "test_bid_id",
+                                    "impid": "test-imp-id",
+                                    "price": 0.27543,
+                                    "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                                    "cid": "test_cid",
+                                    "crid": "test_crid",
+                                    "dealid": "test_dealid",
+                                    "w": 300,
+                                    "h": 250,
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "native"
+                                        }
+                                    }
+                                }
+                            ],
+                            "seat": "adprime"
+                        }
+                    ],
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test_bid_id",
+                        "impid": "test-imp-id",
+                        "price": 0.27543,
+                        "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                        "cid": "test_cid",
+                        "crid": "test_crid",
+                        "dealid": "test_dealid",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "prebid": {
+                                "type": "native"
+                            }
+                        }
+                    },
+                    "type": "native"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/exemplary/simple-video.json b/adapters/adprime/adprimetest/exemplary/simple-video.json
index 3e61c4dd..164e3040 100644
--- a/adapters/adprime/adprimetest/exemplary/simple-video.json
+++ b/adapters/adprime/adprimetest/exemplary/simple-video.json
@@ -1,119 +1,129 @@
 {
-  "mockBidRequest": {
-    "id": "test-request-id",
-    "device": {
-      "ip": "123.123.123.123",
-      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
-    },
-    "app": {
-      "id": "1",
-      "bundle": "com.wls.testwlsapplication"
-    },
-    "imp": [
-      {
-        "id": "test-imp-id",
-        "video": {
-          "mimes": ["video/mp4"],
-          "protocols": [2, 5],
-          "w": 1024,
-          "h": 576
-        },
-        "ext": {
-          "bidder": {
-            "TagID": "288"
-          }
-        }
-      }
-    ]
-  },
-
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "uri": "http://delta.adprime.com/?c=o&m=ortb",
-        "body": {
-          "id": "test-request-id",
-          "device": {
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "device": {
             "ip": "123.123.123.123",
-            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
-          },
-          "app": {
+            "ua": "iPad"
+        },
+        "app": {
             "id": "1",
             "bundle": "com.wls.testwlsapplication"
-          },
-          "imp": [
+        },
+        "imp": [
             {
-              "id": "test-imp-id",
-              "video": {
-                "mimes": ["video/mp4"],
-                "protocols": [2, 5],
-                "w": 1024,
-                "h": 576
-              },
-              "tagid": "288",
-              "ext": {
-                "bidder": {
-                  "TagID": "288"
+                "id": "test-imp-id",
+                "tagid": "test",
+                "video": {
+                    "mimes": [
+                        "video/mp4"
+                    ],
+                    "protocols": [
+                        2,
+                        5
+                    ],
+                    "w": 1024,
+                    "h": 576
+                },
+                "ext": {
+                    "bidder": {
+                        "placementId": "test",
+                        "TagID": "test"
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://delta.adprime.com/pserver",
+                "body": {
+                    "id": "test-request-id",
+                    "device": {
+                        "ip": "123.123.123.123",
+                        "ua": "iPad"
+                    },
+                    "app": {
+                        "id": "1",
+                        "bundle": "com.wls.testwlsapplication"
+                    },
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "tagid": "test",
+                            "video": {
+                                "mimes": [
+                                    "video/mp4"
+                                ],
+                                "protocols": [
+                                    2,
+                                    5
+                                ],
+                                "w": 1024,
+                                "h": 576
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": "test",
+                                    "TagID": "test"
+                                }
+                            }
+                        }
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "bid": [
+                                {
+                                    "id": "test_bid_id",
+                                    "impid": "test-imp-id",
+                                    "price": 0.27543,
+                                    "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>",
+                                    "cid": "test_cid",
+                                    "crid": "test_crid",
+                                    "dealid": "test_dealid",
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "video"
+                                        }
+                                    }
+                                }
+                            ],
+                            "seat": "adprime"
+                        }
+                    ],
+                    "cur": "USD"
                 }
-              }
             }
-          ]
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "test-request-id",
-          "seatbid": [
-              {
-                  "bid": [
-                      {
-                          "id": "test_bid_id",
-                          "impid": "test-imp-id",
-                          "price": 0.27543,
-                          "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>",
-                          "cid": "test_cid",
-                          "crid": "test_crid",
-                          "dealid": "test_dealid",
-                          "ext": {
-                              "prebid": {
-                                  "type": "video"
-                              }
-                          }
-                      }
-                  ],
-                  "seat": "adprime"
-              }
-          ],
-          "cur": "USD"
         }
-      }
-    }
-  ],
-
-
-  "expectedBidResponses": [
-    {
-      "currency": "USD",
-      "bids": [
+    ],
+    "expectedBidResponses": [
         {
-          "bid": {
-            "id": "test_bid_id",
-                          "impid": "test-imp-id",
-                          "price": 0.27543,
-                          "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>",
-                          "cid": "test_cid",
-                          "crid": "test_crid",
-                          "dealid": "test_dealid",
-                          "ext": {
-                              "prebid": {
-                                  "type": "video"
-                              }
-                          }
-          },
-          "type": "video"
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test_bid_id",
+                        "impid": "test-imp-id",
+                        "price": 0.27543,
+                        "adm": "<VAST version=\"3.0\"><Ad id=\"20001\" sequence=\"1\"><InLine><AdSystem version=\"4.0\"><![CDATA[iabtechlab]]></AdSystem><AdTitle><![CDATA[Inline Simple Ad]]></AdTitle><Impression><![CDATA[]]></Impression><Creatives><Creative id=\"5480\" sequence=\"1\"><Linear><Duration>00:01:00</Duration><MediaFiles><MediaFile id=\"5246\" delivery=\"progressive\" type=\"video/mp4\" bitrate=\"600\" width=\"640\" height=\"360\" minBitrate=\"500\" maxBitrate=\"700\" scalable=\"1\" maintainAspectRatio=\"1\" codec=\"0\"><![CDATA[https://s0.2mdn.net/4253510/google_ddm_animation_480P.mp4]]></MediaFile></MediaFiles><VideoClicks><ClickThrough id=\"blog\"><![CDATA[https://example.com]]></ClickThrough></VideoClicks></Linear></Creative></Creatives></InLine></Ad></VAST>",
+                        "cid": "test_cid",
+                        "crid": "test_crid",
+                        "dealid": "test_dealid",
+                        "ext": {
+                            "prebid": {
+                                "type": "video"
+                            }
+                        }
+                    },
+                    "type": "video"
+                }
+            ]
         }
-      ]
-    }
-  ]
-}
+    ]
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/exemplary/simple-web-banner.json b/adapters/adprime/adprimetest/exemplary/simple-web-banner.json
index a955854f..74797b19 100644
--- a/adapters/adprime/adprimetest/exemplary/simple-web-banner.json
+++ b/adapters/adprime/adprimetest/exemplary/simple-web-banner.json
@@ -1,133 +1,134 @@
 {
     "mockBidRequest": {
-      "id": "test-request-id",
-      "imp": [
-          {
-              "id": "test-imp-id",
-              "banner": {
-                  "format": [
-                      {
-                          "w": 300,
-                          "h": 250
-                      },
-                      {
-                          "w": 300,
-                          "h": 600
-                      }
-                  ]
-              },
-              "tagid": "1",
-              "ext": {
-                  "bidder": {
-                      "TagID": "1"
-                  }
-              }
-          }
-      ],
-      "site": {
-          "id": "1",
-          "domain": "test.com"
-      },
-      "device": {
-          "ip": "123.123.123.123"
-      }
-  },
-  
-    "httpCalls": [
-      {
-        "expectedRequest": {
-          "uri": "http://delta.adprime.com/?c=o&m=ortb",
-          "body": {
-            "id": "test-request-id",
-            "imp": [
-                {
-                    "id": "test-imp-id",
-                    "banner": {
-                        "format": [
-                            {
-                                "w": 300,
-                                "h": 250
-                            },
-                            {
-                                "w": 300,
-                                "h": 600
-                            }
-                        ]
-                    },
-                    "tagid": "1",
-                    "ext": {
-                        "bidder": {
-                            "TagID": "1"
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "tagid": "test",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
                         }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "TagID": "test",
+                        "placementId": "test"
                     }
                 }
-            ],
-            "site": {
-                "id": "1",
-                "domain": "test.com"
-            },
-            "device": {
-                "ip": "123.123.123.123"
             }
-        }
+        ],
+        "site": {
+            "id": "1",
+            "domain": "test.com"
         },
-        "mockResponse": {
-          "status": 200,
-          "body": {
-            "id": "test-request-id",
-            "seatbid": [
-                {
-                    "bid": [
+        "device": {
+            "ip": "123.123.123.123",
+            "ua": "Ubuntu"
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://delta.adprime.com/pserver",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
                         {
-                            "id": "test_bid_id",
-                            "impid": "test-imp-id",
-                            "price": 0.27543,
-                            "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>",
-                            "cid": "test_cid",
-                            "crid": "test_crid",
-                            "dealid": "test_dealid",
-                            "w": 468,
-                            "h": 60,
+                            "id": "test-imp-id",
+                            "tagid": "test",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ]
+                            },
                             "ext": {
-                                "prebid": {
-                                    "type": "banner"
+                                "bidder": {
+                                    "placementId": "test",
+                                    "TagID": "test"
                                 }
                             }
                         }
                     ],
-                    "seat": "adprime"
+                    "site": {
+                        "id": "1",
+                        "domain": "test.com"
+                    },
+                    "device": {
+                        "ip": "123.123.123.123",
+                        "ua": "Ubuntu"
+                    }
                 }
-            ],
-            "cur": "USD"
-          }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "bid": [
+                                {
+                                    "id": "test_bid_id",
+                                    "impid": "test-imp-id",
+                                    "price": 0.27543,
+                                    "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>",
+                                    "cid": "test_cid",
+                                    "crid": "test_crid",
+                                    "dealid": "test_dealid",
+                                    "w": 468,
+                                    "h": 60,
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "banner"
+                                        }
+                                    }
+                                }
+                            ],
+                            "seat": "adprime"
+                        }
+                    ],
+                    "cur": "USD"
+                }
+            }
         }
-      }
     ],
-  
     "expectedBidResponses": [
-      {
-        "bids":[
-          {
-            "bid":  {
-                "id": "test_bid_id",
-                "impid": "test-imp-id",
-                "price": 0.27543,
-                "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>",
-                "cid": "test_cid",
-                "crid": "test_crid",
-                "dealid": "test_dealid",
-                "w": 468,
-                "h": 60,
-                "ext": {
-                    "prebid": {
-                        "type": "banner"
-                    }
+        {
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test_bid_id",
+                        "impid": "test-imp-id",
+                        "price": 0.27543,
+                        "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>",
+                        "cid": "test_cid",
+                        "crid": "test_crid",
+                        "dealid": "test_dealid",
+                        "w": 468,
+                        "h": 60,
+                        "ext": {
+                            "prebid": {
+                                "type": "banner"
+                            }
+                        }
+                    },
+                    "type": "banner"
                 }
-            },
-            "type": "banner"
-          }
-        ]
-      }
+            ]
+        }
     ]
-  }
-  
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/exemplary/withAudiences.json b/adapters/adprime/adprimetest/exemplary/withAudiences.json
new file mode 100644
index 00000000..ed8e1c00
--- /dev/null
+++ b/adapters/adprime/adprimetest/exemplary/withAudiences.json
@@ -0,0 +1,138 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "device": {
+            "ip": "123.123.123.123",
+            "ua": "iPad"
+        },
+        "site": {
+            "id": "1",
+            "domain": "test.com"
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "tagid": "test",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placementId": "test",
+                        "TagID": "test",
+                        "audiences": ["aud1", "aud2"]
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://delta.adprime.com/pserver",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "tagid": "test",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ]
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": "test",
+                                    "TagID": "test"
+                                }
+                            }
+                        }
+                    ],
+                    "site": {
+                        "id": "1",
+                        "domain": "test.com"
+                    },
+                    "user": {
+                        "customdata": "aud1,aud2"
+                    },
+                    "device": {
+                        "ip": "123.123.123.123",
+                        "ua": "iPad"
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "bid": [
+                                {
+                                    "id": "test_bid_id",
+                                    "impid": "test-imp-id",
+                                    "price": 0.27543,
+                                    "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                                    "cid": "test_cid",
+                                    "crid": "test_crid",
+                                    "dealid": "test_dealid",
+                                    "w": 300,
+                                    "h": 250,
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "banner"
+                                        }
+                                    }
+                                }
+                            ],
+                            "seat": "adprime"
+                        }
+                    ],
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test_bid_id",
+                        "impid": "test-imp-id",
+                        "price": 0.27543,
+                        "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                        "cid": "test_cid",
+                        "crid": "test_crid",
+                        "dealid": "test_dealid",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "prebid": {
+                                "type": "banner"
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/exemplary/withKeywords.json b/adapters/adprime/adprimetest/exemplary/withKeywords.json
new file mode 100644
index 00000000..3e1528fe
--- /dev/null
+++ b/adapters/adprime/adprimetest/exemplary/withKeywords.json
@@ -0,0 +1,136 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "device": {
+            "ip": "123.123.123.123",
+            "ua": "iPad"
+        },
+        "site": {
+            "id": "1",
+            "domain": "test.com"
+        },
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "tagid": "test",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "ext": {
+                    "bidder": {
+                        "placementId": "test",
+                        "TagID": "test",
+                        "keywords": ["keyw1", "keyw2"]
+                    }
+                }
+            }
+        ]
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://delta.adprime.com/pserver",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "tagid": "test",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    },
+                                    {
+                                        "w": 300,
+                                        "h": 600
+                                    }
+                                ]
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": "test",
+                                    "TagID": "test"
+                                }
+                            }
+                        }
+                    ],
+                    "site": {
+                        "id": "1",
+                        "domain": "test.com",
+                        "keywords": "keyw1,keyw2"
+                    },
+                    "device": {
+                        "ip": "123.123.123.123",
+                        "ua": "iPad"
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "bid": [
+                                {
+                                    "id": "test_bid_id",
+                                    "impid": "test-imp-id",
+                                    "price": 0.27543,
+                                    "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                                    "cid": "test_cid",
+                                    "crid": "test_crid",
+                                    "dealid": "test_dealid",
+                                    "w": 300,
+                                    "h": 250,
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "banner"
+                                        }
+                                    }
+                                }
+                            ],
+                            "seat": "adprime"
+                        }
+                    ],
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "bids": [
+                {
+                    "bid": {
+                        "id": "test_bid_id",
+                        "impid": "test-imp-id",
+                        "price": 0.27543,
+                        "adm": "<iframe id=\"adm-banner-16\" width=\"300\" height=\"250\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=882b2510ed6d6c94fa69c99aa522a708\"></iframe>",
+                        "cid": "test_cid",
+                        "crid": "test_crid",
+                        "dealid": "test_dealid",
+                        "w": 300,
+                        "h": 250,
+                        "ext": {
+                            "prebid": {
+                                "type": "banner"
+                            }
+                        }
+                    },
+                    "type": "banner"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/params/race/banner.json b/adapters/adprime/adprimetest/params/race/banner.json
new file mode 100644
index 00000000..22651f51
--- /dev/null
+++ b/adapters/adprime/adprimetest/params/race/banner.json
@@ -0,0 +1,3 @@
+{
+    "TagID": "test"
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/params/race/native.json b/adapters/adprime/adprimetest/params/race/native.json
new file mode 100644
index 00000000..22651f51
--- /dev/null
+++ b/adapters/adprime/adprimetest/params/race/native.json
@@ -0,0 +1,3 @@
+{
+    "TagID": "test"
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/params/race/video.json b/adapters/adprime/adprimetest/params/race/video.json
new file mode 100644
index 00000000..22651f51
--- /dev/null
+++ b/adapters/adprime/adprimetest/params/race/video.json
@@ -0,0 +1,3 @@
+{
+    "TagID": "test"
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/supplemental/bad-imp-ext.json b/adapters/adprime/adprimetest/supplemental/bad-imp-ext.json
index a95c56e8..39cd3cd0 100644
--- a/adapters/adprime/adprimetest/supplemental/bad-imp-ext.json
+++ b/adapters/adprime/adprimetest/supplemental/bad-imp-ext.json
@@ -1,42 +1,42 @@
 {
-  "mockBidRequest": {
-    "id": "test-request-id",
-    "imp": [
-        {
-            "id": "test-imp-id",
-            "banner": {
-                "format": [
-                    {
-                        "w": 300,
-                        "h": 250
-                    },
-                    {
-                        "w": 300,
-                        "h": 600
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "tagid": "1",
+                "ext": {
+                    "adprime": {
+                        "TagID": "1"
                     }
-                ]
-            },
-            "tagid": "1",
-            "ext": {
-                "adprime": {
-                    "TagID": "1"
                 }
             }
+        ],
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
         }
-    ],
-    "app": {
-        "id": "1",
-        "bundle": "com.wls.testwlsapplication"
     },
-    "device": {
-        "ip": "123.123.123.123",
-        "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
-    }
-},
-"expectedMakeRequestsErrors": [
-  {
-    "value": "Key path not found",
-    "comparison": "literal"
-  }
-]
-}
+    "expectedMakeRequestsErrors": [
+        {
+            "value": "unexpected end of JSON input",
+            "comparison": "literal"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/supplemental/bad_media_type.json b/adapters/adprime/adprimetest/supplemental/bad_media_type.json
new file mode 100644
index 00000000..e91a0138
--- /dev/null
+++ b/adapters/adprime/adprimetest/supplemental/bad_media_type.json
@@ -0,0 +1,91 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "tagid": "test",
+                "ext": {
+                    "bidder": {
+                        "TagID": "test",
+                        "placementId": "test"
+                    }
+                }
+            }
+        ],
+        "site": {
+            "id": "1",
+            "domain": "test.com"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ua": "Ubuntu"
+        }
+    },
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://delta.adprime.com/pserver",
+                "body": {
+                    "id": "test-request-id",
+                    "imp": [
+                        {
+                            "id": "test-imp-id",
+                            "tagid": "test",
+                            "ext": {
+                                "bidder": {
+                                    "placementId": "test",
+                                    "TagID": "test"
+                                }
+                            }
+                        }
+                    ],
+                    "site": {
+                        "id": "1",
+                        "domain": "test.com"
+                    },
+                    "device": {
+                        "ip": "123.123.123.123",
+                        "ua": "Ubuntu"
+                    }
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "bid": [
+                                {
+                                    "id": "test_bid_id",
+                                    "impid": "test-imp-id",
+                                    "price": 0.27543,
+                                    "adm": "<iframe id=\"adm-banner-1\" width=\"468\" height=\"60\" frameborder=\"0\" marginheight=\"0\" marginwidth=\"0\" style=\"{overflow:hidden}\" src=\"https://delta.adprime.com/?c=o&m=adm&k=bc2d316f39931a07d9a8dd249bf85fc0\"></iframe>",
+                                    "cid": "test_cid",
+                                    "crid": "test_crid",
+                                    "dealid": "test_dealid",
+                                    "w": 468,
+                                    "h": 60,
+                                    "ext": {
+                                        "prebid": {
+                                            "type": "banner"
+                                        }
+                                    }
+                                }
+                            ],
+                            "seat": "adprime"
+                        }
+                    ],
+                    "cur": "USD"
+                }
+            }
+        }
+    ],
+    "expectedMakeBidsErrors": [
+        {
+            "value": "Failed to find impression \"test-imp-id\"",
+            "comparison": "literal"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/supplemental/bad_response.json b/adapters/adprime/adprimetest/supplemental/bad_response.json
index 435529a4..acec885f 100644
--- a/adapters/adprime/adprimetest/supplemental/bad_response.json
+++ b/adapters/adprime/adprimetest/supplemental/bad_response.json
@@ -19,7 +19,8 @@
                 "tagid": "17",
                 "ext": {
                     "bidder": {
-                        "TagID": "17"
+                        "TagID": "17",
+                        "placementId": "17"
                     }
                 }
             }
@@ -35,7 +36,7 @@
     },
 	"httpCalls": [{
 		"expectedRequest": {
-			"uri": "http://delta.adprime.com/?c=o&m=ortb",
+			"uri": "http://delta.adprime.com/pserver",
 			"body": {
                 "id": "test-request-id",
                 "imp": [
@@ -56,7 +57,8 @@
                         "tagid": "17",
                         "ext": {
                             "bidder": {
-                                "TagID": "17"
+                                "TagID": "17",
+                                "placementId": "17"
                             }
                         }
                     }
diff --git a/adapters/adprime/adprimetest/supplemental/no-imp-ext-1.json b/adapters/adprime/adprimetest/supplemental/no-imp-ext-1.json
index 1e38dbe4..5ba65925 100644
--- a/adapters/adprime/adprimetest/supplemental/no-imp-ext-1.json
+++ b/adapters/adprime/adprimetest/supplemental/no-imp-ext-1.json
@@ -1,39 +1,38 @@
 {
     "mockBidRequest": {
-      "id": "test-request-id",
-      "imp": [
-          {
-              "id": "test-imp-id",
-              "banner": {
-                  "format": [
-                      {
-                          "w": 300,
-                          "h": 250
-                      },
-                      {
-                          "w": 300,
-                          "h": 600
-                      }
-                  ]
-              },
-              "tagid": "1",
-              "ext": ""
-          }
-      ],
-      "app": {
-          "id": "1",
-          "bundle": "com.wls.testwlsapplication"
-      },
-      "device": {
-          "ip": "123.123.123.123",
-          "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
-      }
-  },
-  "expectedMakeRequestsErrors": [
-    {
-      "value": "Key path not found",
-      "comparison": "literal"
-    }
-  ]
-  }
-  
\ No newline at end of file
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "tagid": "1",
+                "ext": ""
+            }
+        ],
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+        }
+    },
+    "expectedMakeRequestsErrors": [
+        {
+            "value": "json: cannot unmarshal string into Go value of type adapters.ExtImpBidder",
+            "comparison": "literal"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/supplemental/no-imp-ext-2.json b/adapters/adprime/adprimetest/supplemental/no-imp-ext-2.json
index f9759fae..e08f5385 100644
--- a/adapters/adprime/adprimetest/supplemental/no-imp-ext-2.json
+++ b/adapters/adprime/adprimetest/supplemental/no-imp-ext-2.json
@@ -1,39 +1,38 @@
 {
     "mockBidRequest": {
-      "id": "test-request-id",
-      "imp": [
-          {
-              "id": "test-imp-id",
-              "banner": {
-                  "format": [
-                      {
-                          "w": 300,
-                          "h": 250
-                      },
-                      {
-                          "w": 300,
-                          "h": 600
-                      }
-                  ]
-              },
-              "tagid": "1",
-              "ext": {}
-          }
-      ],
-      "app": {
-          "id": "1",
-          "bundle": "com.wls.testwlsapplication"
-      },
-      "device": {
-          "ip": "123.123.123.123",
-          "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
-      }
-  },
-  "expectedMakeRequestsErrors": [
-    {
-      "value": "Key path not found",
-      "comparison": "literal"
-    }
-  ]
-  }
-  
\ No newline at end of file
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "tagid": "1",
+                "ext": {}
+            }
+        ],
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+        }
+    },
+    "expectedMakeRequestsErrors": [
+        {
+            "value": "unexpected end of JSON input",
+            "comparison": "literal"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/adapters/adprime/adprimetest/supplemental/status-204.json b/adapters/adprime/adprimetest/supplemental/status-204.json
index 4fa57dce..c0c2f346 100644
--- a/adapters/adprime/adprimetest/supplemental/status-204.json
+++ b/adapters/adprime/adprimetest/supplemental/status-204.json
@@ -19,7 +19,8 @@
                 "tagid": "17",
                 "ext": {
                     "bidder": {
-                        "TagID": "17"
+                        "TagID": "17",
+                        "placementId": "17"
                     }
                 }
             }
@@ -35,7 +36,7 @@
     },
 	"httpCalls": [{
 		"expectedRequest": {
-			"uri": "http://delta.adprime.com/?c=o&m=ortb",
+			"uri": "http://delta.adprime.com/pserver",
 			"body": {
                 "id": "test-request-id",
                 "imp": [
@@ -56,7 +57,8 @@
                         "tagid": "17",
                         "ext": {
                             "bidder": {
-                                "TagID": "17"
+                                "TagID": "17",
+                                "placementId": "17"
                             }
                         }
                     }
diff --git a/adapters/adprime/adprimetest/supplemental/status-400.json b/adapters/adprime/adprimetest/supplemental/status-400.json
new file mode 100644
index 00000000..ab1c38a0
--- /dev/null
+++ b/adapters/adprime/adprimetest/supplemental/status-400.json
@@ -0,0 +1,87 @@
+{
+	"mockBidRequest": {
+        "id": "test-request-id",
+        "imp": [
+            {
+                "id": "test-imp-id",
+                "banner": {
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        },
+                        {
+                            "w": 300,
+                            "h": 600
+                        }
+                    ]
+                },
+                "tagid": "100000000",
+                "ext": {
+                    "bidder": {
+                        "TagID": "100000000",
+                        "placementId": "100000000"
+                    }
+                }
+            }
+        ],
+        "app": {
+            "id": "1",
+            "bundle": "com.wls.testwlsapplication"
+        },
+        "device": {
+            "ip": "123.123.123.123",
+            "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+        }
+    },
+	"httpCalls": [{
+		"expectedRequest": {
+			"uri": "http://delta.adprime.com/pserver",
+			"body": {
+                "id": "test-request-id",
+                "imp": [
+                    {
+                        "id": "test-imp-id",
+                        "banner": {
+                            "format": [
+                                {
+                                    "w": 300,
+                                    "h": 250
+                                },
+                                {
+                                    "w": 300,
+                                    "h": 600
+                                }
+                            ]
+                        },
+                        "tagid": "100000000",
+                        "ext": {
+                            "bidder": {
+                                "TagID": "100000000",
+                                "placementId": "100000000"
+                            }
+                        }
+                    }
+                ],
+                "app": {
+                    "id": "1",
+                    "bundle": "com.wls.testwlsapplication"
+                },
+                "device": {
+                    "ip": "123.123.123.123",
+                    "ifa": "sdjfksdf-dfsds-dsdg-dsgg"
+                }
+            }
+		},
+		"mockResponse": {
+			"status": 400,
+			"body": {}
+		}
+    }],
+    "expectedMakeBidsErrors": [
+        {
+          "value": "Unexpected status code: 400. Run with request.debug = 1 for more info",
+          "comparison": "literal"
+        }
+    ]
+}
diff --git a/adapters/adprime/adprimetest/supplemental/status-404.json b/adapters/adprime/adprimetest/supplemental/status-404.json
index c2b303f0..6cd71854 100644
--- a/adapters/adprime/adprimetest/supplemental/status-404.json
+++ b/adapters/adprime/adprimetest/supplemental/status-404.json
@@ -19,7 +19,8 @@
                 "tagid": "100000000",
                 "ext": {
                     "bidder": {
-                        "TagID": "100000000"
+                        "TagID": "100000000",
+                        "placementId": "100000000"
                     }
                 }
             }
@@ -35,7 +36,7 @@
     },
 	"httpCalls": [{
 		"expectedRequest": {
-			"uri": "http://delta.adprime.com/?c=o&m=ortb",
+			"uri": "http://delta.adprime.com/pserver",
 			"body": {
                 "id": "test-request-id",
                 "imp": [
@@ -56,7 +57,8 @@
                         "tagid": "100000000",
                         "ext": {
                             "bidder": {
-                                "TagID": "100000000"
+                                "TagID": "100000000",
+                                "placementId": "100000000"
                             }
                         }
                     }
diff --git a/adapters/adprime/params_test.go b/adapters/adprime/params_test.go
index 05adad5c..b466c658 100644
--- a/adapters/adprime/params_test.go
+++ b/adapters/adprime/params_test.go
@@ -36,7 +36,7 @@ func TestInvalidParams(t *testing.T) {
 }
 
 var validParams = []string{
-	`{"TagID": "1"}`,
+	`{"TagID": "test"}`,
 }
 
 var invalidParams = []string{
diff --git a/adapters/adview/adview_test.go b/adapters/adview/adview_test.go
new file mode 100644
index 00000000..5b872581
--- /dev/null
+++ b/adapters/adview/adview_test.go
@@ -0,0 +1,28 @@
+package adview
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderAdView, config.Adapter{
+		Endpoint: "https://bid.adview.com/agent/thirdAdxService/{{.AccountID}}"})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "adviewtest", bidder)
+}
+
+func TestEndpointTemplateMalformed(t *testing.T) {
+	_, buildErr := Builder(openrtb_ext.BidderAdView, config.Adapter{
+		Endpoint: "{{Malformed}}"})
+
+	assert.Error(t, buildErr)
+}
diff --git a/adapters/adview/adviewtest/exemplary/banner-app-format.json b/adapters/adview/adviewtest/exemplary/banner-app-format.json
new file mode 100644
index 00000000..49956cdc
--- /dev/null
+++ b/adapters/adview/adviewtest/exemplary/banner-app-format.json
@@ -0,0 +1,156 @@
+{
+  "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": {
+          "format": [
+            {
+              "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",
+          "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,
+                "format": [
+                  {
+                    "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
+                }
+              ],
+              "type": "banner",
+              "seat": "adview"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "adview": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 320,
+            "h": 50
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adview/adviewtest/exemplary/banner-app.json b/adapters/adview/adviewtest/exemplary/banner-app.json
new file mode 100644
index 00000000..e8697229
--- /dev/null
+++ b/adapters/adview/adviewtest/exemplary/banner-app.json
@@ -0,0 +1,146 @@
+{
+  "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",
+          "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
+                }
+              ],
+              "type": "banner",
+              "seat": "adview"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "adview": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 320,
+            "h": 50
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adview/adviewtest/exemplary/native-app.json b/adapters/adview/adviewtest/exemplary/native-app.json
new file mode 100644
index 00000000..df776a36
--- /dev/null
+++ b/adapters/adview/adviewtest/exemplary/native-app.json
@@ -0,0 +1,142 @@
+{
+  "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",
+        "native": {
+          "ver":"1.1",
+          "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"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",
+          "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",
+              "native": {
+                "ver":"1.1",
+                "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "posid00001",
+                  "accountId": "accountid01"
+                }
+              },
+              "tagid": "posid00001"
+            }
+          ],
+          "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"
+                }
+              ],
+              "type": "native",
+              "seat": "adview"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "adview": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ]
+          },
+          "type": "native"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adview/adviewtest/exemplary/video-app.json b/adapters/adview/adviewtest/exemplary/video-app.json
new file mode 100644
index 00000000..2136a8f7
--- /dev/null
+++ b/adapters/adview/adviewtest/exemplary/video-app.json
@@ -0,0 +1,155 @@
+{
+  "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",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "posid00001",
+            "accountId": "accountid01"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://bid.adview.com/agent/thirdAdxService/accountid01",
+        "body": {
+          "id": "some-request-id",
+          "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",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              },
+              "ext": {
+                "bidder": {
+                  "placementId": "posid00001",
+                  "accountId": "accountid01"
+                }   
+              },   
+              "tagid": "posid00001"
+            }
+          ],
+          "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": 1280,
+                  "h": 720
+                }
+              ],
+              "seat": "adview"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "adview": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "w": 1280,
+            "h": 720
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/adview/adviewtest/supplemental/bad-request.json b/adapters/adview/adviewtest/supplemental/bad-request.json
new file mode 100644
index 00000000..131e6d83
--- /dev/null
+++ b/adapters/adview/adviewtest/supplemental/bad-request.json
@@ -0,0 +1,50 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [{
+        "id": "test-imp-id",
+        "native": {
+          "request": ""
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "posid00001",
+            "accountId": "accountid01"
+          }
+        }
+      }]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://bid.adview.com/agent/thirdAdxService/accountid01",
+        "body": {
+          "id": "test-request-id",
+          "imp": [{
+            "ext": {
+              "bidder": {
+                "placementId": "posid00001",
+                "accountId": "accountid01"
+              }
+            },
+            "id": "test-imp-id",
+            "native": {
+              "request": ""
+            },
+            "tagid": "posid00001"
+          }]
+        }
+      },
+      "mockResponse": {
+        "status": 400
+      }
+    }
+  ],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [ 
+    {
+      "value": "Unexpected status code: 400. Bad request from publisher.",
+      "comparison": "literal" 
+    }
+  ]
+}
diff --git a/adapters/adview/adviewtest/supplemental/empty-response.json b/adapters/adview/adviewtest/supplemental/empty-response.json
new file mode 100644
index 00000000..5bd86bc9
--- /dev/null
+++ b/adapters/adview/adviewtest/supplemental/empty-response.json
@@ -0,0 +1,44 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [{
+        "id": "test-imp-id",
+        "native": {
+          "request": ""
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "posid00001",
+            "accountId": "accountid01"
+          }
+        }
+      }]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://bid.adview.com/agent/thirdAdxService/accountid01",
+        "body": {
+          "id": "test-request-id",
+          "imp": [{
+            "ext": {
+              "bidder": {
+                "placementId": "posid00001",
+                "accountId": "accountid01"
+              }
+            },
+            "id": "test-imp-id",
+            "native": {
+              "request": ""
+            },
+            "tagid": "posid00001"
+          }]
+        }
+      },
+      "mockResponse": {
+        "status": 204
+      }
+    }
+  ],
+  "expectedBidResponses": []
+}
diff --git a/adapters/adview/adviewtest/supplemental/nobid-response.json b/adapters/adview/adviewtest/supplemental/nobid-response.json
new file mode 100644
index 00000000..f2c8864d
--- /dev/null
+++ b/adapters/adview/adviewtest/supplemental/nobid-response.json
@@ -0,0 +1,51 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [{
+        "id": "test-imp-id",
+        "native": {
+          "request": ""
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "posid00001",
+            "accountId": "accountid01"
+          }
+        }
+      }]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://bid.adview.com/agent/thirdAdxService/accountid01",
+        "body": {
+          "id": "test-request-id",
+          "imp": [{
+            "ext": {
+              "bidder": {
+                "placementId": "posid00001",
+                "accountId": "accountid01"
+              }
+            },
+            "id": "test-imp-id",
+            "native": {
+              "request": ""
+            },
+            "tagid": "posid00001"
+          }]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": null,
+          "bidid": null,
+          "cur": null
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": []
+}
diff --git a/adapters/adview/adviewtest/supplemental/server-error.json b/adapters/adview/adviewtest/supplemental/server-error.json
new file mode 100644
index 00000000..7894be1b
--- /dev/null
+++ b/adapters/adview/adviewtest/supplemental/server-error.json
@@ -0,0 +1,51 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [{
+        "id": "test-imp-id",
+        "native": {
+          "request": ""
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "posid00001",
+            "accountId": "accountid01"
+          }
+        }
+      }]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://bid.adview.com/agent/thirdAdxService/accountid01",
+        "body": {
+          "id": "test-request-id",
+          "imp": [{
+            "ext": {
+              "bidder": {
+                "placementId": "posid00001",
+                "accountId": "accountid01"
+              }
+            },
+            "id": "test-imp-id",
+            "native": {
+              "request": ""
+            },
+            "tagid": "posid00001"
+          }]
+        }
+      },
+      "mockResponse": {
+        "status": 500,
+        "body": "Server error"
+      }
+    }
+  ],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [ 
+    {
+      "value": "Unexpected status code: 500.",
+      "comparison": "literal" 
+    }
+  ]
+}
diff --git a/adapters/adview/adviewtest/supplemental/unparsable-response.json b/adapters/adview/adviewtest/supplemental/unparsable-response.json
new file mode 100644
index 00000000..cef70ba8
--- /dev/null
+++ b/adapters/adview/adviewtest/supplemental/unparsable-response.json
@@ -0,0 +1,51 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [{
+        "id": "test-imp-id",
+        "native": {
+          "request": ""
+        },
+        "ext": {
+          "bidder": {
+            "placementId": "posid00001",
+            "accountId": "accountid01"
+          }
+        }
+      }]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://bid.adview.com/agent/thirdAdxService/accountid01",
+        "body": {
+          "id": "test-request-id",
+          "imp": [{
+            "ext": {
+              "bidder": {
+                "placementId": "posid00001",
+                "accountId": "accountid01"
+	      }
+            },
+            "id": "test-imp-id",
+            "native": {
+              "request": ""
+            },
+            "tagid": "posid00001"
+          }]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": ""
+      }
+    }
+  ],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "json: cannot unmarshal string into Go value of type openrtb2.BidResponse",
+      "comparison": "literal" 
+    }
+  ]
+}
diff --git a/adapters/adview/params_test.go b/adapters/adview/params_test.go
new file mode 100644
index 00000000..6d124e9b
--- /dev/null
+++ b/adapters/adview/params_test.go
@@ -0,0 +1,48 @@
+package adview
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestValidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, validParam := range validParams {
+		if err := validator.Validate(openrtb_ext.BidderAdView, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected adview params: %s", validParam)
+		}
+	}
+}
+
+func TestInvalidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, invalidParam := range invalidParams {
+		if err := validator.Validate(openrtb_ext.BidderAdView, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{ "placementId": "posid00001", "accountId": "accountid01"}`,
+}
+
+var invalidParams = []string{
+	``,
+	`null`,
+	`{}`,
+	`{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`,
+	`{ "accountId": "accountid01" }`,
+	`{ "placementId": "posid00001" }`,
+	`{ "placementId": "", "accountId": "" }`,
+}
diff --git a/adapters/improvedigital/improvedigitaltest/exemplary/app-multi.json b/adapters/improvedigital/improvedigitaltest/exemplary/app-multi.json
index 1aee6bdf..6963e82f 100644
--- a/adapters/improvedigital/improvedigitaltest/exemplary/app-multi.json
+++ b/adapters/improvedigital/improvedigitaltest/exemplary/app-multi.json
@@ -2,21 +2,24 @@
     "mockBidRequest": {
         "id": "test-request-id",
         "app": {
-			"id": "appID",
+            "id": "appID",
             "publisher": {
                 "id": "uniq_pub_id"
             }
         },
-		"device":{
-			"ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
-		},
-        "imp": [{
+        "device": {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
+        },
+        "imp": [
+            {
                 "id": "test-imp-id-banner",
                 "banner": {
-                    "format": [{
-                        "w": 300,
-                        "h": 250
-                    }]
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
                 },
                 "ext": {
                     "bidder": {
@@ -40,113 +43,160 @@
             }
         ]
     },
-
-    "httpCalls": [{
-        "expectedRequest": {
-            "uri": "http://localhost/pbs",
-            "body": {
-                "id": "test-request-id",
-				"app": {
-					"id": "appID",
-		            "publisher": {
-		                "id": "uniq_pub_id"
-		            }
-		        },
-				"device":{
-					"ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
-				},
-                "imp": [{
-                        "id": "test-imp-id-banner",
-                        "banner": {
-                            "format": [{
-                                "w": 300,
-                                "h": 250
-                            }]
-                        },
-                        "ext": {
-                            "bidder": {
-                                "placementId": 13245
-                            }
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://localhost/pbs",
+                "body": {
+                    "id": "test-request-id",
+                    "app": {
+                        "id": "appID",
+                        "publisher": {
+                            "id": "uniq_pub_id"
                         }
                     },
-                    {
-                        "id": "test-imp-id-video",
-                        "video": {
-                            "mimes": ["video/mp4"],
-                            "protocols": [2, 5],
-                            "w": 1920,
-                            "h": 1080
-                        },
-                        "ext": {
-                            "bidder": {
-                                "placementId": 13244
+                    "device": {
+                        "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
+                    },
+                    "imp": [
+                        {
+                            "id": "test-imp-id-banner",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ]
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": 13245
+                                }
                             }
                         }
-                    }
-                ]
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "improvedigital",
+                            "bid": [
+                                {
+                                    "id": "randomid1",
+                                    "impid": "test-imp-id-banner",
+                                    "price": 0.5,
+                                    "adid": "12345678",
+                                    "adm": "some-test-ad-html",
+                                    "cid": "987",
+                                    "crid": "12345678",
+                                    "h": 250,
+                                    "w": 300
+                                }
+                            ]
+                        }
+                    ],
+                    "cur": "USD"
+                }
             }
         },
-        "mockResponse": {
-            "status": 200,
-            "body": {
-                "id": "test-request-id",
-                "seatbid": [{
-                    "seat": "improvedigital",
-                    "bid": [{
-                            "id": "randomid1",
-                            "impid": "test-imp-id-banner",
-                            "price": 0.500000,
-                            "adid": "12345678",
-                            "adm": "some-test-ad-html",
-                            "cid": "987",
-                            "crid": "12345678",
-                            "h": 250,
-                            "w": 300
-                        },
+        {
+            "expectedRequest": {
+                "uri": "http://localhost/pbs",
+                "body": {
+                    "id": "test-request-id",
+                    "app": {
+                        "id": "appID",
+                        "publisher": {
+                            "id": "uniq_pub_id"
+                        }
+                    },
+                    "device": {
+                        "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
+                    },
+                    "imp": [
                         {
-                            "id": "randomid2",
-                            "impid": "test-imp-id-video",
-                            "price": 0.500000,
-                            "adm": "some-test-ad-vast",
-                            "crid": "1234567",
-                            "w": 1920,
-                            "h": 1080
+                            "id": "test-imp-id-video",
+                            "video": {
+                                "mimes": ["video/mp4"],
+                                "protocols": [2, 5],
+                                "w": 1920,
+                                "h": 1080
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": 13244
+                                }
+                            }
                         }
                     ]
-                }],
-                "cur": "USD"
-            }
-        }
-    }],
-
-    "expectedBidResponses": [{
-        "currency": "USD",
-        "bids": [{
-                "bid": {
-                    "id": "randomid1",
-                    "impid": "test-imp-id-banner",
-                    "price": 0.5,
-                    "adm": "some-test-ad-html",
-                    "adid": "12345678",
-                    "cid": "987",
-                    "crid": "12345678",
-                    "w": 300,
-                    "h": 250
-                },
-                "type": "banner"
+                }
             },
-            {
-                "bid": {
-                    "id": "randomid2",
-                    "impid": "test-imp-id-video",
-                    "price": 0.5,
-                    "adm": "some-test-ad-vast",
-                    "crid": "1234567",
-                    "w": 1920,
-                    "h": 1080
-                },
-                "type": "video"
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "improvedigital",
+                            "bid": [
+                                {
+                                    "id": "randomid2",
+                                    "impid": "test-imp-id-video",
+                                    "price": 0.5,
+                                    "adm": "some-test-ad-vast",
+                                    "crid": "1234567",
+                                    "w": 1920,
+                                    "h": 1080
+                                }
+                            ]
+                        }
+                    ],
+                    "cur": "USD"
+                }
             }
-        ]
-    }]
+        }
+    ],
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "randomid1",
+                        "impid": "test-imp-id-banner",
+                        "price": 0.5,
+                        "adm": "some-test-ad-html",
+                        "adid": "12345678",
+                        "cid": "987",
+                        "crid": "12345678",
+                        "w": 300,
+                        "h": 250
+                    },
+                    "type": "banner"
+                }
+            ]
+        },
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "randomid2",
+                        "impid": "test-imp-id-video",
+                        "price": 0.5,
+                        "adm": "some-test-ad-vast",
+                        "crid": "1234567",
+                        "w": 1920,
+                        "h": 1080
+                    },
+                    "type": "video"
+                }
+            ]
+        }
+    ]
 }
diff --git a/adapters/improvedigital/improvedigitaltest/exemplary/site-multi.json b/adapters/improvedigital/improvedigitaltest/exemplary/site-multi.json
index 5fb4f061..0945b4c0 100644
--- a/adapters/improvedigital/improvedigitaltest/exemplary/site-multi.json
+++ b/adapters/improvedigital/improvedigitaltest/exemplary/site-multi.json
@@ -12,13 +12,16 @@
                 "amp": 0
             }
         },
-        "imp": [{
+        "imp": [
+            {
                 "id": "test-imp-id-banner",
                 "banner": {
-                    "format": [{
-                        "w": 300,
-                        "h": 250
-                    }]
+                    "format": [
+                        {
+                            "w": 300,
+                            "h": 250
+                        }
+                    ]
                 },
                 "ext": {
                     "bidder": {
@@ -43,114 +46,165 @@
         ]
     },
 
-    "httpCalls": [{
-        "expectedRequest": {
-            "uri": "http://localhost/pbs",
-            "body": {
-                "id": "test-request-id",
-                "site": {
-                    "page": "https://good.site/url",
-                    "domain": "good.site",
-                    "publisher": {
-                        "id": "uniq_pub_id"
-                    },
-                    "keywords": "omgword",
-                    "ext": {
-                        "amp": 0
-                    }
-                },
-                "imp": [{
-                        "id": "test-imp-id-banner",
-                        "banner": {
-                            "format": [{
-                                "w": 300,
-                                "h": 250
-                            }]
+    "httpCalls": [
+        {
+            "expectedRequest": {
+                "uri": "http://localhost/pbs",
+                "body": {
+                    "id": "test-request-id",
+                    "site": {
+                        "page": "https://good.site/url",
+                        "domain": "good.site",
+                        "publisher": {
+                            "id": "uniq_pub_id"
                         },
+                        "keywords": "omgword",
                         "ext": {
-                            "bidder": {
-                                "placementId": 13245
-                            }
+                            "amp": 0
                         }
                     },
-                    {
-                        "id": "test-imp-id-video",
-                        "video": {
-                            "mimes": ["video/mp4"],
-                            "protocols": [2, 5],
-                            "w": 1920,
-                            "h": 1080
-                        },
-                        "ext": {
-                            "bidder": {
-                                "placementId": 13244
+                    "imp": [
+                        {
+                            "id": "test-imp-id-banner",
+                            "banner": {
+                                "format": [
+                                    {
+                                        "w": 300,
+                                        "h": 250
+                                    }
+                                ]
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": 13245
+                                }
                             }
                         }
-                    }
-                ]
+                    ]
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "improvedigital",
+                            "bid": [
+                                {
+                                    "id": "randomid1",
+                                    "impid": "test-imp-id-banner",
+                                    "price": 0.5,
+                                    "adid": "12345678",
+                                    "adm": "some-test-ad-html",
+                                    "cid": "987",
+                                    "crid": "12345678",
+                                    "h": 250,
+                                    "w": 300
+                                }
+                            ]
+                        }
+                    ],
+                    "cur": "USD"
+                }
             }
         },
-        "mockResponse": {
-            "status": 200,
-            "body": {
-                "id": "test-request-id",
-                "seatbid": [{
-                    "seat": "improvedigital",
-                    "bid": [{
-                            "id": "randomid1",
-                            "impid": "test-imp-id-banner",
-                            "price": 0.500000,
-                            "adid": "12345678",
-                            "adm": "some-test-ad-html",
-                            "cid": "987",
-                            "crid": "12345678",
-                            "h": 250,
-                            "w": 300
+        {
+            "expectedRequest": {
+                "uri": "http://localhost/pbs",
+                "body": {
+                    "id": "test-request-id",
+                    "site": {
+                        "page": "https://good.site/url",
+                        "domain": "good.site",
+                        "publisher": {
+                            "id": "uniq_pub_id"
                         },
+                        "keywords": "omgword",
+                        "ext": {
+                            "amp": 0
+                        }
+                    },
+                    "imp": [
                         {
-                            "id": "randomid2",
-                            "impid": "test-imp-id-video",
-                            "price": 0.500000,
-                            "adm": "some-test-ad-vast",
-                            "crid": "1234567",
-                            "w": 1920,
-                            "h": 1080
+                            "id": "test-imp-id-video",
+                            "video": {
+                                "mimes": ["video/mp4"],
+                                "protocols": [2, 5],
+                                "w": 1920,
+                                "h": 1080
+                            },
+                            "ext": {
+                                "bidder": {
+                                    "placementId": 13244
+                                }
+                            }
                         }
                     ]
-                }],
-                "cur": "USD"
+                }
+            },
+            "mockResponse": {
+                "status": 200,
+                "body": {
+                    "id": "test-request-id",
+                    "seatbid": [
+                        {
+                            "seat": "improvedigital",
+                            "bid": [
+                                {
+                                    "id": "randomid2",
+                                    "impid": "test-imp-id-video",
+                                    "price": 0.5,
+                                    "adm": "some-test-ad-vast",
+                                    "crid": "1234567",
+                                    "w": 1920,
+                                    "h": 1080
+                                }
+                            ]
+                        }
+                    ],
+                    "cur": "USD"
+                }
             }
         }
-    }],
+    ],
 
-    "expectedBidResponses": [{
-        "currency": "USD",
-        "bids": [{
-                "bid": {
-                    "id": "randomid1",
-                    "impid": "test-imp-id-banner",
-                    "price": 0.5,
-                    "adm": "some-test-ad-html",
-                    "adid": "12345678",
-                    "cid": "987",
-                    "crid": "12345678",
-                    "w": 300,
-                    "h": 250
-                },
-                "type": "banner"
-            },
-            {
-                "bid": {
-                    "id": "randomid2",
-                    "impid": "test-imp-id-video",
-                    "price": 0.5,
-                    "adm": "some-test-ad-vast",
-                    "crid": "1234567",
-                    "w": 1920,
-                    "h": 1080
-                },
-                "type": "video"
-            }
-        ]
-    }]
+    "expectedBidResponses": [
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "randomid1",
+                        "impid": "test-imp-id-banner",
+                        "price": 0.5,
+                        "adm": "some-test-ad-html",
+                        "adid": "12345678",
+                        "cid": "987",
+                        "crid": "12345678",
+                        "w": 300,
+                        "h": 250
+                    },
+                    "type": "banner"
+                }
+            ]
+        },
+        {
+            "currency": "USD",
+            "bids": [
+                {
+                    "bid": {
+                        "id": "randomid2",
+                        "impid": "test-imp-id-video",
+                        "price": 0.5,
+                        "adm": "some-test-ad-vast",
+                        "crid": "1234567",
+                        "w": 1920,
+                        "h": 1080
+                    },
+                    "type": "video"
+                }
+            ]
+        }
+    ]
 }
diff --git a/adapters/visx/visxtest/exemplary/simple-banner.json b/adapters/visx/visxtest/exemplary/simple-banner.json
index 2840521c..0f34e6f0 100644
--- a/adapters/visx/visxtest/exemplary/simple-banner.json
+++ b/adapters/visx/visxtest/exemplary/simple-banner.json
@@ -22,9 +22,6 @@
             "secure": 1,
             "ext": {
                 "bidder": {
-                    "ga_parms": {
-                        "place_on_page": "ATF"
-                    },
                     "size": [
                         300,
                         250
@@ -89,9 +86,6 @@
                     "secure": 1,
                     "ext": {
                         "bidder": {
-                            "ga_parms": {
-                                "place_on_page": "ATF"
-                            },
                             "size": [
                                 300,
                                 250
diff --git a/adapters/visx/visxtest/exemplary/simple-video.json b/adapters/visx/visxtest/exemplary/simple-video.json
new file mode 100644
index 00000000..b39dad74
--- /dev/null
+++ b/adapters/visx/visxtest/exemplary/simple-video.json
@@ -0,0 +1,173 @@
+{
+    "mockBidRequest": {
+        "id": "test-request-id",
+        "site": {
+            "domain": "good.site",
+            "page": "https://good.site/url",
+            "publisher": {
+                "id": "test-publisher-id"
+            },
+            "ext": {
+                "amp": 0
+            }
+        },
+        "imp": [{
+            "id": "test-imp-id",
+            "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 300,
+                "h": 250
+            },
+            "secure": 1,
+            "ext": {
+                "bidder": {
+                    "size": [
+                        300,
+                        250
+                    ],
+                    "uid": 11
+                }
+            }
+        }],
+        "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "h": 700,
+            "w": 375,
+            "ext": {
+                "prebid": {
+                    "interstitial": {
+                        "minwidthperc": 50,
+                        "minheightperc": 40
+                    }
+                }
+            }
+        },
+        "at": 1,
+        "tmax": 2000,
+        "source": {
+            "tid": "283746293874293"
+        },
+        "ext": {
+            "prebid": {
+                "aliases": {
+                    "districtm": "appnexus",
+                    "emxdigital": "appnexus"
+                }
+            }
+        }
+    },
+
+    "httpCalls": [{
+        "expectedRequest": {
+            "uri": "http://localhost/prebid",
+            "body": {
+                "id": "test-request-id",
+                "site": {
+                    "domain": "good.site",
+                    "page": "https://good.site/url",
+                    "publisher": {
+                        "id": "test-publisher-id"
+                    },
+                    "ext": {
+                        "amp": 0
+                    }
+                },
+                "cur": ["USD"],
+                "imp": [{
+                    "id": "test-imp-id",
+                    "video": {
+                        "mimes": ["video/mp4"],
+                        "protocols": [2, 5],
+                        "w": 300,
+                        "h": 250
+                    },
+                    "secure": 1,
+                    "ext": {
+                        "bidder": {
+                            "size": [
+                                300,
+                                250
+                            ],
+                            "uid": 11
+                        }
+                    }
+                }],
+                "device": {
+                    "ua": "test-user-agent",
+                    "ip": "123.123.123.123",
+                    "h": 700,
+                    "w": 375,
+                    "ext": {
+                        "prebid": {
+                            "interstitial": {
+                                "minwidthperc": 50,
+                                "minheightperc": 40
+                            }
+                        }
+                    }
+                },
+                "at": 1,
+                "tmax": 2000,
+                "source": {
+                    "tid": "283746293874293"
+                },
+                "ext": {
+                    "prebid": {
+                        "aliases": {
+                            "districtm": "appnexus",
+                            "emxdigital": "appnexus"
+                        }
+                    }
+                }
+            }
+        },
+        "mockResponse": {
+            "status": 200,
+            "body": {
+                "cur": ["USD"],
+                "seatbid": [
+                    {
+                        "bid": [
+                            {
+                                "crid": "2_260",
+                                "price": 0.500000,
+                                "adm": "some-test-ad-vast",
+                                "impid": "test-imp-id",
+                                "auid": 11,
+                                "h": 250,
+                                "adomain": [
+                                    "goodadvertiser.com"
+                                ],
+                                "dealid": "test_deal_id",
+                                "w": 300
+                            }
+                        ],
+                        "seat": "51"
+                    }
+                ]
+            }
+        }
+    }],
+
+    "expectedBidResponses": [{
+        "currency": "USD",
+        "bids": [{
+            "bid": {
+                "price": 0.5,
+                "adm": "some-test-ad-vast",
+                "impid": "test-imp-id",
+                "id": "test-request-id",
+                "h": 250,
+                "adomain": [
+                    "goodadvertiser.com"
+                ],
+                "dealid": "test_deal_id",
+                "crid": "2_260",
+                "w": 300
+            },
+            "type": "video"
+        }]
+    }]
+}
diff --git a/adapters/visx/visxtest/supplemental/wrong_imp_type.json b/adapters/visx/visxtest/supplemental/wrong_imp_type.json
new file mode 100644
index 00000000..659a0204
--- /dev/null
+++ b/adapters/visx/visxtest/supplemental/wrong_imp_type.json
@@ -0,0 +1,74 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "ext": {
+          "bidder": {
+            "size": [
+              300,
+              250
+            ],
+            "uid": 7
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://localhost/prebid",
+        "body": {
+          "id": "test-request-id",
+          "cur": ["USD"],
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "ext": {
+                "bidder": {
+                  "size": [
+                    300,
+                    250
+                  ],
+                  "uid": 7
+                }
+              }
+            }
+          ]
+        }
+      },
+	  "mockResponse": {
+		  "status": 200,
+		  "body": {
+              "cur": ["USD"],
+			  "seatbid": [{
+				  "seat": "51",
+				  "bid": [{
+                      "crid": "2_260",
+                      "price": 0.500000,
+                      "adm": "some-test-ad",
+                      "impid": "test-imp-id",
+                      "auid": 46,
+                      "h": 250,
+                      "adomain": [
+                        "goodadvertiser.com"
+                      ],
+                      "dealid": "test_deal_id",
+                      "w": 300
+				  }]
+			  }]
+		  }
+	  }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unknown impression type for ID: \"test-imp-id\"",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/visx/visxtest/supplemental/wrong_impid.json b/adapters/visx/visxtest/supplemental/wrong_impid.json
new file mode 100644
index 00000000..ac18ac07
--- /dev/null
+++ b/adapters/visx/visxtest/supplemental/wrong_impid.json
@@ -0,0 +1,82 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "uid": 7
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://localhost/prebid",
+        "body": {
+          "id": "test-request-id",
+          "cur": ["USD"],
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "uid": 7
+                }
+              }
+            }
+          ]
+        }
+      },
+	  "mockResponse": {
+		  "status": 200,
+		  "body": {
+              "cur": ["USD"],
+			  "seatbid": [{
+				  "seat": "51",
+				  "bid": [{
+                      "crid": "2_260",
+                      "price": 0.500000,
+                      "adm": "some-test-ad",
+                      "impid": "unknown_impid",
+                      "auid": 46,
+                      "h": 250,
+                      "adomain": [
+                        "goodadvertiser.com"
+                      ],
+                      "dealid": "test_deal_id",
+                      "w": 300
+				  }]
+			  }]
+		  }
+	  }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Failed to find impression for ID: \"unknown_impid\"",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/config/config_test.go b/config/config_test.go
index 2e889a79..b22b384d 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -108,6 +108,11 @@ func TestExternalCacheURLValidate(t *testing.T) {
 			data:      ExternalCache{Scheme: "https", Host: "www.google.com", Path: "/path/v1"},
 			expErrors: 0,
 		},
+		{
+			desc:      "Host with port",
+			data:      ExternalCache{Scheme: "https", Host: "localhost:2424", Path: "/path/v1"},
+			expErrors: 0,
+		},
 	}
 	for _, test := range testCases {
 		errs := test.data.validate([]error{})
diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go
index 667c4aef..ae3c036a 100644
--- a/endpoints/openrtb2/amp_auction_test.go
+++ b/endpoints/openrtb2/amp_auction_test.go
@@ -11,6 +11,8 @@ import (
 	"strconv"
 	"testing"
 
+	"github.com/julienschmidt/httprouter"
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
 	"github.com/prebid/prebid-server/analytics"
 	analyticsConf "github.com/prebid/prebid-server/analytics/config"
 	"github.com/prebid/prebid-server/config"
@@ -19,7 +21,6 @@ import (
 	"github.com/prebid/prebid-server/openrtb_ext"
 	"github.com/prebid/prebid-server/stored_requests/backends/empty_fetcher"
 
-	"github.com/mxmCherry/openrtb/v15/openrtb2"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -38,6 +39,7 @@ func TestGoodAmpRequests(t *testing.T) {
 	}
 
 	endpoint, _ := NewAmpEndpoint(
+		fakeUUIDGenerator{},
 		&mockAmpExchange{},
 		newParamsValidator(t),
 		&mockAmpStoredReqFetcher{goodRequests},
@@ -91,6 +93,7 @@ func TestAMPPageInfo(t *testing.T) {
 	exchange := &mockAmpExchange{}
 
 	endpoint, _ := NewAmpEndpoint(
+		fakeUUIDGenerator{},
 		exchange,
 		newParamsValidator(t),
 		&mockAmpStoredReqFetcher{stored},
@@ -188,6 +191,7 @@ func TestGDPRConsent(t *testing.T) {
 		// Build Exchange Endpoint
 		mockExchange := &mockAmpExchange{}
 		endpoint, _ := NewAmpEndpoint(
+			fakeUUIDGenerator{},
 			mockExchange,
 			newParamsValidator(t),
 			&mockAmpStoredReqFetcher{stored},
@@ -340,6 +344,7 @@ func TestCCPAConsent(t *testing.T) {
 		// Build Exchange Endpoint
 		mockExchange := &mockAmpExchange{}
 		endpoint, _ := NewAmpEndpoint(
+			fakeUUIDGenerator{},
 			mockExchange,
 			newParamsValidator(t),
 			&mockAmpStoredReqFetcher{stored},
@@ -450,6 +455,7 @@ func TestConsentWarnings(t *testing.T) {
 			mockExchange = &mockAmpExchange{}
 		}
 		endpoint, _ := NewAmpEndpoint(
+			fakeUUIDGenerator{},
 			mockExchange,
 			newParamsValidator(t),
 			&mockAmpStoredReqFetcher{stored},
@@ -542,6 +548,7 @@ func TestNewAndLegacyConsentBothProvided(t *testing.T) {
 		// Build Exchange Endpoint
 		mockExchange := &mockAmpExchange{}
 		endpoint, _ := NewAmpEndpoint(
+			fakeUUIDGenerator{},
 			mockExchange,
 			newParamsValidator(t),
 			&mockAmpStoredReqFetcher{stored},
@@ -593,6 +600,7 @@ func TestAMPSiteExt(t *testing.T) {
 	}
 	exchange := &mockAmpExchange{}
 	endpoint, _ := NewAmpEndpoint(
+		fakeUUIDGenerator{},
 		exchange,
 		newParamsValidator(t),
 		&mockAmpStoredReqFetcher{stored},
@@ -629,6 +637,7 @@ func TestAmpBadRequests(t *testing.T) {
 	}
 
 	endpoint, _ := NewAmpEndpoint(
+		fakeUUIDGenerator{},
 		&mockAmpExchange{},
 		newParamsValidator(t),
 		&mockAmpStoredReqFetcher{badRequests},
@@ -659,6 +668,7 @@ func TestAmpDebug(t *testing.T) {
 	}
 
 	endpoint, _ := NewAmpEndpoint(
+		fakeUUIDGenerator{},
 		&mockAmpExchange{},
 		newParamsValidator(t),
 		&mockAmpStoredReqFetcher{requests},
@@ -731,6 +741,7 @@ func TestQueryParamOverrides(t *testing.T) {
 	}
 
 	endpoint, _ := NewAmpEndpoint(
+		fakeUUIDGenerator{},
 		&mockAmpExchange{},
 		newParamsValidator(t),
 		&mockAmpStoredReqFetcher{requests},
@@ -883,6 +894,7 @@ func (s formatOverrideSpec) execute(t *testing.T) {
 	}
 
 	endpoint, _ := NewAmpEndpoint(
+		fakeUUIDGenerator{},
 		&mockAmpExchange{},
 		newParamsValidator(t),
 		&mockAmpStoredReqFetcher{requests},
@@ -1249,31 +1261,8 @@ func TestBuildAmpObject(t *testing.T) {
 	recorder := httptest.NewRecorder()
 
 	for _, test := range testCases {
-
 		// Set up test, declare a new mock logger every time
-		actualAmpObject := new(analytics.AmpObject)
-
-		logger := newMockLogger(actualAmpObject)
-
-		mockAmpFetcher := &mockAmpStoredReqFetcher{
-			data: map[string]json.RawMessage{
-				test.inTagId: json.RawMessage(test.inStoredRequest),
-			},
-		}
-
-		endpoint, _ := NewAmpEndpoint(
-			&mockAmpExchange{},
-			newParamsValidator(t),
-			mockAmpFetcher,
-			empty_fetcher.EmptyFetcher{},
-			&config.Configuration{MaxRequestSize: maxSize},
-			&metricsConfig.DummyMetricsEngine{},
-			logger,
-			map[string]string{},
-			[]byte{},
-			openrtb_ext.BuildBidderMap(),
-		)
-
+		actualAmpObject, endpoint := AmpObjectTestSetup(t, test.inTagId, test.inStoredRequest, false)
 		// Run test
 		endpoint(recorder, request, nil)
 
@@ -1286,3 +1275,76 @@ func TestBuildAmpObject(t *testing.T) {
 		assert.Equalf(t, test.expectedAmpObject.Origin, actualAmpObject.Origin, "Amp Object Origin field doesn't match expected: %s\n", test.description)
 	}
 }
+
+func TestIdGeneration(t *testing.T) {
+	uuid := "foo"
+
+	testCases := []struct {
+		description            string
+		givenInStoredRequest   json.RawMessage
+		givenGenerateRequestID bool
+		expectedID             string
+	}{
+		{
+			description:            "The givenGenerateRequestID flag is set to true, so even though the stored amp request already has an id, we should still generate a new uuid",
+			givenInStoredRequest:   json.RawMessage(`{"id":"ThisID","site":{"page":"prebid.org"},"imp":[{"id":"some-imp-id","banner":{"format":[{"w":300,"h":250}]},"ext":{"appnexus":{"placementId":1}}}],"tmax":1}`),
+			givenGenerateRequestID: true,
+			expectedID:             uuid,
+		},
+		{
+			description:            "The givenGenerateRequestID flag is set to true and the stored amp request ID is blank, so we should generate a new uuid for the request",
+			givenInStoredRequest:   json.RawMessage(`{"id":"","site":{"page":"prebid.org"},"imp":[{"id":"some-imp-id","banner":{"format":[{"w":300,"h":250}]},"ext":{"appnexus":{"placementId":1}}}],"tmax":1}`),
+			givenGenerateRequestID: true,
+			expectedID:             uuid,
+		},
+		{
+			description:            "The givenGenerateRequestID flag is false, so the ID shouldn't change",
+			givenInStoredRequest:   json.RawMessage(`{"id":"ThisID","site":{"page":"prebid.org"},"imp":[{"id":"some-imp-id","banner":{"format":[{"w":300,"h":250}]},"ext":{"appnexus":{"placementId":1}}}],"tmax":1}`),
+			givenGenerateRequestID: false,
+			expectedID:             "ThisID",
+		},
+		{
+			description:            "The givenGenerateRequestID flag is true, and if the id field isn't included in the stored request",
+			givenInStoredRequest:   json.RawMessage(`{"site":{"page":"prebid.org"},"imp":[{"id":"some-imp-id","banner":{"format":[{"w":300,"h":250}]},"ext":{"appnexus":{"placementId":1}}}],"tmax":1}`),
+			givenGenerateRequestID: true,
+			expectedID:             uuid,
+		},
+	}
+
+	request := httptest.NewRequest("GET", "/openrtb2/auction/amp?tag_id=test", nil)
+	recorder := httptest.NewRecorder()
+
+	for _, test := range testCases {
+		// Set up and run test
+		actualAmpObject, endpoint := AmpObjectTestSetup(t, "test", test.givenInStoredRequest, test.givenGenerateRequestID)
+		endpoint(recorder, request, nil)
+
+		assert.Equalf(t, test.expectedID, actualAmpObject.Request.ID, "Bid Request ID is incorrect: %s\n", test.description)
+	}
+}
+
+func AmpObjectTestSetup(t *testing.T, inTagId string, inStoredRequest json.RawMessage, generateRequestID bool) (*analytics.AmpObject, httprouter.Handle) {
+	actualAmpObject := analytics.AmpObject{}
+	logger := newMockLogger(&actualAmpObject)
+
+	mockAmpFetcher := &mockAmpStoredReqFetcher{
+		data: map[string]json.RawMessage{
+			inTagId: json.RawMessage(inStoredRequest),
+		},
+	}
+
+	endpoint, _ := NewAmpEndpoint(
+		fakeUUIDGenerator{id: "foo", err: nil},
+		&mockAmpExchange{},
+		newParamsValidator(t),
+		mockAmpFetcher,
+		empty_fetcher.EmptyFetcher{},
+		&config.Configuration{MaxRequestSize: maxSize, GenerateRequestID: generateRequestID},
+		&metricsConfig.DummyMetricsEngine{},
+		logger,
+		map[string]string{},
+		[]byte{},
+		openrtb_ext.BuildBidderMap(),
+	)
+	return &actualAmpObject, endpoint
+}
diff --git a/endpoints/openrtb2/auction_benchmark_test.go b/endpoints/openrtb2/auction_benchmark_test.go
index ecc0554f..f2e0fb2a 100644
--- a/endpoints/openrtb2/auction_benchmark_test.go
+++ b/endpoints/openrtb2/auction_benchmark_test.go
@@ -87,6 +87,7 @@ func BenchmarkOpenrtbEndpoint(b *testing.B) {
 	)
 
 	endpoint, _ := NewEndpoint(
+		fakeUUIDGenerator{},
 		exchange,
 		paramValidator,
 		empty_fetcher.EmptyFetcher{},
diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go
index 31c3c109..ebf18994 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -430,6 +430,7 @@ func TestExplicitUserId(t *testing.T) {
 	})
 
 	endpoint, _ := NewEndpoint(
+		fakeUUIDGenerator{},
 		ex,
 		newParamsValidator(t),
 		empty_fetcher.EmptyFetcher{},
@@ -464,6 +465,7 @@ func doRequest(t *testing.T, test testCase) (int, string) {
 	mockExchange := newMockBidExchange(test.Config.MockBidder, test.Config.CurrencyRates)
 
 	endpoint, _ := NewEndpoint(
+		fakeUUIDGenerator{},
 		mockExchange,
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -534,6 +536,7 @@ func doBadAliasRequest(t *testing.T, filename string, expectMsg string) {
 	// NewMetrics() will create a new go_metrics MetricsEngine, bypassing the need for a crafted configuration set to support it.
 	// As a side effect this gives us some coverage of the go_metrics piece of the metrics engine.
 	endpoint, _ := NewEndpoint(
+		fakeUUIDGenerator{},
 		&nobidExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -584,6 +587,7 @@ func TestNilExchange(t *testing.T) {
 	// NewMetrics() will create a new go_metrics MetricsEngine, bypassing the need for a crafted configuration set to support it.
 	// As a side effect this gives us some coverage of the go_metrics piece of the metrics engine.
 	_, err := NewEndpoint(
+		fakeUUIDGenerator{},
 		nil,
 		newParamsValidator(t),
 		empty_fetcher.EmptyFetcher{},
@@ -604,6 +608,7 @@ func TestNilValidator(t *testing.T) {
 	// NewMetrics() will create a new go_metrics MetricsEngine, bypassing the need for a crafted configuration set to support it.
 	// As a side effect this gives us some coverage of the go_metrics piece of the metrics engine.
 	_, err := NewEndpoint(
+		fakeUUIDGenerator{},
 		&nobidExchange{},
 		nil,
 		empty_fetcher.EmptyFetcher{},
@@ -625,6 +630,7 @@ func TestExchangeError(t *testing.T) {
 	// NewMetrics() will create a new go_metrics MetricsEngine, bypassing the need for a crafted configuration set to support it.
 	// As a side effect this gives us some coverage of the go_metrics piece of the metrics engine.
 	endpoint, _ := NewEndpoint(
+		fakeUUIDGenerator{},
 		&brokenExchange{},
 		newParamsValidator(t),
 		empty_fetcher.EmptyFetcher{},
@@ -747,6 +753,7 @@ func TestImplicitIPsEndToEnd(t *testing.T) {
 			},
 		}
 		endpoint, _ := NewEndpoint(
+			fakeUUIDGenerator{},
 			exchange,
 			newParamsValidator(t),
 			&mockStoredReqFetcher{},
@@ -941,6 +948,7 @@ func TestImplicitDNTEndToEnd(t *testing.T) {
 	for _, test := range testCases {
 		exchange := &nobidExchange{}
 		endpoint, _ := NewEndpoint(
+			fakeUUIDGenerator{},
 			exchange,
 			newParamsValidator(t),
 			&mockStoredReqFetcher{},
@@ -1094,6 +1102,7 @@ func TestParseImpInfoMultipleImpressions(t *testing.T) {
 // Test the stored request functionality
 func TestStoredRequests(t *testing.T) {
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		&nobidExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -1140,10 +1149,81 @@ func TestStoredRequests(t *testing.T) {
 	}
 }
 
+func TestStoredRequestGenerateUuid(t *testing.T) {
+	uuid := "foo"
+
+	deps := &endpointDeps{
+		fakeUUIDGenerator{id: "foo", err: nil},
+		&nobidExchange{},
+		newParamsValidator(t),
+		&mockStoredReqFetcher{},
+		empty_fetcher.EmptyFetcher{},
+		empty_fetcher.EmptyFetcher{},
+		&config.Configuration{MaxRequestSize: maxSize},
+		&metricsConfig.DummyMetricsEngine{},
+		analyticsConf.NewPBSAnalytics(&config.Analytics{}),
+		map[string]string{},
+		false,
+		[]byte{},
+		openrtb_ext.BuildBidderMap(),
+		nil,
+		nil,
+		hardcodedResponseIPValidator{response: true},
+	}
+
+	req := &openrtb2.BidRequest{}
+
+	testCases := []struct {
+		description            string
+		givenRawData           string
+		givenGenerateRequestID bool
+		expectedID             string
+	}{
+		{
+			description:            "GenerateRequestID is true, rawData is an app request, and stored bid we should generate uuid",
+			givenRawData:           testStoredRequestsUuid[2],
+			givenGenerateRequestID: true,
+			expectedID:             uuid,
+		},
+		{
+			description:            "GenerateRequestID is true, rawData is an app request, but no stored bid, we should not generate uuid",
+			givenRawData:           testStoredRequestsUuid[0],
+			givenGenerateRequestID: true,
+			expectedID:             "ThisID",
+		},
+		{
+			description:            "GenerateRequestID is false so we should not generate uuid",
+			givenRawData:           testStoredRequestsUuid[0],
+			givenGenerateRequestID: false,
+			expectedID:             "ThisID",
+		},
+		{
+			description:            "GenerateRequestID is true, but rawData is a site request, we should not generate uuid",
+			givenRawData:           testStoredRequestsUuid[1],
+			givenGenerateRequestID: true,
+			expectedID:             "ThisID",
+		},
+	}
+
+	for _, test := range testCases {
+		deps.cfg.GenerateRequestID = test.givenGenerateRequestID
+		impInfo, errs := parseImpInfo([]byte(test.givenRawData))
+		assert.Empty(t, errs, test.description)
+		newRequest, _, errList := deps.processStoredRequests(context.Background(), json.RawMessage(test.givenRawData), impInfo)
+		assert.Empty(t, errList, test.description)
+
+		if err := json.Unmarshal(newRequest, req); err != nil {
+			t.Errorf("processStoredRequests Error: %s", err.Error())
+		}
+		assert.Equalf(t, test.expectedID, req.ID, "The Bid Request ID is incorrect: %s\n", test.description)
+	}
+}
+
 // TestOversizedRequest makes sure we behave properly when the request size exceeds the configured max.
 func TestOversizedRequest(t *testing.T) {
 	reqBody := validRequest(t, "site.json")
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		&nobidExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -1179,6 +1259,7 @@ func TestOversizedRequest(t *testing.T) {
 func TestRequestSizeEdgeCase(t *testing.T) {
 	reqBody := validRequest(t, "site.json")
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		&nobidExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -1213,6 +1294,7 @@ func TestRequestSizeEdgeCase(t *testing.T) {
 // TestNoEncoding prevents #231.
 func TestNoEncoding(t *testing.T) {
 	endpoint, _ := NewEndpoint(
+		fakeUUIDGenerator{},
 		&mockExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -1288,6 +1370,7 @@ func TestExplicitAMP(t *testing.T) {
 // TestContentType prevents #328
 func TestContentType(t *testing.T) {
 	endpoint, _ := NewEndpoint(
+		fakeUUIDGenerator{},
 		&mockExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -1607,6 +1690,7 @@ func TestValidateImpExt(t *testing.T) {
 	}
 
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		&nobidExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -1653,6 +1737,7 @@ func validRequest(t *testing.T, filename string) string {
 
 func TestCurrencyTrunc(t *testing.T) {
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		&nobidExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -1697,6 +1782,7 @@ func TestCurrencyTrunc(t *testing.T) {
 
 func TestCCPAInvalid(t *testing.T) {
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		&nobidExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -1745,6 +1831,7 @@ func TestCCPAInvalid(t *testing.T) {
 
 func TestNoSaleInvalid(t *testing.T) {
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		&nobidExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -1796,6 +1883,7 @@ func TestValidateSourceTID(t *testing.T) {
 	}
 
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		&nobidExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -1837,6 +1925,7 @@ func TestValidateSourceTID(t *testing.T) {
 
 func TestSChainInvalid(t *testing.T) {
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		&nobidExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -2056,6 +2145,7 @@ func TestValidateAndFillSourceTID(t *testing.T) {
 
 func TestEidPermissionsInvalid(t *testing.T) {
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		&nobidExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -2307,6 +2397,7 @@ func TestIOS14EndToEnd(t *testing.T) {
 	exchange := &nobidExchange{}
 
 	endpoint, _ := NewEndpoint(
+		fakeUUIDGenerator{},
 		exchange,
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -2334,6 +2425,7 @@ func TestIOS14EndToEnd(t *testing.T) {
 func TestAuctionWarnings(t *testing.T) {
 	reqBody := validRequest(t, "us-privacy-invalid.json")
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		&warningsCheckExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -2373,6 +2465,7 @@ func TestAuctionWarnings(t *testing.T) {
 func TestParseRequestParseImpInfoError(t *testing.T) {
 	reqBody := validRequest(t, "imp-info-invalid.json")
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		&warningsCheckExchange{},
 		newParamsValidator(t),
 		&mockStoredReqFetcher{},
@@ -3452,6 +3545,105 @@ var testStoredImps = []string{
 	``,
 }
 
+var testStoredRequestsUuid = []string{
+	`{
+		"id": "ThisID",
+		"app": {
+			"id": "123"
+		},
+		"imp": [
+			{
+				"video":{
+					"h":300,
+					"w":200
+				},
+				"ext": {
+					"prebid": {
+						"storedrequest": {
+							"id": "1"
+						},
+						"options": {
+							"echovideoattrs": true
+						}
+					}
+				}
+			}
+		],
+		"ext": {
+			"prebid": {
+				"cache": {
+					"markup": 1
+				},
+				"targeting": {
+				}
+			}
+		}
+	}`,
+	`{
+		"id": "ThisID",
+		"site": {
+			"page": "prebid.org"
+		},
+		"imp": [
+			{
+				"id": "adUnit2",
+				"ext": {
+					"prebid": {
+						"storedrequest": {
+							"id": "1"
+						},
+						"options": {
+							"echovideoattrs": true
+						}
+					},
+					"appnexus": {
+						"placementId": "def",
+						"trafficSourceCode": "mysite.com",
+						"reserve": null
+					},
+					"rubicon": null
+				}
+			}
+		],
+		"ext": {
+			"prebid": {
+				"cache": {
+					"markup": 1
+				},
+				"targeting": {
+				}
+			}
+		}
+	}`,
+	`{
+		"id": "ThisID",
+		"app": {
+			"id": "123"
+		},
+		"imp": [
+			{
+				"ext": {
+					"prebid": {
+						"storedrequest": {
+							"id": "2"
+						},
+						"options": {
+							"echovideoattrs": false
+						}
+					}
+				}
+			}
+		],
+		"ext": {
+			"prebid": {
+				"storedrequest": {
+					"id": "2"
+				}
+			}
+		}
+	}`,
+}
+
 type mockStoredReqFetcher struct {
 }
 
@@ -3514,3 +3706,12 @@ type hardcodedResponseIPValidator struct {
 func (v hardcodedResponseIPValidator) IsValid(net.IP, iputil.IPVersion) bool {
 	return v.response
 }
+
+type fakeUUIDGenerator struct {
+	id  string
+	err error
+}
+
+func (f fakeUUIDGenerator) Generate() (string, error) {
+	return f.id, f.err
+}
diff --git a/endpoints/openrtb2/video_auction_test.go b/endpoints/openrtb2/video_auction_test.go
index b00467d9..26d9f028 100644
--- a/endpoints/openrtb2/video_auction_test.go
+++ b/endpoints/openrtb2/video_auction_test.go
@@ -1210,6 +1210,7 @@ func mockDepsWithMetrics(t *testing.T, ex *mockExchangeVideo) (*endpointDeps, *m
 	metrics := metrics.NewMetrics(gometrics.NewRegistry(), openrtb_ext.CoreBidderNames(), config.DisabledMetrics{}, nil)
 
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		ex,
 		newParamsValidator(t),
 		&mockVideoStoredReqFetcher{},
@@ -1252,6 +1253,7 @@ func (m *mockAnalyticsModule) LogNotificationEventObject(ne *analytics.Notificat
 
 func mockDeps(t *testing.T, ex *mockExchangeVideo) *endpointDeps {
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		ex,
 		newParamsValidator(t),
 		&mockVideoStoredReqFetcher{},
@@ -1274,6 +1276,7 @@ func mockDeps(t *testing.T, ex *mockExchangeVideo) *endpointDeps {
 
 func mockDepsAppendBidderNames(t *testing.T, ex *mockExchangeAppendBidderNames) *endpointDeps {
 	deps := &endpointDeps{
+		fakeUUIDGenerator{},
 		ex,
 		newParamsValidator(t),
 		&mockVideoStoredReqFetcher{},
@@ -1296,6 +1299,7 @@ func mockDepsAppendBidderNames(t *testing.T, ex *mockExchangeAppendBidderNames)
 
 func mockDepsNoBids(t *testing.T, ex *mockExchangeVideoNoBids) *endpointDeps {
 	edep := &endpointDeps{
+		fakeUUIDGenerator{},
 		ex,
 		newParamsValidator(t),
 		&mockVideoStoredReqFetcher{},
diff --git a/endpoints/version_test.go b/endpoints/version_test.go
index 1d21a89f..ecddf532 100644
--- a/endpoints/version_test.go
+++ b/endpoints/version_test.go
@@ -11,17 +11,18 @@ import (
 func TestVersion(t *testing.T) {
 	// Setup:
 	var testCases = []struct {
-		input    string
+		version  string
+		revision string
 		expected string
 	}{
-		{"", `{"revision": "not-set"}`},
-		{"abc", `{"revision": "abc"}`},
-		{"d6cd1e2bd19e03a81132a23b2025920577f84e37", `{"revision": "d6cd1e2bd19e03a81132a23b2025920577f84e37"}`},
+		{"", "", `{"version":"not-set","revision":"not-set"}`},
+		{"abc", "def", `{"version":"abc","revision"	:"def"}`},
+		{"1.2.3", "d6cd1e2bd19e03a81132a23b2025920577f84e37", `{"version":"1.2.3","revision":"d6cd1e2bd19e03a81132a23b2025920577f84e37"}`},
 	}
 
 	for _, tc := range testCases {
 
-		handler := NewVersionEndpoint(tc.input)
+		handler := NewVersionEndpoint(tc.version, tc.revision)
 		w := httptest.NewRecorder()
 
 		// Execute:
@@ -29,7 +30,11 @@ func TestVersion(t *testing.T) {
 
 		// Verify:
 		var result, expected versionModel
-		err := json.NewDecoder(w.Body).Decode(&result)
+		responseBodyBytes, err := ioutil.ReadAll(w.Body)
+		if err != nil {
+			t.Errorf("Error reading response body bytes: %s", err)
+		}
+		err = json.Unmarshal(responseBodyBytes, &result)
 		if err != nil {
 			t.Errorf("Bad response body. Expected: %s, got an error %s", tc.expected, err)
 		}
@@ -40,7 +45,6 @@ func TestVersion(t *testing.T) {
 		}
 
 		if !reflect.DeepEqual(expected, result) {
-			responseBodyBytes, _ := ioutil.ReadAll(w.Body)
 			responseBodyString := string(responseBodyBytes)
 			t.Errorf("Bad response body. Expected: %s, got %s", tc.expected, responseBodyString)
 		}
diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go
index a31a195c..1591d353 100644
--- a/exchange/bidder_test.go
+++ b/exchange/bidder_test.go
@@ -26,6 +26,7 @@ import (
 	"github.com/prebid/prebid-server/metrics"
 	metricsConfig "github.com/prebid/prebid-server/metrics/config"
 	"github.com/prebid/prebid-server/openrtb_ext"
+	"github.com/prebid/prebid-server/version"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
 )
@@ -145,6 +146,12 @@ func TestRequestBidRemovesSensitiveHeaders(t *testing.T) {
 	server := httptest.NewServer(mockHandler(200, "getBody", "responseJson"))
 	defer server.Close()
 
+	oldVer := version.Ver
+	version.Ver = "test-version"
+	defer func() {
+		version.Ver = oldVer
+	}()
+
 	requestHeaders := http.Header{}
 	requestHeaders.Add("Content-Type", "application/json")
 	requestHeaders.Add("Authorization", "anySecret")
@@ -173,7 +180,7 @@ func TestRequestBidRemovesSensitiveHeaders(t *testing.T) {
 		{
 			Uri:            server.URL,
 			RequestBody:    "requestJson",
-			RequestHeaders: map[string][]string{"Content-Type": {"application/json"}},
+			RequestHeaders: map[string][]string{"Content-Type": {"application/json"}, "X-Prebid": {"pbs-go/test-version"}},
 			ResponseBody:   "responseJson",
 			Status:         200,
 		},
@@ -214,7 +221,7 @@ func TestSetGPCHeader(t *testing.T) {
 		{
 			Uri:            server.URL,
 			RequestBody:    "requestJson",
-			RequestHeaders: map[string][]string{"Content-Type": {"application/json"}, "Sec-Gpc": {"1"}},
+			RequestHeaders: map[string][]string{"Content-Type": {"application/json"}, "X-Prebid": {"pbs-go/unknown"}, "Sec-Gpc": {"1"}},
 			ResponseBody:   "responseJson",
 			Status:         200,
 		},
@@ -252,7 +259,7 @@ func TestSetGPCHeaderNil(t *testing.T) {
 		{
 			Uri:            server.URL,
 			RequestBody:    "requestJson",
-			RequestHeaders: map[string][]string{"Sec-Gpc": {"1"}},
+			RequestHeaders: map[string][]string{"X-Prebid": {"pbs-go/unknown"}, "Sec-Gpc": {"1"}},
 			ResponseBody:   "responseJson",
 			Status:         200,
 		},
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 706d118d..ed378e7b 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -3491,11 +3491,19 @@ func TestMakeBidExtJSON(t *testing.T) {
 
 	testCases := []aTest{
 		{
-			description:        "Valid extension, non empty extBidPrebid and valid imp ext info",
+			description:        "Valid extension, non empty extBidPrebid, valid imp ext info, meta from adapter",
 			ext:                json.RawMessage(`{"video":{"h":100}}`),
+			extBidPrebid:       openrtb_ext.ExtBidPrebid{Type: openrtb_ext.BidType("video"), Meta: &openrtb_ext.ExtBidPrebidMeta{BrandName: "foo"}},
+			impExtInfo:         map[string]ImpExtInfo{"test_imp_id": {true, []byte(`{"video":{"h":480,"mimes":["video/mp4"]}}`)}},
+			expectedBidExt:     `{"prebid":{"meta": {"brandName": "foo"}, "type":"video"},"storedrequestattributes":{"h":480,"mimes":["video/mp4"]},"video":{"h":100}}`,
+			expectedErrMessage: "",
+		},
+		{
+			description:        "Valid extension, non empty extBidPrebid, valid imp ext info, meta from response",
+			ext:                json.RawMessage(`{"video":{"h":100},"prebid":{"meta": {"brandName": "foo"}}}`),
 			extBidPrebid:       openrtb_ext.ExtBidPrebid{Type: openrtb_ext.BidType("video")},
 			impExtInfo:         map[string]ImpExtInfo{"test_imp_id": {true, []byte(`{"video":{"h":480,"mimes":["video/mp4"]}}`)}},
-			expectedBidExt:     `{"prebid":{"type":"video"},"storedrequestattributes":{"h":480,"mimes":["video/mp4"]},"video":{"h":100}}`,
+			expectedBidExt:     `{"prebid":{"meta": {"brandName": "foo"}, "type":"video"},"storedrequestattributes":{"h":480,"mimes":["video/mp4"]},"video":{"h":100}}`,
 			expectedErrMessage: "",
 		},
 		{
@@ -3554,6 +3562,54 @@ func TestMakeBidExtJSON(t *testing.T) {
 			expectedBidExt:     `{"prebid":{"type":"video"}, "storedrequestattributes":{"h":480,"mimes":["video/mp4"]}}`,
 			expectedErrMessage: "",
 		},
+		{
+			description:        "Meta - Defined By Bid - Nil Extension",
+			ext:                nil,
+			extBidPrebid:       openrtb_ext.ExtBidPrebid{Type: openrtb_ext.BidType("banner"), Meta: &openrtb_ext.ExtBidPrebidMeta{BrandName: "foo"}},
+			impExtInfo:         map[string]ImpExtInfo{},
+			expectedBidExt:     `{"prebid":{"meta":{"brandName":"foo"},"type":"banner"}}`,
+			expectedErrMessage: "",
+		},
+		{
+			description:        "Meta - Defined By Bid - Empty Extension",
+			ext:                json.RawMessage(`{}`),
+			extBidPrebid:       openrtb_ext.ExtBidPrebid{Type: openrtb_ext.BidType("banner"), Meta: &openrtb_ext.ExtBidPrebidMeta{BrandName: "foo"}},
+			impExtInfo:         nil,
+			expectedBidExt:     `{"prebid":{"meta":{"brandName":"foo"},"type":"banner"}}`,
+			expectedErrMessage: "",
+		},
+		{
+			description:        "Meta - Defined By Bid - Existing Extension Overwritten",
+			ext:                json.RawMessage(`{"prebid":{"meta":{"brandName":"notfoo", "brandId": 42}}}`),
+			extBidPrebid:       openrtb_ext.ExtBidPrebid{Type: openrtb_ext.BidType("banner"), Meta: &openrtb_ext.ExtBidPrebidMeta{BrandName: "foo"}},
+			impExtInfo:         nil,
+			expectedBidExt:     `{"prebid":{"meta":{"brandName":"foo"},"type":"banner"}}`,
+			expectedErrMessage: "",
+		},
+		{
+			description:        "Meta - Not Defined By Bid - Persists From Bid Ext",
+			ext:                json.RawMessage(`{"prebid":{"meta":{"brandName":"foo"}}}`),
+			extBidPrebid:       openrtb_ext.ExtBidPrebid{Type: openrtb_ext.BidType("banner")},
+			impExtInfo:         nil,
+			expectedBidExt:     `{"prebid":{"meta":{"brandName":"foo"},"type":"banner"}}`,
+			expectedErrMessage: "",
+		},
+		{
+			description:        "Meta - Not Defined By Bid - Persists From Bid Ext - Invalid Fields Ignored",
+			ext:                json.RawMessage(`{"prebid":{"meta":{"brandName":"foo","unknown":"value"}}}`),
+			extBidPrebid:       openrtb_ext.ExtBidPrebid{Type: openrtb_ext.BidType("banner")},
+			impExtInfo:         nil,
+			expectedBidExt:     `{"prebid":{"meta":{"brandName":"foo"},"type":"banner"}}`,
+			expectedErrMessage: "",
+		},
+		{
+			description:        "Meta - Not Defined",
+			ext:                nil,
+			extBidPrebid:       openrtb_ext.ExtBidPrebid{Type: openrtb_ext.BidType("banner")},
+			impExtInfo:         nil,
+			expectedBidExt:     `{"prebid":{"type":"banner"}}`,
+			expectedErrMessage: "",
+		},
 		//Error cases
 		{
 			description:        "Invalid extension, valid extBidPrebid and valid imp ext info",
@@ -3571,6 +3627,14 @@ func TestMakeBidExtJSON(t *testing.T) {
 			expectedBidExt:     ``,
 			expectedErrMessage: "invalid character",
 		},
+		{
+			description:        "Meta - Invalid",
+			ext:                json.RawMessage(`{"prebid":{"meta":{"brandId":"foo"}}}`), // brandId should be an int, but is a string in this test case
+			extBidPrebid:       openrtb_ext.ExtBidPrebid{Type: openrtb_ext.BidType("banner")},
+			impExtInfo:         nil,
+			expectedErrMessage: "error validaing response from server, json: cannot unmarshal string into Go struct field ExtBidPrebidMeta.prebid.meta.brandId of type int",
+		},
+		// add invalid
 	}
 
 	for _, test := range testCases {
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index 81b0b9bd..6ce4b28a 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -2228,3 +2228,117 @@ func TestRemoveUnpermissionedEidsEmptyValidations(t *testing.T) {
 		assert.Equal(t, &requestExpected, test.request, test.description+":request")
 	}
 }
+
+func TestBuildXPrebidHeader(t *testing.T) {
+	testCases := []struct {
+		description   string
+		version       string
+		requestExt    *openrtb_ext.ExtRequest
+		requestAppExt *openrtb_ext.ExtApp
+		result        string
+	}{
+		{
+			description: "No versions",
+			version:     "",
+			result:      "pbs-go/unknown",
+		},
+		{
+			description: "pbs",
+			version:     "test-version",
+			result:      "pbs-go/test-version",
+		},
+		{
+			description: "prebid.js",
+			version:     "test-version",
+			requestExt: &openrtb_ext.ExtRequest{
+				Prebid: openrtb_ext.ExtRequestPrebid{
+					Channel: &openrtb_ext.ExtRequestPrebidChannel{
+						Name:    "pbjs",
+						Version: "test-pbjs-version",
+					},
+				},
+			},
+			result: "pbs-go/test-version,pbjs/test-pbjs-version",
+		},
+		{
+			description: "unknown prebid.js",
+			version:     "test-version",
+			requestExt: &openrtb_ext.ExtRequest{
+				Prebid: openrtb_ext.ExtRequestPrebid{
+					Channel: &openrtb_ext.ExtRequestPrebidChannel{
+						Name: "pbjs",
+					},
+				},
+			},
+			result: "pbs-go/test-version,pbjs/unknown",
+		},
+		{
+			description: "channel without a name",
+			version:     "test-version",
+			requestExt: &openrtb_ext.ExtRequest{
+				Prebid: openrtb_ext.ExtRequestPrebid{
+					Channel: &openrtb_ext.ExtRequestPrebidChannel{
+						Version: "test-version",
+					},
+				},
+			},
+			result: "pbs-go/test-version",
+		},
+		{
+			description: "prebid-mobile",
+			version:     "test-version",
+			requestAppExt: &openrtb_ext.ExtApp{
+				Prebid: openrtb_ext.ExtAppPrebid{
+					Source:  "prebid-mobile",
+					Version: "test-prebid-mobile-version",
+				},
+			},
+			result: "pbs-go/test-version,prebid-mobile/test-prebid-mobile-version",
+		},
+		{
+			description: "app ext without a source",
+			version:     "test-version",
+			requestAppExt: &openrtb_ext.ExtApp{
+				Prebid: openrtb_ext.ExtAppPrebid{
+					Version: "test-version",
+				},
+			},
+			result: "pbs-go/test-version",
+		},
+		{
+			description: "Version found in both req.Ext and req.App.Ext",
+			version:     "test-version",
+			requestExt: &openrtb_ext.ExtRequest{
+				Prebid: openrtb_ext.ExtRequestPrebid{
+					Channel: &openrtb_ext.ExtRequestPrebidChannel{
+						Name:    "pbjs",
+						Version: "test-pbjs-version",
+					},
+				},
+			},
+			requestAppExt: &openrtb_ext.ExtApp{
+				Prebid: openrtb_ext.ExtAppPrebid{
+					Source:  "prebid-mobile",
+					Version: "test-prebid-mobile-version",
+				},
+			},
+			result: "pbs-go/test-version,pbjs/test-pbjs-version,prebid-mobile/test-prebid-mobile-version",
+		},
+	}
+
+	for _, test := range testCases {
+		req := &openrtb2.BidRequest{}
+		if test.requestExt != nil {
+			reqExt, err := json.Marshal(test.requestExt)
+			assert.NoError(t, err, test.description+":err marshalling reqExt")
+			req.Ext = reqExt
+		}
+		if test.requestAppExt != nil {
+			reqAppExt, err := json.Marshal(test.requestAppExt)
+			assert.NoError(t, err, test.description+":err marshalling reqAppExt")
+			req.App = &openrtb2.App{Ext: reqAppExt}
+		}
+		result := buildXPrebidHeader(req, test.version)
+		assert.Equal(t, test.result, result, test.description+":result")
+	}
+}
diff --git a/util/maputil/maputil_test.go b/util/maputil/maputil_test.go
index abce102f..114c2332 100644
--- a/util/maputil/maputil_test.go
+++ b/util/maputil/maputil_test.go
@@ -164,3 +164,84 @@ func TestReadEmbeddedString(t *testing.T) {
 		assert.Equal(t, test.expectedOK, resultOK, test.description+":ok")
 	}
 }
+
+func TestHasElement(t *testing.T) {
+	testCases := []struct {
+		description string
+		value       map[string]interface{}
+		keys        []string
+		expected    bool
+	}{
+		{
+			description: "Level 1 - Exists",
+			value:       map[string]interface{}{"foo": "exists"},
+			keys:        []string{"foo"},
+			expected:    true,
+		},
+		{
+			description: "Level 1 - Does Not Exist",
+			value:       map[string]interface{}{"foo": "exists"},
+			keys:        []string{"doesnotexist"},
+			expected:    false,
+		},
+		{
+			description: "Level 2 - Exists",
+			value:       map[string]interface{}{"foo": map[string]interface{}{"bar": "exists"}},
+			keys:        []string{"foo", "bar"},
+			expected:    true,
+		},
+		{
+			description: "Level 2 - Top Level Does Not Exist",
+			value:       map[string]interface{}{"foo": map[string]interface{}{"bar": "exists"}},
+			keys:        []string{"doesnotexist", "bar"},
+			expected:    false,
+		},
+		{
+			description: "Level 2 - Lower Level Does Not Exist",
+			value:       map[string]interface{}{"foo": map[string]interface{}{"bar": "exists"}},
+			keys:        []string{"foo", "doesnotexist"},
+			expected:    false,
+		},
+		{
+			description: "Level 2 - Does Not Exist At All",
+			value:       map[string]interface{}{"foo": map[string]interface{}{"bar": "exists"}},
+			keys:        []string{"doesnotexist", "doesnotexist"},
+			expected:    false,
+		},
+		{
+			description: "Keys Nil",
+			value:       map[string]interface{}{"foo": "exists"},
+			keys:        nil,
+			expected:    false,
+		},
+		{
+			description: "Keys Empty",
+			value:       map[string]interface{}{"foo": "exists"},
+			keys:        []string{},
+			expected:    false,
+		},
+		{
+			description: "Map Nil",
+			value:       nil,
+			keys:        []string{"foo"},
+			expected:    false,
+		},
+		{
+			description: "Map Empty",
+			value:       map[string]interface{}{},
+			keys:        []string{"foo"},
+			expected:    false,
+		},
+		{
+			description: "Nil",
+			value:       nil,
+			keys:        nil,
+			expected:    false,
+		},
+	}
+
+	for _, test := range testCases {
+		result := HasElement(test.value, test.keys...)
+		assert.Equal(t, test.expected, result, test.description)
+	}
+}