Repository: prebid/prebid-server
Pull request #1983 (2021-09-02 18:22:08)

Persist bid.ext.prebid.meta From Bidding Server Response
Implements https://github.com/prebid/prebid-server/issues/1922

Persists the `bid.ext.prebid.meta` object from the bidding server response with no changes required by the bid adapter.
- If a bid adapter explicitly specifies metadata, that takes precedence.
- If metadata from the bidding server is invalid / fails validation, PBS returns an error.
- If unknown metadata is specified from the bidding server, it is ignored.


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/aceex/aceex.go b/adapters/aceex/aceex.go
new file mode 100644
index 00000000..abf748a7
--- /dev/null
+++ b/adapters/aceex/aceex.go
@@ -0,0 +1,190 @@
+package aceex
+
+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 Aceex adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	template, 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: template,
+	}
+	return bidder, nil
+}
+
+func getHeaders(request *openrtb2.BidRequest) http.Header {
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	headers.Add("X-Openrtb-Version", "2.5")
+
+	if request.Device != nil {
+		if len(request.Device.UA) > 0 {
+			headers.Add("User-Agent", request.Device.UA)
+		}
+
+		if len(request.Device.IPv6) > 0 {
+			headers.Add("X-Forwarded-For", request.Device.IPv6)
+		}
+
+		if len(request.Device.IP) > 0 {
+			headers.Add("X-Forwarded-For", request.Device.IP)
+		}
+	}
+
+	return headers
+}
+
+func (a *adapter) MakeRequests(
+	openRTBRequest *openrtb2.BidRequest,
+	reqInfo *adapters.ExtraRequestInfo,
+) (
+	requestsToBidder []*adapters.RequestData,
+	errs []error,
+) {
+
+	var errors []error
+
+	aceexExt, err := a.getImpressionExt(&openRTBRequest.Imp[0])
+	if err != nil {
+		return nil, append(errors, err)
+	}
+
+	url, err := a.buildEndpointURL(aceexExt)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	reqJSON, err := json.Marshal(openRTBRequest)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	return []*adapters.RequestData{{
+		Method:  http.MethodPost,
+		Body:    reqJSON,
+		Uri:     url,
+		Headers: getHeaders(openRTBRequest),
+	}}, nil
+}
+
+func (a *adapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtAceex, error) {
+	var bidderExt adapters.ExtImpBidder
+	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
+		return nil, &errortypes.BadInput{
+			Message: "ext.bidder not provided",
+		}
+	}
+	var aceexExt openrtb_ext.ExtAceex
+	if err := json.Unmarshal(bidderExt.Bidder, &aceexExt); err != nil {
+		return nil, &errortypes.BadInput{
+			Message: "ext.bidder not provided",
+		}
+	}
+	imp.Ext = nil
+	return &aceexExt, nil
+}
+
+func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtAceex) (string, error) {
+	endpointParams := macros.EndpointTemplateParams{AccountID: params.AccountID}
+	return macros.ResolveMacros(a.endpoint, endpointParams)
+}
+
+func (a *adapter) checkResponseStatusCodes(response *adapters.ResponseData) error {
+	if response.StatusCode == http.StatusBadRequest {
+		return &errortypes.BadInput{
+			Message: fmt.Sprintf("Unexpected status code: [ %d ]", response.StatusCode),
+		}
+	}
+
+	if response.StatusCode == http.StatusServiceUnavailable {
+		return &errortypes.BadInput{
+			Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode),
+		}
+	}
+
+	if response.StatusCode != http.StatusOK {
+		return &errortypes.BadInput{
+			Message: fmt.Sprintf("Unexpected status code: [ %d ]. Run with request.debug = 1 for more info", response.StatusCode),
+		}
+	}
+
+	return nil
+}
+
+func (a *adapter) MakeBids(
+	openRTBRequest *openrtb2.BidRequest,
+	requestToBidder *adapters.RequestData,
+	bidderRawResponse *adapters.ResponseData,
+) (
+	bidderResponse *adapters.BidderResponse,
+	errs []error,
+) {
+	if bidderRawResponse.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	httpStatusError := a.checkResponseStatusCodes(bidderRawResponse)
+	if httpStatusError != nil {
+		return nil, []error{httpStatusError}
+	}
+
+	responseBody := bidderRawResponse.Body
+	var bidResp openrtb2.BidResponse
+	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Bad Server Response",
+		}}
+	}
+
+	if len(bidResp.SeatBid) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid array",
+		}}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))
+	sb := bidResp.SeatBid[0]
+
+	for _, bid := range sb.Bid {
+		bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+			Bid:     &bid,
+			BidType: getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp),
+		})
+	}
+	return bidResponse, nil
+}
+
+func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType {
+	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
+		}
+	}
+	return mediaType
+}
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/openweb/openweb.go b/adapters/openweb/openweb.go
new file mode 100644
index 00000000..9c6c48c5
--- /dev/null
+++ b/adapters/openweb/openweb.go
@@ -0,0 +1,191 @@
+package openweb
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+
+	"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/openrtb_ext"
+)
+
+type adapter struct {
+	endpoint string
+}
+
+type openwebImpExt struct {
+	OpenWeb openrtb_ext.ExtImpOpenWeb `json:"openweb"`
+}
+
+func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	totalImps := len(request.Imp)
+	errors := make([]error, 0, totalImps)
+	sourceIdToImpIds := make(map[int][]int)
+	var sourceIds []int
+
+	for i := 0; i < totalImps; i++ {
+
+		sourceId, err := validateImpression(&request.Imp[i])
+
+		if err != nil {
+			errors = append(errors, err)
+			continue
+		}
+
+		if _, ok := sourceIdToImpIds[sourceId]; !ok {
+			sourceIdToImpIds[sourceId] = make([]int, 0, totalImps-i)
+			sourceIds = append(sourceIds, sourceId)
+		}
+
+		sourceIdToImpIds[sourceId] = append(sourceIdToImpIds[sourceId], i)
+
+	}
+
+	totalReqs := len(sourceIdToImpIds)
+	if totalReqs == 0 {
+		return nil, errors
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+
+	reqs := make([]*adapters.RequestData, 0, totalReqs)
+
+	imps := request.Imp
+	reqCopy := *request
+	reqCopy.Imp = make([]openrtb2.Imp, totalImps)
+	for _, sourceId := range sourceIds {
+		impIds := sourceIdToImpIds[sourceId]
+		reqCopy.Imp = reqCopy.Imp[:0]
+
+		for i := 0; i < len(impIds); i++ {
+			reqCopy.Imp = append(reqCopy.Imp, imps[impIds[i]])
+		}
+
+		body, err := json.Marshal(reqCopy)
+		if err != nil {
+			errors = append(errors, fmt.Errorf("error while encoding bidRequest, err: %s", err))
+			return nil, errors
+		}
+
+		reqs = append(reqs, &adapters.RequestData{
+			Method:  "POST",
+			Uri:     a.endpoint + fmt.Sprintf("?aid=%d", sourceId),
+			Body:    body,
+			Headers: headers,
+		})
+	}
+
+	return reqs, errors
+
+}
+
+func (a *adapter) MakeBids(bidReq *openrtb2.BidRequest, unused *adapters.RequestData, httpRes *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+
+	if httpRes.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if httpRes.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Remote server error: %s", httpRes.Body),
+		}}
+	}
+	var bidResp openrtb2.BidResponse
+	if err := json.Unmarshal(httpRes.Body, &bidResp); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("error while decoding response, err: %s", err),
+		}}
+	}
+
+	bidResponse := adapters.NewBidderResponse()
+	var errors []error
+
+	for _, sb := range bidResp.SeatBid {
+		for i := 0; i < len(sb.Bid); i++ {
+
+			bid := sb.Bid[i]
+
+			mediaType, impOK := getBidType(bidReq.Imp, bid.ImpID)
+			if !impOK {
+				errors = append(errors, &errortypes.BadServerResponse{
+					Message: fmt.Sprintf("ignoring bid id=%s, request doesn't contain any impression with id=%s", bid.ID, bid.ImpID),
+				})
+				continue
+			}
+
+			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+				Bid:     &bid,
+				BidType: mediaType,
+			})
+		}
+	}
+
+	return bidResponse, errors
+}
+
+func getBidType(imps []openrtb2.Imp, impId string) (mediaType openrtb_ext.BidType, ok bool) {
+	mediaType = openrtb_ext.BidTypeBanner
+	for _, imp := range imps {
+		if imp.ID == impId {
+			ok = true
+
+			if imp.Video != nil {
+				mediaType = openrtb_ext.BidTypeVideo
+			}
+
+			break
+		}
+	}
+
+	return
+}
+
+func validateImpression(imp *openrtb2.Imp) (int, error) {
+	var bidderExt adapters.ExtImpBidder
+
+	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
+		return 0, &errortypes.BadInput{
+			Message: fmt.Sprintf("ignoring imp id=%s, error while decoding extImpBidder, err: %s", imp.ID, err),
+		}
+	}
+
+	impExt := openrtb_ext.ExtImpOpenWeb{}
+	err := json.Unmarshal(bidderExt.Bidder, &impExt)
+	if err != nil {
+		return 0, &errortypes.BadInput{
+			Message: fmt.Sprintf("ignoring imp id=%s, error while decoding impExt, err: %s", imp.ID, err),
+		}
+	}
+
+	var impExtBuffer []byte
+
+	impExtBuffer, err = json.Marshal(&openwebImpExt{
+		OpenWeb: impExt,
+	})
+	if err != nil {
+		return 0, &errortypes.BadInput{
+			Message: fmt.Sprintf("ignoring imp id=%s, error while encoding impExt, err: %s", imp.ID, err),
+		}
+	}
+
+	if impExt.BidFloor > 0 {
+		imp.BidFloor = impExt.BidFloor
+	}
+
+	imp.Ext = impExtBuffer
+
+	return impExt.SourceID, nil
+}
+
+// Builder builds a new instance of the OpenWeb adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &adapter{
+		endpoint: config.Endpoint,
+	}
+	return bidder, nil
+}
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 7e902df2..0286744d 100644
--- a/config/config.go
+++ b/config/config.go
@@ -148,7 +148,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, "/") {
@@ -738,6 +738,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	// for them and specify all the parameters they need for them to work correctly.
 	v.SetDefault("adapters.33across.endpoint", "https://ssc.33across.com/api/v1/s2s")
 	v.SetDefault("adapters.33across.partner_id", "")
+	v.SetDefault("adapters.aceex.endpoint", "http://bl-us.aceex.io/?uqhash={{.AccountID}}")
 	v.SetDefault("adapters.acuityads.endpoint", "http://{{.Host}}.admanmedia.com/bid?token={{.AccountID}}")
 	v.SetDefault("adapters.adagio.endpoint", "https://mp.4dex.io/ortb2")
 	v.SetDefault("adapters.adf.endpoint", "https://adx.adform.net/adx/openrtb")
@@ -752,10 +753,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")
@@ -824,6 +826,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.ninthdecimal.endpoint", "http://rtb.ninthdecimal.com/xp/get?pubid={{.PublisherID}}")
 	v.SetDefault("adapters.nobid.endpoint", "https://ads.servenobid.com/ortb_adreq?tek=pbs&ver=1")
 	v.SetDefault("adapters.onetag.endpoint", "https://prebid-server.onetag-sys.com/prebid-server/{{.PublisherID}}")
+	v.SetDefault("adapters.openweb.endpoint", "http://ghb.spotim.market/pbs/ortb")
 	v.SetDefault("adapters.openx.endpoint", "http://rtb.openx.net/prebid")
 	v.SetDefault("adapters.operaads.endpoint", "https://s.adx.opera.com/ortb/v2/{{.PublisherID}}?ep={{.AccountID}}")
 	v.SetDefault("adapters.orbidder.endpoint", "https://orbidder.otto.de/openrtb2")
@@ -862,7 +865,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/")
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index fea39191..1d879443 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -14,7 +14,7 @@ import (
 	"time"
 
 	"github.com/buger/jsonparser"
-	jsonpatch "github.com/evanphx/json-patch"
+	"github.com/evanphx/json-patch"
 	"github.com/gofrs/uuid"
 	"github.com/golang/glog"
 	"github.com/julienschmidt/httprouter"
@@ -262,8 +262,13 @@ func (deps *endpointDeps) parseRequest(httpRequest *http.Request) (req *openrtb_
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
+	impInfo, errs := parseImpInfo(requestJson)
+	if len(errs) > 0 {
+		return nil, nil, errs
+	}
+
 	// Fetch the Stored Request data and merge it into the HTTP request.
-	if requestJson, impExtInfoMap, errs = deps.processStoredRequests(ctx, requestJson); len(errs) > 0 {
+	if requestJson, impExtInfoMap, errs = deps.processStoredRequests(ctx, requestJson, impInfo); len(errs) > 0 {
 		return
 	}
 
@@ -1317,23 +1322,32 @@ func getJsonSyntaxError(testJSON []byte) (bool, string) {
 	return false, ""
 }
 
-func (deps *endpointDeps) processStoredRequests(ctx context.Context, requestJson []byte) ([]byte, map[string]exchange.ImpExtInfo, []error) {
+func (deps *endpointDeps) processStoredRequests(ctx context.Context, requestJson []byte, impInfo []ImpExtPrebidData) ([]byte, map[string]exchange.ImpExtInfo, []error) {
 	// Parse the Stored Request IDs from the BidRequest and Imps.
 	storedBidRequestId, hasStoredBidRequest, err := getStoredRequestId(requestJson)
 	if err != nil {
 		return nil, nil, []error{err}
 	}
-	imps, impIds, idIndices, errs := parseImpInfo(requestJson)
-	if len(errs) > 0 {
-		return nil, nil, errs
-	}
 
 	// Fetch the Stored Request data
 	var storedReqIds []string
 	if hasStoredBidRequest {
 		storedReqIds = []string{storedBidRequestId}
 	}
-	storedRequests, storedImps, errs := deps.storedReqFetcher.FetchRequests(ctx, storedReqIds, impIds)
+
+	impStoredReqIds := make([]string, 0, len(impInfo))
+	impStoredReqIdsUniqueTracker := make(map[string]struct{}, len(impInfo))
+	for _, impData := range impInfo {
+		if impData.ImpExtPrebid.StoredRequest != nil && len(impData.ImpExtPrebid.StoredRequest.ID) > 0 {
+			storedImpId := impData.ImpExtPrebid.StoredRequest.ID
+			if _, present := impStoredReqIdsUniqueTracker[storedImpId]; !present {
+				impStoredReqIds = append(impStoredReqIds, storedImpId)
+				impStoredReqIdsUniqueTracker[storedImpId] = struct{}{}
+			}
+		}
+	}
+
+	storedRequests, storedImps, errs := deps.storedReqFetcher.FetchRequests(ctx, storedReqIds, impStoredReqIds)
 	if len(errs) != 0 {
 		return nil, nil, errs
 	}
@@ -1378,42 +1392,44 @@ func (deps *endpointDeps) processStoredRequests(ctx context.Context, requestJson
 	// Apply any Stored Imps, if they exist. Since the JSON Merge Patch overrides arrays,
 	// and Prebid Server defers to the HTTP Request to resolve conflicts, it's safe to
 	// assume that the request.imp data did not change when applying the Stored BidRequest.
-	impExtInfoMap := make(map[string]exchange.ImpExtInfo, len(impIds))
-	for i := 0; i < len(impIds); i++ {
-		resolvedImp, err := jsonpatch.MergePatch(storedImps[impIds[i]], imps[idIndices[i]])
+	impExtInfoMap := make(map[string]exchange.ImpExtInfo, len(impInfo))
+	resolvedImps := make([]json.RawMessage, 0, len(impInfo))
+	for i, impData := range impInfo {
+		if impData.ImpExtPrebid.StoredRequest != nil && len(impData.ImpExtPrebid.StoredRequest.ID) > 0 {
+			resolvedImp, err := jsonpatch.MergePatch(storedImps[impData.ImpExtPrebid.StoredRequest.ID], impData.Imp)
 
-		if err != nil {
-			hasErr, Err := getJsonSyntaxError(imps[idIndices[i]])
-			if hasErr {
-				err = fmt.Errorf("Invalid JSON in Imp[%d] of Incoming Request: %s", i, Err)
-			} else {
-				hasErr, Err = getJsonSyntaxError(storedImps[impIds[i]])
+			if err != nil {
+				hasErr, errMessage := getJsonSyntaxError(impData.Imp)
 				if hasErr {
-					err = fmt.Errorf("imp.ext.prebid.storedrequest.id %s: Stored Imp has Invalid JSON: %s", impIds[i], Err)
+					err = fmt.Errorf("Invalid JSON in Imp[%d] of Incoming Request: %s", i, errMessage)
+				} else {
+					hasErr, errMessage = getJsonSyntaxError(storedImps[impData.ImpExtPrebid.StoredRequest.ID])
+					if hasErr {
+						err = fmt.Errorf("imp.ext.prebid.storedrequest.id %s: Stored Imp has Invalid JSON: %s", impData.ImpExtPrebid.StoredRequest.ID, errMessage)
+					}
 				}
+				return nil, nil, []error{err}
 			}
-			return nil, nil, []error{err}
-		}
-		imps[idIndices[i]] = resolvedImp
+			resolvedImps = append(resolvedImps, resolvedImp)
 
-		impId, err := jsonparser.GetString(resolvedImp, "id")
-		if err != nil {
-			return nil, nil, []error{err}
-		}
-		// This is substantially faster for reading values from a json blob than the Go json package,
-		// but keep in mind that each jsonparser.GetXXX call re-parses the entire json.
-		// Based on performance measurements, the tipping point of efficiency is around 4 calls.
-		// At that point, please consider switching to EachKey to use a single pass.
-		includeVideoAttributes, err := jsonparser.GetBoolean(resolvedImp, "ext", "prebid", "options", "echovideoattrs")
-		if err != nil && err != jsonparser.KeyPathNotFoundError {
-			return nil, nil, []error{err}
-		}
-		if storedImps[impIds[i]] != nil {
-			impExtInfoMap[impId] = exchange.ImpExtInfo{EchoVideoAttrs: includeVideoAttributes, StoredImp: storedImps[impIds[i]]}
+			impId, err := jsonparser.GetString(resolvedImp, "id")
+			if err != nil {
+				return nil, nil, []error{err}
+			}
+
+			echoVideoAttributes := false
+			if impData.ImpExtPrebid.Options != nil {
+				echoVideoAttributes = impData.ImpExtPrebid.Options.EchoVideoAttrs
+			}
+			impExtInfoMap[impId] = exchange.ImpExtInfo{EchoVideoAttrs: echoVideoAttributes, StoredImp: storedImps[impData.ImpExtPrebid.StoredRequest.ID]}
+
+		} else {
+			resolvedImps = append(resolvedImps, impData.Imp)
 		}
+
 	}
-	if len(impIds) > 0 {
-		newImpJson, err := json.Marshal(imps)
+	if len(resolvedImps) > 0 {
+		newImpJson, err := json.Marshal(resolvedImps)
 		if err != nil {
 			return nil, nil, []error{err}
 		}
@@ -1426,29 +1442,30 @@ func (deps *endpointDeps) processStoredRequests(ctx context.Context, requestJson
 	return resolvedRequest, impExtInfoMap, nil
 }
 
-// parseImpInfo parses the request JSON and returns several things about the Imps
-//
-// 1. A list of the JSON for every Imp.
-// 2. A list of all IDs which appear at `imp[i].ext.prebid.storedrequest.id`.
-// 3. A list intended to parallel "ids". Each element tells which index of "imp[index]" the corresponding element of "ids" should modify.
-// 4. Any errors which occur due to bad requests. These should warrant an HTTP 4xx response.
-func parseImpInfo(requestJson []byte) (imps []json.RawMessage, ids []string, impIdIndices []int, errs []error) {
+// parseImpInfo parses the request JSON and returns impression and unmarshalled imp.ext.prebid
+func parseImpInfo(requestJson []byte) (impData []ImpExtPrebidData, errs []error) {
+
 	if impArray, dataType, _, err := jsonparser.Get(requestJson, "imp"); err == nil && dataType == jsonparser.Array {
-		i := 0
-		jsonparser.ArrayEach(impArray, func(imp []byte, _ jsonparser.ValueType, _ int, err error) {
-			if storedImpId, hasStoredImp, err := getStoredRequestId(imp); err != nil {
-				errs = append(errs, err)
-			} else if hasStoredImp {
-				ids = append(ids, storedImpId)
-				impIdIndices = append(impIdIndices, i)
+		_, err = jsonparser.ArrayEach(impArray, func(imp []byte, _ jsonparser.ValueType, _ int, err error) {
+			impExtData, _, _, err := jsonparser.Get(imp, "ext", "prebid")
+			var impExtPrebid openrtb_ext.ExtImpPrebid
+			if impExtData != nil {
+				if err := json.Unmarshal(impExtData, &impExtPrebid); err != nil {
+					errs = append(errs, err)
+				}
 			}
-			imps = append(imps, imp)
-			i++
+			newImpData := ImpExtPrebidData{imp, impExtPrebid}
+			impData = append(impData, newImpData)
 		})
 	}
 	return
 }
 
+type ImpExtPrebidData struct {
+	Imp          json.RawMessage
+	ImpExtPrebid openrtb_ext.ExtImpPrebid
+}
+
 // getStoredRequestId parses a Stored Request ID from some json, without doing a full (slow) unmarshal.
 // It returns the ID, true/false whether a stored request key existed, and an error if anything went wrong
 // (e.g. malformed json, id not a string, etc).
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/supplementary/imp-info-invalid.json b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/imp-info-invalid.json
new file mode 100644
index 00000000..190a7ad0
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/imp-info-invalid.json
@@ -0,0 +1,23 @@
+{
+  "description": "Impression with  stored request has invalid data",
+  "mockBidRequest": {
+    "id": "ThisID",
+    "imp": [
+      {
+        "id": "imp1",
+        "ext": {
+          "prebid": {
+            "storedrequest": {
+              "id": "1"
+            },
+            "options": {
+              "echovideoattrs": "true"
+            }
+          }
+        }
+      }
+    ]
+  },
+  "expectedBidResponse": {},
+  "expectedReturnCode": 200
+}
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 74a1d257..630f18b6 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -3,6 +3,7 @@ package exchange
 import (
 	"github.com/prebid/prebid-server/adapters"
 	ttx "github.com/prebid/prebid-server/adapters/33across"
+	"github.com/prebid/prebid-server/adapters/aceex"
 	"github.com/prebid/prebid-server/adapters/acuityads"
 	"github.com/prebid/prebid-server/adapters/adagio"
 	"github.com/prebid/prebid-server/adapters/adf"
@@ -21,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"
@@ -82,6 +84,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/ninthdecimal"
 	"github.com/prebid/prebid-server/adapters/nobid"
 	"github.com/prebid/prebid-server/adapters/onetag"
+	"github.com/prebid/prebid-server/adapters/openweb"
 	"github.com/prebid/prebid-server/adapters/openx"
 	"github.com/prebid/prebid-server/adapters/operaads"
 	"github.com/prebid/prebid-server/adapters/orbidder"
@@ -132,6 +135,7 @@ import (
 func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 	return map[openrtb_ext.BidderName]adapters.Builder{
 		openrtb_ext.Bidder33Across:          ttx.Builder,
+		openrtb_ext.BidderAceex:             aceex.Builder,
 		openrtb_ext.BidderAcuityAds:         acuityads.Builder,
 		openrtb_ext.BidderAdagio:            adagio.Builder,
 		openrtb_ext.BidderAdf:               adf.Builder,
@@ -150,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,
@@ -213,6 +218,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderNinthDecimal:      ninthdecimal.Builder,
 		openrtb_ext.BidderNoBid:             nobid.Builder,
 		openrtb_ext.BidderOneTag:            onetag.Builder,
+		openrtb_ext.BidderOpenWeb:           openweb.Builder,
 		openrtb_ext.BidderOpenx:             openx.Builder,
 		openrtb_ext.BidderOperaads:          operaads.Builder,
 		openrtb_ext.BidderOrbidder:          orbidder.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/go.mod b/go.mod
index 6c6f3209..347f36bc 100644
--- a/go.mod
+++ b/go.mod
@@ -20,14 +20,13 @@ require (
 	github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
 	github.com/influxdata/influxdb v1.6.1
 	github.com/julienschmidt/httprouter v1.1.0
-	github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
 	github.com/lib/pq v1.0.0
 	github.com/magiconair/properties v1.8.5
 	github.com/mattn/go-colorable v0.1.2 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
 	github.com/mitchellh/copystructure v1.1.2
 	github.com/mxmCherry/openrtb/v15 v15.0.0
-	github.com/prebid/go-gdpr v0.9.0
+	github.com/prebid/go-gdpr v1.10.0
 	github.com/prometheus/client_golang v0.0.0-20180623155954-77e8f2ddcfed
 	github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4
 	github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e // indirect
diff --git a/go.sum b/go.sum
index 6db57ada..31e6b8fc 100644
--- a/go.sum
+++ b/go.sum
@@ -57,7 +57,6 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
 github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
 github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
 github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
-github.com/buger/jsonparser v0.0.0-20180318095312-2cac668e8456/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
 github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
 github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -205,8 +204,6 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.1.0 h1:7wLdtIiIpzOkC9u6sXOozpBauPdskj3ru4EI5MABq68=
 github.com/julienschmidt/httprouter v1.1.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=
-github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
@@ -265,8 +262,8 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/prebid/go-gdpr v0.9.0 h1:FL1ZXuccMYOPIt69mIHF2AyRhv8ezvtjnUoAE3Ph8O0=
-github.com/prebid/go-gdpr v0.9.0/go.mod h1:OfBxLfd+JfP3OAJ1MhI4JYAV3dSMQYT1QAb80DHpZFo=
+github.com/prebid/go-gdpr v1.10.0 h1:f9Ua+PAIK97j82QkJtIsohlbyU8961mFphw23hTsoMo=
+github.com/prebid/go-gdpr v1.10.0/go.mod h1:mPZAdkRxn+iuSjaUuJAi9+0SppBOdM1PCzv/55UH3pY=
 github.com/prometheus/client_golang v0.0.0-20180623155954-77e8f2ddcfed h1:0dloFFFNNDG7c+8qtkYw2FdADrWy9s5cI8wHp6tK3Mg=
 github.com/prometheus/client_golang v0.0.0-20180623155954-77e8f2ddcfed/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
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 dd4c1c86..88f816c2 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -74,6 +74,7 @@ func IsBidderNameReserved(name string) bool {
 // Please keep this list alphabetized to minimize merge conflicts.
 const (
 	Bidder33Across          BidderName = "33across"
+	BidderAceex             BidderName = "aceex"
 	BidderAcuityAds         BidderName = "acuityads"
 	BidderAdagio            BidderName = "adagio"
 	BidderAdf               BidderName = "adf"
@@ -92,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"
@@ -155,6 +157,7 @@ const (
 	BidderNinthDecimal      BidderName = "ninthdecimal"
 	BidderNoBid             BidderName = "nobid"
 	BidderOneTag            BidderName = "onetag"
+	BidderOpenWeb           BidderName = "openweb"
 	BidderOpenx             BidderName = "openx"
 	BidderOperaads          BidderName = "operaads"
 	BidderOrbidder          BidderName = "orbidder"
@@ -204,6 +207,7 @@ const (
 func CoreBidderNames() []BidderName {
 	return []BidderName{
 		Bidder33Across,
+		BidderAceex,
 		BidderAcuityAds,
 		BidderAdagio,
 		BidderAdf,
@@ -222,6 +226,7 @@ func CoreBidderNames() []BidderName {
 		BidderAdtarget,
 		BidderAdtelligent,
 		BidderAdvangelists,
+		BidderAdView,
 		BidderAdxcg,
 		BidderAdyoulike,
 		BidderAJA,
@@ -285,6 +290,7 @@ func CoreBidderNames() []BidderName {
 		BidderNinthDecimal,
 		BidderNoBid,
 		BidderOneTag,
+		BidderOpenWeb,
 		BidderOpenx,
 		BidderOperaads,
 		BidderOrbidder,
diff --git a/openrtb_ext/imp.go b/openrtb_ext/imp.go
index 670087ad..b51f2cde 100644
--- a/openrtb_ext/imp.go
+++ b/openrtb_ext/imp.go
@@ -14,9 +14,15 @@ type ExtImpPrebid struct {
 
 	// Bidder is the preferred approach for providing paramters to be interepreted by the bidder's adapter.
 	Bidder map[string]json.RawMessage `json:"bidder"`
+
+	Options *Options `json:"options,omitempty"`
 }
 
 // ExtStoredRequest defines the contract for bidrequest.imp[i].ext.prebid.storedrequest
 type ExtStoredRequest struct {
 	ID string `json:"id"`
 }
+
+type Options struct {
+	EchoVideoAttrs bool `json:"echovideoattrs"`
+}
diff --git a/openrtb_ext/imp_aceex.go b/openrtb_ext/imp_aceex.go
new file mode 100644
index 00000000..62500852
--- /dev/null
+++ b/openrtb_ext/imp_aceex.go
@@ -0,0 +1,5 @@
+package openrtb_ext
+
+type ExtAceex struct {
+	AccountID string `json:"accountid"`
+}
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/imp_openweb.go b/openrtb_ext/imp_openweb.go
new file mode 100644
index 00000000..3d28265e
--- /dev/null
+++ b/openrtb_ext/imp_openweb.go
@@ -0,0 +1,9 @@
+package openrtb_ext
+
+// ExtImpOpenWeb defines the contract for bidrequest.imp[i].ext.openweb
+type ExtImpOpenWeb struct {
+	SourceID    int     `json:"aid"`
+	PlacementID int     `json:"placementId,omitempty"`
+	SiteID      int     `json:"siteId,omitempty"`
+	BidFloor    float64 `json:"bidFloor,omitempty"`
+}
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/static/bidder-info/aceex.yaml b/static/bidder-info/aceex.yaml
new file mode 100644
index 00000000..a94d3752
--- /dev/null
+++ b/static/bidder-info/aceex.yaml
@@ -0,0 +1,13 @@
+maintainer:
+  email: "tech@aceex.io"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - native
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/openweb.yaml b/static/bidder-info/openweb.yaml
new file mode 100644
index 00000000..5886c4a7
--- /dev/null
+++ b/static/bidder-info/openweb.yaml
@@ -0,0 +1,17 @@
+maintainer:
+  email: "monetization@openweb.com"
+gvlVendorID: 280
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+  site:
+    mediaTypes:
+      - banner
+      - video
+userSync:
+  # openweb supports user syncing, but requires configuration by the host. contact this
+  # bidder directly at the email address in this file to ask about enabling user sync.
+  supports:
+    - redirect
\ No newline at end of file
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/aceex.json b/static/bidder-params/aceex.json
new file mode 100644
index 00000000..1539af91
--- /dev/null
+++ b/static/bidder-params/aceex.json
@@ -0,0 +1,14 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Aceex Adapter Params",
+  "description": "A schema which validates params accepted by the Aceex adapter",
+  "type": "object",
+  "properties": {
+    "accountid": {
+      "type": "string",
+      "description": "Account id",
+      "minLength": 1
+    }
+  },
+  "required": ["accountid"]
+}
\ No newline at end of file
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/static/bidder-params/openweb.json b/static/bidder-params/openweb.json
new file mode 100644
index 00000000..ec5766ad
--- /dev/null
+++ b/static/bidder-params/openweb.json
@@ -0,0 +1,26 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "OpenWeb Adapter Params",
+  "description": "A schema which validates params accepted by the OpenWeb adapter",
+
+  "type": "object",
+  "properties": {
+    "placementId": {
+      "type": "integer",
+      "description": "An ID which identifies this placement of the impression"
+    },
+    "siteId": {
+      "type": "integer",
+      "description": "An ID which identifies the site selling the impression"
+    },
+    "aid": {
+      "type": "integer",
+      "description": "An ID which identifies the channel"
+    },
+    "bidFloor": {
+      "type": "number",
+      "description": "BidFloor, US Dollars"
+    }
+  },
+  "required": ["aid"]
+}
diff --git a/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/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/aceex/aceex_test.go b/adapters/aceex/aceex_test.go
new file mode 100644
index 00000000..4970f652
--- /dev/null
+++ b/adapters/aceex/aceex_test.go
@@ -0,0 +1,28 @@
+package aceex
+
+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.BidderAceex, config.Adapter{
+		Endpoint: "http://us.example.com/bid?uqhash={{.AccountID}}"})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "aceextest", bidder)
+}
+
+func TestEndpointTemplateMalformed(t *testing.T) {
+	_, buildErr := Builder(openrtb_ext.BidderAceex, config.Adapter{
+		Endpoint: "{{Malformed}}"})
+
+	assert.Error(t, buildErr)
+}
diff --git a/adapters/aceex/aceextest/exemplary/banner-app.json b/adapters/aceex/aceextest/exemplary/banner-app.json
new file mode 100644
index 00000000..f6509699
--- /dev/null
+++ b/adapters/aceex/aceextest/exemplary/banner-app.json
@@ -0,0 +1,155 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "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",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w": 320,
+          "h": 50
+        },
+        "ext": {
+          "bidder": {
+            "accountid": "hash"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://us.example.com/bid?uqhash=hash",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "banner": {
+                "w": 320,
+                "h": 50
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "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": "1",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50
+                }
+              ],
+              "type": "banner",
+              "seat": "aceex"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "aceex": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "1",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 320,
+            "h": 50
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/aceex/aceextest/exemplary/banner-web.json b/adapters/aceex/aceextest/exemplary/banner-web.json
new file mode 100644
index 00000000..cf0d69be
--- /dev/null
+++ b/adapters/aceex/aceextest/exemplary/banner-web.json
@@ -0,0 +1,143 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w":320,
+          "h":50
+        },
+        "ext": {
+          "bidder": {
+            "accountid": "hash"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://us.example.com/bid?uqhash=hash",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "banner": {
+                "w":320,
+                "h":50
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "publisher": {
+              "id": "123456789"
+            }
+          },
+          "user": {
+            "buyeruid": "awesome-user"
+          },
+          "tmax": 1000
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "awesome-resp-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+                  "impid": "1",
+                  "price": 3.5,
+                  "adm": "awesome-markup",
+                  "adomain": [
+                    "awesome.com"
+                  ],
+                  "crid": "20",
+                  "w": 320,
+                  "h": 50
+                }
+              ],
+              "type": "banner",
+              "seat": "aceex"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "aceex": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids":[
+        {
+          "bid":  {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "1",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "crid": "20",
+            "adomain": [
+              "awesome.com"
+            ],
+            "w": 320,
+            "h": 50
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/aceex/aceextest/exemplary/native-app.json b/adapters/aceex/aceextest/exemplary/native-app.json
new file mode 100644
index 00000000..3e8d0fe2
--- /dev/null
+++ b/adapters/aceex/aceextest/exemplary/native-app.json
@@ -0,0 +1,152 @@
+{
+    "mockBidRequest": {
+      "id": "some-request-id",
+      "device": {
+        "ua": "test-user-agent",
+        "ip": "123.123.123.123",
+        "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",
+          "tagid": "ogTAGID",
+          "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": {
+              "accountid": "hash"
+            }
+          }
+        }
+      ]
+    },
+    "httpCalls": [
+      {
+        "expectedRequest": {
+          "headers": {
+            "Content-Type": [
+              "application/json;charset=utf-8"
+            ],
+            "Accept": [
+              "application/json"
+            ],
+            "X-Openrtb-Version": [
+              "2.5"
+            ],
+            "User-Agent": [
+              "test-user-agent"
+            ],
+            "X-Forwarded-For": [
+              "123.123.123.123"
+            ]
+          },
+          "uri": "http://us.example.com/bid?uqhash=hash",
+          "body": {
+            "id": "some-request-id",
+            "device": {
+              "ua": "test-user-agent",
+              "ip": "123.123.123.123",
+              "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}}}"
+                },
+                "tagid": "ogTAGID"
+              }
+            ],
+            "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": "aceex"
+              }
+            ],
+            "cur": "USD",
+            "ext": {
+              "responsetimemillis": {
+                "aceex": 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"
+          }
+        ]
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/adapters/aceex/aceextest/exemplary/native-web.json b/adapters/aceex/aceextest/exemplary/native-web.json
new file mode 100644
index 00000000..a0c220ef
--- /dev/null
+++ b/adapters/aceex/aceextest/exemplary/native-web.json
@@ -0,0 +1,139 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "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": {
+            "host": "ep1",
+            "accountid": "hash"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "2607:fb90:f27:4512:d800:cb23:a603:e245"
+          ]
+        },
+        "uri": "http://us.example.com/bid?uqhash=hash",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "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}}}"
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "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"
+                }
+              ],
+              "seat": "acuityads"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "acuityads": 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/aceex/aceextest/exemplary/video-app.json b/adapters/aceex/aceextest/exemplary/video-app.json
new file mode 100644
index 00000000..cc27ad60
--- /dev/null
+++ b/adapters/aceex/aceextest/exemplary/video-app.json
@@ -0,0 +1,164 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "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",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountid": "hash"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://us.example.com/bid?uqhash=hash",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "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": "aceex"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "aceex": 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/aceex/aceextest/exemplary/video-web.json b/adapters/aceex/aceextest/exemplary/video-web.json
new file mode 100644
index 00000000..a1559086
--- /dev/null
+++ b/adapters/aceex/aceextest/exemplary/video-web.json
@@ -0,0 +1,162 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "language": "en",
+      "dnt": 0
+    },
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountid": "hash"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://us.example.com/bid?uqhash=hash",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "tagid": "ogTAGID",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              }
+            }
+          ],
+          "site": {
+            "page": "test.com",
+            "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,
+                  "ext": {
+                    "prebid": {
+                      "type": "video"
+                    }
+                  }
+                }
+              ],
+              "seat": "aceex"
+            }
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "aceex": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
+            "impid": "some-impression-id",
+            "price": 3.5,
+            "adm": "awesome-markup",
+            "adomain": [
+              "awesome.com"
+            ],
+            "crid": "20",
+            "w": 1280,
+            "h": 720,
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          },
+          "type":"video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/aceex/aceextest/supplemental/empty-seatbid-array.json b/adapters/aceex/aceextest/supplemental/empty-seatbid-array.json
new file mode 100644
index 00000000..e53e6252
--- /dev/null
+++ b/adapters/aceex/aceextest/supplemental/empty-seatbid-array.json
@@ -0,0 +1,136 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "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",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountid": "hash"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "Accept": [
+            "application/json"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "User-Agent": [
+            "test-user-agent"
+          ],
+          "X-Forwarded-For": [
+            "123.123.123.123"
+          ]
+        },
+        "uri": "http://us.example.com/bid?uqhash=hash",
+        "body": {
+          "id": "some-request-id",
+          "device": {
+            "ua": "test-user-agent",
+            "ip": "123.123.123.123",
+            "language": "en",
+            "dnt": 0
+          },
+          "imp": [
+            {
+              "id": "some-impression-id",
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "minduration": 120,
+                "maxduration": 150,
+                "w": 640,
+                "h": 480
+              },
+              "tagid": "ogTAGID"
+            }
+          ],
+          "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": [
+          ],
+          "cur": "USD",
+          "ext": {
+            "responsetimemillis": {
+              "aceex": 154
+            },
+            "tmaxrequest": 1000
+          }
+        }
+      }
+    }
+  ],
+    "mockResponse": {
+      "status": 200,
+      "body": "invalid response"
+    },
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Empty SeatBid array",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/aceex/aceextest/supplemental/invalid-aceex-ext-object.json b/adapters/aceex/aceextest/supplemental/invalid-aceex-ext-object.json
new file mode 100644
index 00000000..77752d01
--- /dev/null
+++ b/adapters/aceex/aceextest/supplemental/invalid-aceex-ext-object.json
@@ -0,0 +1,29 @@
+{
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "ext.bidder not provided",
+      "comparison": "literal"
+    }
+  ],
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "my-adcode",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": "Awesome"
+      }
+    ],
+    "site": {
+      "page": "test.com"
+    }
+  },
+  "httpCalls": []
+}
diff --git a/adapters/aceex/aceextest/supplemental/invalid-response.json b/adapters/aceex/aceextest/supplemental/invalid-response.json
new file mode 100644
index 00000000..c1d62068
--- /dev/null
+++ b/adapters/aceex/aceextest/supplemental/invalid-response.json
@@ -0,0 +1,111 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "device": {
+      "ua": "test-user-agent",
+      "ip": "123.123.123.123",
+      "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",
+        "tagid": "ogTAGID",
+        "banner": {
+          "w":320,
+          "h":50
+        },
+        "ext": {
+          "bidder": {
+            "accountid": "hash"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "headers": {
+        "Content-Type": [
+          "application/json;charset=utf-8"
+        ],
+        "Accept": [
+          "application/json"
+        ],
+        "X-Openrtb-Version": [
+          "2.5"
+        ],
+        "User-Agent": [
+          "test-user-agent"
+        ],
+        "X-Forwarded-For": [
+          "123.123.123.123"
+        ]
+      },
+      "uri": "http://us.example.com/bid?uqhash=hash",
+      "body": {
+        "id": "some-request-id",
+        "device": {
+          "ua": "test-user-agent",
+          "ip": "123.123.123.123",
+          "language": "en",
+          "dnt": 0
+        },
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "banner": {
+                "w":320,
+                "h":50
+            },
+            "tagid": "ogTAGID"
+          }
+        ],
+        "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": "invalid response"
+    }
+  }],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bad Server Response",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/aceex/aceextest/supplemental/status-code-bad-request.json b/adapters/aceex/aceextest/supplemental/status-code-bad-request.json
new file mode 100644
index 00000000..553a9264
--- /dev/null
+++ b/adapters/aceex/aceextest/supplemental/status-code-bad-request.json
@@ -0,0 +1,92 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "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",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountid": "hash"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://us.example.com/bid?uqhash=hash",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            },
+            "tagid": "ogTAGID"
+          }
+        ],
+        "app":  {
+          "publisher": {
+            "id": "123456789"
+          },
+          "cat": [
+            "IAB22-1"
+          ],
+          "bundle": "com.app.awesome",
+          "name": "Awesome App",
+          "domain": "awesomeapp.com",
+          "id": "123456789"
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 400
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: [ 400 ]",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/aceex/aceextest/supplemental/status-code-no-content.json b/adapters/aceex/aceextest/supplemental/status-code-no-content.json
new file mode 100644
index 00000000..c669c3ce
--- /dev/null
+++ b/adapters/aceex/aceextest/supplemental/status-code-no-content.json
@@ -0,0 +1,68 @@
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [{
+      "id": "some-impression-id",
+      "tagid": "ogTAGID",
+      "video": {
+        "mimes": ["video/mp4"],
+        "w": 640,
+        "h": 480,
+        "minduration": 120,
+        "maxduration": 150
+      },
+      "ext": {
+        "bidder": {
+          "accountid": "hash"
+        }
+      }
+    }]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://us.example.com/bid?uqhash=hash",
+      "body": {
+        "id": "some-request-id",
+        "imp": [{
+          "id": "some-impression-id",
+          "tagid": "ogTAGID",
+          "video": {
+            "mimes": [
+              "video/mp4"
+            ],
+            "minduration": 120,
+            "maxduration": 150,
+            "w": 640,
+            "h": 480
+          }
+        }],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "123456789"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 204
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": []
+}
\ No newline at end of file
diff --git a/adapters/aceex/aceextest/supplemental/status-code-other-error.json b/adapters/aceex/aceextest/supplemental/status-code-other-error.json
new file mode 100644
index 00000000..18892fe5
--- /dev/null
+++ b/adapters/aceex/aceextest/supplemental/status-code-other-error.json
@@ -0,0 +1,78 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountid": "hash"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://us.example.com/bid?uqhash=hash",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "tagid": "ogTAGID",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            }
+          }
+        ],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "123456789"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 306
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: [ 306 ]. Run with request.debug = 1 for more info",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/aceex/aceextest/supplemental/status-code-service-unavailable.json b/adapters/aceex/aceextest/supplemental/status-code-service-unavailable.json
new file mode 100644
index 00000000..9c244ce3
--- /dev/null
+++ b/adapters/aceex/aceextest/supplemental/status-code-service-unavailable.json
@@ -0,0 +1,78 @@
+
+{
+  "mockBidRequest": {
+    "id": "some-request-id",
+    "tmax": 1000,
+    "user": {
+      "buyeruid": "awesome-user"
+    },
+    "site": {
+      "page": "test.com",
+      "publisher": {
+        "id": "123456789"
+      }
+    },
+    "imp": [
+      {
+        "id": "some-impression-id",
+        "tagid": "ogTAGID",
+        "video": {
+          "mimes": ["video/mp4"],
+          "w": 640,
+          "h": 480,
+          "minduration": 120,
+          "maxduration": 150
+        },
+        "ext": {
+          "bidder": {
+            "accountid": "hash"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://us.example.com/bid?uqhash=hash",
+      "body": {
+        "id": "some-request-id",
+        "imp": [
+          {
+            "id": "some-impression-id",
+            "tagid": "ogTAGID",
+            "video": {
+              "mimes": [
+                "video/mp4"
+              ],
+              "minduration": 120,
+              "maxduration": 150,
+              "w": 640,
+              "h": 480
+            }
+          }
+        ],
+        "site": {
+          "page": "test.com",
+          "publisher": {
+            "id": "123456789"
+          }
+        },
+        "user": {
+          "buyeruid": "awesome-user"
+        },
+        "tmax": 1000
+      }
+    },
+    "mockResponse": {
+      "status": 503
+    }
+  }],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Something went wrong, please contact your Account Manager. Status Code: [ 503 ] ",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/aceex/params_test.go b/adapters/aceex/params_test.go
new file mode 100644
index 00000000..220adb23
--- /dev/null
+++ b/adapters/aceex/params_test.go
@@ -0,0 +1,50 @@
+package aceex
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+var validParams = []string{
+	`{  "accountid": "hash" }`,
+}
+
+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.BidderAceex, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected Aceex params: %s", validParam)
+		}
+	}
+}
+
+var invalidParams = []string{
+	``,
+	`null`,
+	`true`,
+	`5`,
+	`4.2`,
+	`[]`,
+	`{}`,
+	`{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`,
+	`{  "accountid": "" }`,
+}
+
+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.BidderAceex, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
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/openweb/openweb_test.go b/adapters/openweb/openweb_test.go
new file mode 100644
index 00000000..007bcf52
--- /dev/null
+++ b/adapters/openweb/openweb_test.go
@@ -0,0 +1,20 @@
+package openweb
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderOpenWeb, config.Adapter{
+		Endpoint: "http://ghb.spotim.market/pbs/ortb"})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "openwebtest", bidder)
+}
diff --git a/adapters/openweb/openwebtest/exemplary/multiple-imps-same-aid.json b/adapters/openweb/openwebtest/exemplary/multiple-imps-same-aid.json
new file mode 100644
index 00000000..2abc3269
--- /dev/null
+++ b/adapters/openweb/openwebtest/exemplary/multiple-imps-same-aid.json
@@ -0,0 +1,174 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "bidfloor": 30,
+        "ext": {
+          "bidder": {
+            "aid": 1000,
+            "siteId": 1234,
+            "bidFloor": 20
+          }
+        }
+      },
+      {
+        "id": "test-imp-id-2",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "bidfloor": 30,
+        "ext": {
+          "bidder": {
+            "aid": 1000,
+            "siteId": 4321,
+            "bidFloor": 20
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://ghb.spotim.market/pbs/ortb?aid=1000",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "bidfloor": 20,
+              "ext": {
+                "openweb": {
+                  "aid": 1000,
+                  "siteId": 1234,
+                  "bidFloor": 20
+                }
+              }
+            },
+            {
+              "id": "test-imp-id-2",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "bidfloor": 20,
+              "ext": {
+                "openweb": {
+                  "aid": 1000,
+                  "siteId": 4321,
+                  "bidFloor": 20
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "test-seat",
+              "bid": [
+                {
+                  "id": "test-bid-id",
+                  "impid": "test-imp-id",
+                  "price": 30,
+                  "adm": "some-test-ad",
+                  "crid": "crid_10",
+                  "h": 250,
+                  "w": 300
+                },
+                {
+                  "id": "test-bid-id-2",
+                  "impid": "test-imp-id-2",
+                  "price": 30,
+                  "adm": "some-test-ad",
+                  "crid": "crid_10",
+                  "h": 250,
+                  "w": 300
+                }
+              ]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test-bid-id",
+            "impid": "test-imp-id",
+            "price": 30,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        },
+        {
+          "bid": {
+            "id": "test-bid-id-2",
+            "impid": "test-imp-id-2",
+            "price": 30,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/openweb/openwebtest/exemplary/simple-banner.json b/adapters/openweb/openwebtest/exemplary/simple-banner.json
new file mode 100644
index 00000000..dc4c42ac
--- /dev/null
+++ b/adapters/openweb/openwebtest/exemplary/simple-banner.json
@@ -0,0 +1,188 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "bidfloor": 30,
+        "ext": {
+          "bidder": {
+            "aid": 1000,
+            "siteId": 1234,
+            "bidFloor": 20
+          }
+        }
+      },
+      {
+        "id": "test-imp-id-2",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "bidfloor": 30,
+        "ext": {
+          "bidder": {
+            "aid": 2000,
+            "siteId": 4321,
+            "bidFloor": 20
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://ghb.spotim.market/pbs/ortb?aid=1000",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id":"test-imp-id",
+              "banner": {
+                "format": [
+                  {"w":300,"h":250},
+                  {"w":300,"h":600}
+                ]
+              },
+              "bidfloor": 20,
+              "ext": {
+                "openweb": {
+                  "aid": 1000,
+                  "siteId": 1234,
+                  "bidFloor": 20
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "test-seat",
+              "bid": [{
+                "id": "test-bid-id",
+                "impid": "test-imp-id",
+                "price": 30,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "h": 250,
+                "w": 300
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    },
+    {
+      "expectedRequest": {
+        "uri": "http://ghb.spotim.market/pbs/ortb?aid=2000",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id":"test-imp-id-2",
+              "banner": {
+                "format": [
+                  {"w":300,"h":250},
+                  {"w":300,"h":600}
+                ]
+              },
+              "bidfloor": 20,
+              "ext": {
+                "openweb": {
+                  "aid": 2000,
+                  "siteId": 4321,
+                  "bidFloor": 20
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "test-seat-2",
+              "bid": [{
+                "id": "test-bid-id-2",
+                "impid": "test-imp-id-2",
+                "price": 30,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "h": 250,
+                "w": 300
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test-bid-id",
+            "impid": "test-imp-id",
+            "price": 30,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    },
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test-bid-id-2",
+            "impid": "test-imp-id-2",
+            "price": 30,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/openweb/openwebtest/exemplary/simple-video.json b/adapters/openweb/openwebtest/exemplary/simple-video.json
new file mode 100644
index 00000000..795938a9
--- /dev/null
+++ b/adapters/openweb/openwebtest/exemplary/simple-video.json
@@ -0,0 +1,88 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "w": 900,
+          "h": 250,
+          "mimes": [
+            "video/x-flv",
+            "video/mp4"
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "aid": 1000
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://ghb.spotim.market/pbs/ortb?aid=1000",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id":"test-imp-id",
+              "video": {
+                "w": 900,
+                "h": 250,
+                "mimes": [
+                  "video/x-flv",
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "openweb": {
+                  "aid": 1000
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test-bid-id",
+                  "impid": "test-imp-id",
+                  "price": 3.5,
+                  "w": 900,
+                  "h": 250
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test-bid-id",
+            "impid": "test-imp-id",
+            "price": 3.5,
+            "w": 900,
+            "h": 250
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/openweb/openwebtest/supplemental/no-valid-imps.json b/adapters/openweb/openwebtest/supplemental/no-valid-imps.json
new file mode 100644
index 00000000..3335639d
--- /dev/null
+++ b/adapters/openweb/openwebtest/supplemental/no-valid-imps.json
@@ -0,0 +1,30 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "w": 900,
+          "h": 250,
+          "mimes": [
+            "video/x-flv",
+            "video/mp4"
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "aid": "not valid value"
+          }
+        }
+      }
+    ]
+  },
+
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "^ignoring imp id=test-imp-id, error while decoding impExt",
+      "comparison": "regex"
+    }
+  ]
+}
diff --git a/adapters/openweb/openwebtest/supplemental/status-204.json b/adapters/openweb/openwebtest/supplemental/status-204.json
new file mode 100644
index 00000000..8c0274ad
--- /dev/null
+++ b/adapters/openweb/openwebtest/supplemental/status-204.json
@@ -0,0 +1,55 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "w": 900,
+          "h": 250,
+          "mimes": [
+            "video/x-flv",
+            "video/mp4"
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "aid": 1000
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://ghb.spotim.market/pbs/ortb?aid=1000",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id":"test-imp-id",
+              "video": {
+                "w": 900,
+                "h": 250,
+                "mimes": [
+                  "video/x-flv",
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "openweb": {
+                  "aid": 1000
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 204
+      }
+    }
+  ]
+}
diff --git a/adapters/openweb/openwebtest/supplemental/status-400.json b/adapters/openweb/openwebtest/supplemental/status-400.json
new file mode 100644
index 00000000..1b8ea455
--- /dev/null
+++ b/adapters/openweb/openwebtest/supplemental/status-400.json
@@ -0,0 +1,65 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "w": 900,
+          "h": 250,
+          "mimes": [
+            "video/x-flv",
+            "video/mp4"
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "aid": 1000
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://ghb.spotim.market/pbs/ortb?aid=1000",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id":"test-imp-id",
+              "video": {
+                "w": 900,
+                "h": 250,
+                "mimes": [
+                  "video/x-flv",
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "openweb": {
+                  "aid": 1000
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 400,
+        "body": "Bad request"
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Remote server error: \"Bad request\"",
+      "comparison": "literal"
+    }
+  ],
+
+  "expectedBidResponses": []
+}
diff --git a/adapters/openweb/openwebtest/supplemental/status-500.json b/adapters/openweb/openwebtest/supplemental/status-500.json
new file mode 100644
index 00000000..1dac7250
--- /dev/null
+++ b/adapters/openweb/openwebtest/supplemental/status-500.json
@@ -0,0 +1,65 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "w": 900,
+          "h": 250,
+          "mimes": [
+            "video/x-flv",
+            "video/mp4"
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "aid": 1000
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://ghb.spotim.market/pbs/ortb?aid=1000",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id":"test-imp-id",
+              "video": {
+                "w": 900,
+                "h": 250,
+                "mimes": [
+                  "video/x-flv",
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "openweb": {
+                  "aid": 1000
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 500,
+        "body": "Internal error"
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Remote server error: \"Internal error\"",
+      "comparison": "literal"
+    }
+  ],
+
+  "expectedBidResponses": []
+}
diff --git a/adapters/openweb/openwebtest/supplemental/wrong-impression-mapping.json b/adapters/openweb/openwebtest/supplemental/wrong-impression-mapping.json
new file mode 100644
index 00000000..776cbabc
--- /dev/null
+++ b/adapters/openweb/openwebtest/supplemental/wrong-impression-mapping.json
@@ -0,0 +1,77 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "w": 900,
+          "h": 250,
+          "mimes": [
+            "video/x-flv",
+            "video/mp4"
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "aid": 1000
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://ghb.spotim.market/pbs/ortb?aid=1000",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id":"test-imp-id",
+              "video": {
+                "w": 900,
+                "h": 250,
+                "mimes": [
+                  "video/x-flv",
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "openweb": {
+                  "aid": 1000
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test-bid-id",
+                  "impid": "SOME-WRONG-IMP-ID",
+                  "price": 3.5,
+                  "w": 900,
+                  "h": 250
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "ignoring bid id=test-bid-id, request doesn't contain any impression with id=SOME-WRONG-IMP-ID",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/openweb/params_test.go b/adapters/openweb/params_test.go
new file mode 100644
index 00000000..62bdaf93
--- /dev/null
+++ b/adapters/openweb/params_test.go
@@ -0,0 +1,60 @@
+package openweb
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// This file actually intends to test static/bidder-params/openweb.json
+// These also validate the format of the external API: request.imp[i].ext.openweb
+// TestValidParams makes sure that the openweb schema accepts all imp.ext fields which we intend to support.
+
+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.BidderOpenWeb, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected openweb params: %s", validParam)
+		}
+	}
+}
+
+// TestInvalidParams makes sure that the openweb schema rejects all the imp.ext fields we don't support.
+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.BidderOpenWeb, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"aid":123}`,
+	`{"aid":123,"placementId":1234}`,
+	`{"aid":123,"siteId":4321}`,
+	`{"aid":123,"siteId":0,"bidFloor":0}`,
+}
+
+var invalidParams = []string{
+	``,
+	`null`,
+	`true`,
+	`5`,
+	`4.2`,
+	`[]`,
+	`{}`,
+	`{"aid":"some string instead of int"}`,
+	`{"aid":"0"}`,
+	`{"aid":"123","placementId":"123"}`,
+	`{"aid":123, "placementId":"123", "siteId":"321"}`,
+}
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/auction_test.go b/endpoints/openrtb2/auction_test.go
index 748107c8..31c3c109 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -1000,6 +1000,97 @@ func TestRefererParsing(t *testing.T) {
 	}
 }
 
+func TestParseImpInfoSingleImpression(t *testing.T) {
+
+	expectedRes := []ImpExtPrebidData{
+		{
+			Imp:          json.RawMessage(`{"video":{"h":300,"w":200},"ext": {"prebid": {"storedrequest": {"id": "1"},"options": {"echovideoattrs": true}}}}`),
+			ImpExtPrebid: openrtb_ext.ExtImpPrebid{StoredRequest: &openrtb_ext.ExtStoredRequest{ID: "1"}, Options: &openrtb_ext.Options{EchoVideoAttrs: true}},
+		},
+		{
+			Imp:          json.RawMessage(`{"id": "adUnit2","ext": {"prebid": {"storedrequest": {"id": "1"},"options": {"echovideoattrs": true}},"appnexus": {"placementId": "def","trafficSourceCode": "mysite.com","reserve": null},"rubicon": null}}`),
+			ImpExtPrebid: openrtb_ext.ExtImpPrebid{StoredRequest: &openrtb_ext.ExtStoredRequest{ID: "1"}, Options: &openrtb_ext.Options{EchoVideoAttrs: true}},
+		},
+		{
+			Imp:          json.RawMessage(`{"ext": {"prebid": {"storedrequest": {"id": "2"},"options": {"echovideoattrs": false}}}}`),
+			ImpExtPrebid: openrtb_ext.ExtImpPrebid{StoredRequest: &openrtb_ext.ExtStoredRequest{ID: "2"}, Options: &openrtb_ext.Options{EchoVideoAttrs: false}},
+		},
+		{
+			//in this case impression doesn't have storedrequest so we don't expect any data about this imp will be returned
+			Imp:          json.RawMessage(`{"id": "some-static-imp","video":{"mimes":["video/mp4"]},"ext": {"appnexus": {"placementId": "abc","position": "below"}}}`),
+			ImpExtPrebid: openrtb_ext.ExtImpPrebid{},
+		},
+	}
+
+	for i, requestData := range testStoredRequests {
+		impInfo, errs := parseImpInfo([]byte(requestData))
+		assert.Len(t, errs, 0, "No errors should be returned")
+		assert.JSONEq(t, string(expectedRes[i].Imp), string(impInfo[0].Imp), "Incorrect impression data")
+		assert.Equal(t, expectedRes[i].ImpExtPrebid, impInfo[0].ImpExtPrebid, "Incorrect impression ext prebid data")
+
+	}
+}
+
+func TestParseImpInfoMultipleImpressions(t *testing.T) {
+
+	inputData := []byte(`{
+		"id": "ThisID",
+		"imp": [
+			{
+				"id": "imp1",
+				"ext": {
+					"prebid": {
+						"storedrequest": {
+							"id": "1"
+						},
+						"options": {
+							"echovideoattrs": true
+						}
+					}
+				}
+			},
+			{
+				"id": "imp2",
+				"ext": {
+					"prebid": {
+						"storedrequest": {
+							"id": "2"
+						},
+						"options": {
+							"echovideoattrs": false
+						}
+					}
+				}
+			},
+			{
+				"id": "imp3"
+			}
+		]
+	}`)
+
+	expectedRes := []ImpExtPrebidData{
+		{
+			Imp:          json.RawMessage(`{"id": "imp1","ext": {"prebid": {"storedrequest": {"id": "1"},"options": {"echovideoattrs": true}}}}`),
+			ImpExtPrebid: openrtb_ext.ExtImpPrebid{StoredRequest: &openrtb_ext.ExtStoredRequest{ID: "1"}, Options: &openrtb_ext.Options{EchoVideoAttrs: true}},
+		},
+		{
+			Imp:          json.RawMessage(`{"id": "imp2","ext": {"prebid": {"storedrequest": {"id": "2"},"options": {"echovideoattrs": false}}}}`),
+			ImpExtPrebid: openrtb_ext.ExtImpPrebid{StoredRequest: &openrtb_ext.ExtStoredRequest{ID: "2"}, Options: &openrtb_ext.Options{EchoVideoAttrs: false}},
+		},
+		{
+			Imp:          json.RawMessage(`{"id": "imp3"}`),
+			ImpExtPrebid: openrtb_ext.ExtImpPrebid{},
+		},
+	}
+
+	impInfo, errs := parseImpInfo([]byte(inputData))
+	assert.Len(t, errs, 0, "No errors should be returned")
+	for i, res := range expectedRes {
+		assert.JSONEq(t, string(res.Imp), string(impInfo[i].Imp), "Incorrect impression data")
+		assert.Equal(t, res.ImpExtPrebid, impInfo[i].ImpExtPrebid, "Incorrect impression ext prebid data")
+	}
+}
+
 // Test the stored request functionality
 func TestStoredRequests(t *testing.T) {
 	deps := &endpointDeps{
@@ -1023,7 +1114,9 @@ func TestStoredRequests(t *testing.T) {
 	testStoreVideoAttr := []bool{true, true, false, false}
 
 	for i, requestData := range testStoredRequests {
-		newRequest, impExtInfoMap, errList := deps.processStoredRequests(context.Background(), json.RawMessage(requestData))
+		impInfo, errs := parseImpInfo([]byte(requestData))
+		assert.Len(t, errs, 0, "No errors should be returned")
+		newRequest, impExtInfoMap, errList := deps.processStoredRequests(context.Background(), json.RawMessage(requestData), impInfo)
 		if len(errList) != 0 {
 			for _, err := range errList {
 				if err != nil {
@@ -1047,40 +1140,6 @@ func TestStoredRequests(t *testing.T) {
 	}
 }
 
-func TestStoredRequestsVideoErrors(t *testing.T) {
-	deps := &endpointDeps{
-		&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},
-	}
-
-	// tests processStoredRequests function behavior in parsing incorrect input related to echovideoattrs feature
-	// this test now has 2 scenarios:
-	// 1) expected value we get using jsonparser.GetBoolean is integer
-	// 2) imp id is not found using jsonparser.GetString
-	// this loop iterates over testStoredRequestsErrors where input json has incorrect set up
-	// testStoredRequestsErrorsResults variable contains error message for every iteration
-
-	for i, requestData := range testStoredRequestsErrors {
-		_, _, errList := deps.processStoredRequests(context.Background(), json.RawMessage(requestData))
-
-		assert.NotEmpty(t, errList, "processStoredRequests should return error")
-		assert.Contains(t, errList[0].Error(), testStoredRequestsErrorsResults[i], "Incorrect error")
-	}
-}
-
 // TestOversizedRequest makes sure we behave properly when the request size exceeds the configured max.
 func TestOversizedRequest(t *testing.T) {
 	reqBody := validRequest(t, "site.json")
@@ -2311,6 +2370,36 @@ func TestAuctionWarnings(t *testing.T) {
 	assert.Equal(t, errortypes.InvalidPrivacyConsentWarningCode, actualWarning.WarningCode, "Warning code is incorrect")
 }
 
+func TestParseRequestParseImpInfoError(t *testing.T) {
+	reqBody := validRequest(t, "imp-info-invalid.json")
+	deps := &endpointDeps{
+		&warningsCheckExchange{},
+		newParamsValidator(t),
+		&mockStoredReqFetcher{},
+		empty_fetcher.EmptyFetcher{},
+		empty_fetcher.EmptyFetcher{},
+		&config.Configuration{MaxRequestSize: int64(len(reqBody))},
+		&metricsConfig.DummyMetricsEngine{},
+		analyticsConf.NewPBSAnalytics(&config.Analytics{}),
+		map[string]string{},
+		false,
+		[]byte{},
+		openrtb_ext.BuildBidderMap(),
+		nil,
+		nil,
+		hardcodedResponseIPValidator{response: true},
+	}
+
+	req := httptest.NewRequest("POST", "/openrtb2/auction", strings.NewReader(reqBody))
+
+	resReq, impExtInfoMap, errL := deps.parseRequest(req)
+
+	assert.Nil(t, resReq, "Result request should be nil due to incorrect imp")
+	assert.Nil(t, impExtInfoMap, "Impression info map should be nil due to incorrect imp")
+	assert.Len(t, errL, 1, "One error should be returned")
+	assert.Contains(t, errL[0].Error(), "echovideoattrs of type bool", "Incorrect error message")
+}
+
 func TestValidateNativeContextTypes(t *testing.T) {
 	impIndex := 4
 
@@ -3141,73 +3230,6 @@ var testStoredRequests = []string{
 	}`,
 }
 
-var testStoredRequestsErrors = []string{
-	`{
-		"id": "ThisID",
-		"imp": [
-			{
-				"video":{
-					"h":300,
-					"w":200
-				},
-				"ext": {
-					"prebid": {
-						"storedrequest": {
-							"id": "1"
-						},
-						"options": {
-							"echovideoattrs": 1
-						}
-					}
-				}
-			}
-		],
-		"ext": {
-			"prebid": {
-				"cache": {
-					"markup": 1
-				},
-				"targeting": {
-				}
-			}
-		}
-	}`, `{
-		"id": "ThisID",
-		"imp": [
-			{
-				"video":{
-					"h":300,
-					"w":200
-				},
-				"ext": {
-					"prebid": {
-						"storedrequest": {
-							"id": "10"
-						},
-						"options": {
-							"echovideoattrs": true
-						}
-					}
-				}
-			}
-		],
-		"ext": {
-			"prebid": {
-				"cache": {
-					"markup": 1
-				},
-				"targeting": {
-				}
-			}
-		}
-	}`,
-}
-
-var testStoredRequestsErrorsResults = []string{
-	"Value is not a boolean: 1",
-	"Key path not found",
-}
-
 // The expected requests after stored request processing
 var testFinalRequests = []string{
 	`{
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)
+	}
+}