diff --git a/adapters/dxtech/dxtech.go b/adapters/dxtech/dxtech.go
new file mode 100644
index 00000000000..ab5bcf28201
--- /dev/null
+++ b/adapters/dxtech/dxtech.go
@@ -0,0 +1,171 @@
+package dxtech
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+
+ "github.com/prebid/prebid-server/v4/adapters"
+ "github.com/prebid/prebid-server/v4/config"
+ "github.com/prebid/prebid-server/v4/errortypes"
+ "github.com/prebid/prebid-server/v4/openrtb_ext"
+ "github.com/prebid/prebid-server/v4/util/jsonutil"
+
+ "github.com/prebid/openrtb/v20/openrtb2"
+)
+
+var markupTypeToBidType = map[openrtb2.MarkupType]openrtb_ext.BidType{
+ openrtb2.MarkupBanner: openrtb_ext.BidTypeBanner,
+ openrtb2.MarkupVideo: openrtb_ext.BidTypeVideo,
+}
+
+type adapter struct {
+ endpoint string
+}
+
+// Builder builds a new instance of the DXTech adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
+ bidder := &adapter{
+ endpoint: config.Endpoint,
+ }
+ return bidder, nil
+}
+
+func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+ impressions := request.Imp
+
+ adapterRequests := make([]*adapters.RequestData, 0, len(impressions))
+ var errs []error
+
+ for _, impression := range impressions {
+ impExt, err := parseExt(&impression)
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+
+ request.Imp = []openrtb2.Imp{impression}
+ body, err := jsonutil.Marshal(request)
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+
+ if request.Test == 1 {
+ impExt.PublisherId = "test"
+ }
+
+ params := url.Values{}
+ params.Add("publisher_id", impExt.PublisherId)
+ params.Add("placement_id", impExt.PlacementId)
+
+ adapterRequests = append(adapterRequests, &adapters.RequestData{
+ Method: http.MethodPost,
+ Uri: a.endpoint + "?" + params.Encode(),
+ Body: body,
+ Headers: getHeaders(request),
+ ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
+ })
+ }
+
+ request.Imp = impressions
+ return adapterRequests, errs
+}
+
+func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+ if adapters.IsResponseStatusCodeNoContent(response) {
+ return nil, nil
+ }
+ if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil {
+ return nil, []error{err}
+ }
+
+ var ortbResponse openrtb2.BidResponse
+ err := jsonutil.Unmarshal(response.Body, &ortbResponse)
+ if err != nil {
+ return nil, []error{&errortypes.BadServerResponse{
+ Message: "Bad Server Response",
+ }}
+ }
+
+ var bidErrors []error
+
+ bidderResponse := adapters.NewBidderResponseWithBidsCapacity(1)
+ for _, seatBid := range ortbResponse.SeatBid {
+ for i := range seatBid.Bid {
+ bid := seatBid.Bid[i]
+ bidType, err := getBidType(&bid)
+ if err != nil {
+ bidErrors = append(bidErrors, err)
+ continue
+ }
+
+ bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{
+ Bid: &bid,
+ BidType: bidType,
+ })
+ }
+ }
+
+ return bidderResponse, bidErrors
+}
+
+func getBidType(bid *openrtb2.Bid) (openrtb_ext.BidType, error) {
+ if bidType, ok := markupTypeToBidType[bid.MType]; ok {
+ return bidType, nil
+ }
+ return "", &errortypes.BadServerResponse{
+ Message: fmt.Sprintf("Unsupported MType %d", bid.MType),
+ }
+}
+
+func parseExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpDXTech, error) {
+ var bidderExt adapters.ExtImpBidder
+
+ if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil {
+ return nil, &errortypes.BadInput{
+ Message: fmt.Sprintf("Ignoring imp id=%s, error while decoding extImpBidder, err: %s", imp.ID, err),
+ }
+ }
+
+ impExt := openrtb_ext.ExtImpDXTech{}
+ err := jsonutil.Unmarshal(bidderExt.Bidder, &impExt)
+ if err != nil {
+ return nil, &errortypes.BadInput{
+ Message: fmt.Sprintf("Ignoring imp id=%s, error while decoding impExt, err: %s", imp.ID, err),
+ }
+ }
+
+ return &impExt, nil
+}
+
+func getHeaders(request *openrtb2.BidRequest) http.Header {
+ headers := http.Header{}
+ headers.Set("Content-Type", "application/json;charset=utf-8")
+ headers.Set("Accept", "application/json")
+ headers.Set("X-Openrtb-Version", "2.6")
+
+ if request.Site != nil {
+ if request.Site.Ref != "" {
+ headers.Set("Referer", request.Site.Ref)
+ }
+ if request.Site.Domain != "" {
+ headers.Set("Origin", request.Site.Domain)
+ }
+ }
+
+ if request.Device != nil {
+ if len(request.Device.UA) > 0 {
+ headers.Set("User-Agent", request.Device.UA)
+ }
+
+ if len(request.Device.IPv6) > 0 {
+ headers.Set("X-Forwarded-For", request.Device.IPv6)
+ }
+
+ if len(request.Device.IP) > 0 {
+ headers.Set("X-Forwarded-For", request.Device.IP)
+ }
+ }
+ return headers
+}
diff --git a/adapters/dxtech/dxtech_test.go b/adapters/dxtech/dxtech_test.go
new file mode 100644
index 00000000000..b911bcecd85
--- /dev/null
+++ b/adapters/dxtech/dxtech_test.go
@@ -0,0 +1,17 @@
+package dxtech
+
+import (
+ "testing"
+
+ "github.com/prebid/prebid-server/v4/config"
+
+ "github.com/prebid/prebid-server/v4/adapters/adapterstest"
+)
+
+func TestJsonSamples(t *testing.T) {
+ bidder, buildErr := Builder("dxtech", config.Adapter{Endpoint: "https://ads.dxtech.ai/pbs"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
+ if buildErr != nil {
+ t.Fatalf("Builder returned unexpected error %v", buildErr)
+ }
+ adapterstest.RunJSONBidderTest(t, "dxtechtest", bidder)
+}
diff --git a/adapters/dxtech/dxtechtest/exemplary/banner.json b/adapters/dxtech/dxtechtest/exemplary/banner.json
new file mode 100644
index 00000000000..8c6c72a6e1a
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/exemplary/banner.json
@@ -0,0 +1,145 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Referer": [
+ "http://site.com/ref"
+ ],
+ "Origin": [
+ "site.com"
+ ],
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ]
+ },
+ "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123",
+ "body": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id",
+ "adid": "2422",
+ "adm": "",
+ "mtype": 1
+ }
+ ],
+ "seat": "dxtech"
+ }
+ ],
+ "bidid": "test-request-id",
+ "id": "test-request-id"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id",
+ "adid": "2422",
+ "adm": "",
+ "mtype": 1
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json b/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json
new file mode 100644
index 00000000000..ff0a83ffbdf
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json
@@ -0,0 +1,143 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "http://site.com/page"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ]
+ },
+ "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123",
+ "body": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "http://site.com/page"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id",
+ "adid": "2422",
+ "adm": "",
+ "mtype": 2
+ }
+ ],
+ "seat": "dxtech"
+ }
+ ],
+ "bidid": "test-request-id",
+ "id": "test-request-id"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id",
+ "adid": "2422",
+ "adm": "",
+ "mtype": 2
+ },
+ "type": "video"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/dxtech/dxtechtest/exemplary/ipv6.json b/adapters/dxtech/dxtechtest/exemplary/ipv6.json
new file mode 100644
index 00000000000..7991213c5c7
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/exemplary/ipv6.json
@@ -0,0 +1,143 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ipv6": "2001:0000:130F:0000:0000:09C0:876A:130B"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "http://site.com/page"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "2001:0000:130F:0000:0000:09C0:876A:130B"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ]
+ },
+ "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123",
+ "body": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ipv6": "2001:0000:130F:0000:0000:09C0:876A:130B"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "page": "http://site.com/page"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id",
+ "adid": "2422",
+ "adm": "",
+ "mtype": 2
+ }
+ ],
+ "seat": "dxtech"
+ }
+ ],
+ "bidid": "test-request-id",
+ "id": "test-request-id"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id",
+ "adid": "2422",
+ "adm": "",
+ "mtype": 2
+ },
+ "type": "video"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/dxtech/dxtechtest/exemplary/multi-imp.json b/adapters/dxtech/dxtechtest/exemplary/multi-imp.json
new file mode 100644
index 00000000000..3ebff0ca499
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/exemplary/multi-imp.json
@@ -0,0 +1,266 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id-1",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ },
+ {
+ "id": "test-imp-id-2",
+ "banner": {
+ "w": 728,
+ "h": 90
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement456"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Referer": [
+ "http://site.com/ref"
+ ],
+ "Origin": [
+ "site.com"
+ ],
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ]
+ },
+ "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123",
+ "body": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id-1",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "impIDs": ["test-imp-id-1"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "bid-id-1",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id-1",
+ "adid": "2422",
+ "adm": "",
+ "mtype": 1
+ }
+ ],
+ "seat": "dxtech"
+ }
+ ],
+ "bidid": "test-request-id",
+ "id": "test-request-id"
+ }
+ }
+ },
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Referer": [
+ "http://site.com/ref"
+ ],
+ "Origin": [
+ "site.com"
+ ],
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ]
+ },
+ "uri": "https://ads.dxtech.ai/pbs?placement_id=placement456&publisher_id=pub123",
+ "body": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id-2",
+ "banner": {
+ "w": 728,
+ "h": 90
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement456"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "impIDs": ["test-imp-id-2"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "bid-id-2",
+ "crid": "16330",
+ "adomain": [
+ "adomain2.com"
+ ],
+ "price": 5,
+ "impid": "test-imp-id-2",
+ "adid": "2423",
+ "adm": "",
+ "mtype": 1
+ }
+ ],
+ "seat": "dxtech"
+ }
+ ],
+ "bidid": "test-request-id",
+ "id": "test-request-id"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "bid-id-1",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id-1",
+ "adid": "2422",
+ "adm": "",
+ "mtype": 1
+ },
+ "type": "banner"
+ }
+ ]
+ },
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "bid-id-2",
+ "crid": "16330",
+ "adomain": [
+ "adomain2.com"
+ ],
+ "price": 5,
+ "impid": "test-imp-id-2",
+ "adid": "2423",
+ "adm": "",
+ "mtype": 1
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/dxtech/dxtechtest/exemplary/video-test-request.json b/adapters/dxtech/dxtechtest/exemplary/video-test-request.json
new file mode 100644
index 00000000000..683c985289b
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/exemplary/video-test-request.json
@@ -0,0 +1,155 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "test": 1,
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Referer": [
+ "http://site.com/ref"
+ ],
+ "Origin": [
+ "site.com"
+ ],
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ]
+ },
+ "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=test",
+ "body": {
+ "id": "test-request-id",
+ "test": 1,
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id",
+ "adid": "2422",
+ "adm": "",
+ "mtype": 2
+ }
+ ],
+ "seat": "dxtech"
+ }
+ ],
+ "bidid": "test-request-id",
+ "id": "test-request-id"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id",
+ "adid": "2422",
+ "adm": "",
+ "mtype": 2
+ },
+ "type": "video"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/dxtech/dxtechtest/exemplary/video.json b/adapters/dxtech/dxtechtest/exemplary/video.json
new file mode 100644
index 00000000000..bb039e971de
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/exemplary/video.json
@@ -0,0 +1,153 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Referer": [
+ "http://site.com/ref"
+ ],
+ "Origin": [
+ "site.com"
+ ],
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ]
+ },
+ "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123",
+ "body": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id",
+ "adid": "2422",
+ "adm": "",
+ "mtype": 2
+ }
+ ],
+ "seat": "dxtech"
+ }
+ ],
+ "bidid": "test-request-id",
+ "id": "test-request-id"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id",
+ "adid": "2422",
+ "adm": "",
+ "mtype": 2
+ },
+ "type": "video"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/dxtech/dxtechtest/supplemental/invalid-imp-ext-bidder.json b/adapters/dxtech/dxtechtest/supplemental/invalid-imp-ext-bidder.json
new file mode 100644
index 00000000000..549aef86ba9
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/supplemental/invalid-imp-ext-bidder.json
@@ -0,0 +1,40 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": "not_json"
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "Ignoring imp id=test-imp-id, error while decoding impExt, err: expect { or n, but found \"",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/dxtech/dxtechtest/supplemental/invalid-imp-ext.json b/adapters/dxtech/dxtechtest/supplemental/invalid-imp-ext.json
new file mode 100644
index 00000000000..fddf37a0b99
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/supplemental/invalid-imp-ext.json
@@ -0,0 +1,38 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": "not_json"
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "Ignoring imp id=test-imp-id, error while decoding extImpBidder, err: expect { or n, but found \"",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/dxtech/dxtechtest/supplemental/invalid-response.json b/adapters/dxtech/dxtechtest/supplemental/invalid-response.json
new file mode 100644
index 00000000000..93afea8c7b1
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/supplemental/invalid-response.json
@@ -0,0 +1,114 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Referer": [
+ "http://site.com/ref"
+ ],
+ "Origin": [
+ "site.com"
+ ],
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ]
+ },
+ "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123",
+ "body": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": "body"
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Bad Server Response",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/dxtech/dxtechtest/supplemental/no-mtype.json b/adapters/dxtech/dxtechtest/supplemental/no-mtype.json
new file mode 100644
index 00000000000..2ef76d53c10
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/supplemental/no-mtype.json
@@ -0,0 +1,143 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Referer": [
+ "http://site.com/ref"
+ ],
+ "Origin": [
+ "site.com"
+ ],
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ]
+ },
+ "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123",
+ "body": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "cur": "USD",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
+ "crid": "16329",
+ "adomain": [
+ "adomain.com"
+ ],
+ "price": 3,
+ "impid": "test-imp-id",
+ "adid": "2422",
+ "adm": ""
+ }
+ ],
+ "seat": "dxtech"
+ }
+ ],
+ "bidid": "test-request-id",
+ "id": "test-request-id"
+ }
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Unsupported MType 0",
+ "comparison": "literal"
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": []
+ }
+ ]
+
+}
diff --git a/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json b/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json
new file mode 100644
index 00000000000..7a147852a6c
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json
@@ -0,0 +1,113 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Referer": [
+ "http://site.com/ref"
+ ],
+ "Origin": [
+ "site.com"
+ ],
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ]
+ },
+ "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123",
+ "body": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 400
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Unexpected status code: 400. Run with request.debug = 1 for more info",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json b/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json
new file mode 100644
index 00000000000..5b7b65cc8f7
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json
@@ -0,0 +1,109 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Referer": [
+ "http://site.com/ref"
+ ],
+ "Origin": [
+ "site.com"
+ ],
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ]
+ },
+ "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123",
+ "body": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 204
+ }
+ }
+ ],
+ "expectedBidResponses": [],
+ "expectedMakeBidsErrors": []
+}
diff --git a/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json b/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json
new file mode 100644
index 00000000000..487245ceb89
--- /dev/null
+++ b/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json
@@ -0,0 +1,113 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "method": "POST",
+ "headers": {
+ "Referer": [
+ "http://site.com/ref"
+ ],
+ "Origin": [
+ "site.com"
+ ],
+ "Accept": [
+ "application/json"
+ ],
+ "Content-Type": [
+ "application/json;charset=utf-8"
+ ],
+ "User-Agent": [
+ "user-agent"
+ ],
+ "X-Forwarded-For": [
+ "1.2.3.4"
+ ],
+ "X-Openrtb-Version": [
+ "2.6"
+ ]
+ },
+ "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123",
+ "body": {
+ "id": "test-request-id",
+ "user": {
+ "buyeruid": "userId",
+ "yob": 1990
+ },
+ "device": {
+ "ua": "user-agent",
+ "ip": "1.2.3.4"
+ },
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "w": 1920,
+ "h": 1080,
+ "mimes": [
+ "video/x-flv",
+ "video/mp4"
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "publisherId": "pub123",
+ "placementId": "placement123"
+ }
+ }
+ }
+ ],
+ "site": {
+ "domain": "site.com",
+ "page": "http://site.com/page",
+ "ref": "http://site.com/ref"
+ }
+ },
+ "impIDs":["test-imp-id"]
+ },
+ "mockResponse": {
+ "status": 505
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Unexpected status code: 505. Run with request.debug = 1 for more info",
+ "comparison": "literal"
+ }
+ ]
+}
diff --git a/adapters/dxtech/params_test.go b/adapters/dxtech/params_test.go
new file mode 100644
index 00000000000..6a9f9483cc6
--- /dev/null
+++ b/adapters/dxtech/params_test.go
@@ -0,0 +1,53 @@
+package dxtech
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/prebid/prebid-server/v4/openrtb_ext"
+)
+
+// This file actually intends to test static/bidder-params/dxtech.json
+//
+// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.dxtech
+
+// TestValidParams makes sure that the dxtech 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.BidderDXTech, json.RawMessage(validParam)); err != nil {
+ t.Errorf("Schema rejected dxtech params: %s", validParam)
+ }
+ }
+}
+
+// TestInvalidParams makes sure that the dxtech 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.BidderDXTech, json.RawMessage(invalidParam)); err == nil {
+ t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+ }
+ }
+}
+
+var validParams = []string{
+ `{"publisherId": "pub", "placementId": "plac"}`,
+ `{"publisherId": "pub", "placementId": "plac", "a":1}`,
+}
+
+var invalidParams = []string{
+ `{"publisherId": "pub"}`,
+ `{"placementId": "plac"}`,
+ //malformed
+ `{"ub", "placementId": "plac"}`,
+ `{}`,
+}
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 630fbe348b9..fe820007dd9 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -97,6 +97,7 @@ import (
"github.com/prebid/prebid-server/v4/adapters/displayio"
"github.com/prebid/prebid-server/v4/adapters/dmx"
"github.com/prebid/prebid-server/v4/adapters/driftpixel"
+ "github.com/prebid/prebid-server/v4/adapters/dxtech"
evolution "github.com/prebid/prebid-server/v4/adapters/e_volution"
"github.com/prebid/prebid-server/v4/adapters/edge226"
"github.com/prebid/prebid-server/v4/adapters/elementaltv"
@@ -364,6 +365,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
openrtb_ext.BidderDisplayio: displayio.Builder,
openrtb_ext.BidderEdge226: edge226.Builder,
openrtb_ext.BidderDmx: dmx.Builder,
+ openrtb_ext.BidderDXTech: dxtech.Builder,
openrtb_ext.BidderDriftPixel: driftpixel.Builder,
openrtb_ext.BidderElementalTV: elementaltv.Builder,
openrtb_ext.BidderEmtv: emtv.Builder,
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 1b61ff724e2..9d9115cac62 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -113,6 +113,7 @@ var coreBidderNames []BidderName = []BidderName{
BidderDisplayio,
BidderEdge226,
BidderDmx,
+ BidderDXTech,
BidderDriftPixel,
BidderElementalTV,
BidderEmtv,
@@ -487,6 +488,7 @@ const (
BidderDisplayio BidderName = "displayio"
BidderEdge226 BidderName = "edge226"
BidderDmx BidderName = "dmx"
+ BidderDXTech BidderName = "dxtech"
BidderDriftPixel BidderName = "driftpixel"
BidderElementalTV BidderName = "elementaltv"
BidderEmtv BidderName = "emtv"
diff --git a/openrtb_ext/imp_dxtech.go b/openrtb_ext/imp_dxtech.go
new file mode 100644
index 00000000000..5022dfe2de3
--- /dev/null
+++ b/openrtb_ext/imp_dxtech.go
@@ -0,0 +1,7 @@
+package openrtb_ext
+
+// ExtImpDXTech defines the contract for bidrequest.imp[i].ext.prebid.bidder.dxtech
+type ExtImpDXTech struct {
+ PublisherId string `json:"publisherId"`
+ PlacementId string `json:"placementId"`
+}
diff --git a/static/bidder-info/dxtech.yaml b/static/bidder-info/dxtech.yaml
new file mode 100644
index 00000000000..26d9864d0d2
--- /dev/null
+++ b/static/bidder-info/dxtech.yaml
@@ -0,0 +1,16 @@
+endpoint: "https://ads.dxtech.ai/pbs"
+maintainer:
+ email: "support@dxtech.ai"
+capabilities:
+ app:
+ mediaTypes:
+ - banner
+ - video
+ site:
+ mediaTypes:
+ - banner
+ - video
+userSync:
+ redirect:
+ url: "https://sync.dxtech.ai/usync-pbs?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&cb={{.RedirectURL}}"
+ userMacro: "$UID"
diff --git a/static/bidder-info/nuba.yaml b/static/bidder-info/nuba.yaml
new file mode 100644
index 00000000000..803402c68a1
--- /dev/null
+++ b/static/bidder-info/nuba.yaml
@@ -0,0 +1,4 @@
+aliasOf: "teqblaze"
+endpoint: "https://ads.nuba.io/pserver"
+maintainer:
+ email: "tech@nuba.io"
diff --git a/static/bidder-params/dxtech.json b/static/bidder-params/dxtech.json
new file mode 100644
index 00000000000..1e9cb29137e
--- /dev/null
+++ b/static/bidder-params/dxtech.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "DXTech Adapter Params",
+ "description": "A schema which validates params accepted by the DXTech adapter",
+ "type": "object",
+ "properties": {
+ "publisherId": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The publisher id"
+ },
+ "placementId": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The placement id"
+ }
+ },
+ "required": [
+ "publisherId",
+ "placementId"
+ ]
+}