From 33714f275908f709738689681d9b12cdcdd06e6b Mon Sep 17 00:00:00 2001
From: ownAdx <135326256+ownAdx-prebid@users.noreply.github.com>
Date: Wed, 26 Jul 2023 20:49:57 +0530
Subject: [PATCH] New Adapter: OwnAdX (#2850)
Co-authored by @ownAdx-prebid
---
adapters/ownadx/ownadx.go | 213 ++++++++++++++++++
adapters/ownadx/ownadx_test.go | 17 ++
.../ownadx/ownadxtest/exemplary/banner.json | 166 ++++++++++++++
.../ownadx/ownadxtest/exemplary/video.json | 196 ++++++++++++++++
.../supplemental/bad-server-response.json | 108 +++++++++
.../ownadxtest/supplemental/bid-empty-.json | 118 ++++++++++
.../ownadxtest/supplemental/bidext-type.json | 141 ++++++++++++
.../supplemental/http-status-204.json | 51 +++++
.../supplemental/http-status-400.json | 57 +++++
.../supplemental/invalid-req-empty-imp.json | 34 +++
.../supplemental/invalid-req-imp-ext.json | 47 ++++
.../invalid-req-imp.ext.bidder.json | 49 ++++
.../supplemental/seatbid-empty-.json | 113 ++++++++++
.../supplemental/unexpected-status.json | 107 +++++++++
exchange/adapter_builders.go | 2 +
openrtb_ext/bidders.go | 2 +
openrtb_ext/imp_ownadx.go | 7 +
static/bidder-info/ownadx.yaml | 12 +
static/bidder-params/ownadx.json | 27 +++
19 files changed, 1467 insertions(+)
create mode 100644 adapters/ownadx/ownadx.go
create mode 100644 adapters/ownadx/ownadx_test.go
create mode 100644 adapters/ownadx/ownadxtest/exemplary/banner.json
create mode 100644 adapters/ownadx/ownadxtest/exemplary/video.json
create mode 100644 adapters/ownadx/ownadxtest/supplemental/bad-server-response.json
create mode 100644 adapters/ownadx/ownadxtest/supplemental/bid-empty-.json
create mode 100644 adapters/ownadx/ownadxtest/supplemental/bidext-type.json
create mode 100644 adapters/ownadx/ownadxtest/supplemental/http-status-204.json
create mode 100644 adapters/ownadx/ownadxtest/supplemental/http-status-400.json
create mode 100644 adapters/ownadx/ownadxtest/supplemental/invalid-req-empty-imp.json
create mode 100644 adapters/ownadx/ownadxtest/supplemental/invalid-req-imp-ext.json
create mode 100644 adapters/ownadx/ownadxtest/supplemental/invalid-req-imp.ext.bidder.json
create mode 100644 adapters/ownadx/ownadxtest/supplemental/seatbid-empty-.json
create mode 100644 adapters/ownadx/ownadxtest/supplemental/unexpected-status.json
create mode 100644 openrtb_ext/imp_ownadx.go
create mode 100644 static/bidder-info/ownadx.yaml
create mode 100644 static/bidder-params/ownadx.json
diff --git a/adapters/ownadx/ownadx.go b/adapters/ownadx/ownadx.go
new file mode 100644
index 00000000000..c19343ba47f
--- /dev/null
+++ b/adapters/ownadx/ownadx.go
@@ -0,0 +1,213 @@
+package ownadx
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/prebid/openrtb/v19/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"
+ "net/http"
+ "text/template"
+)
+
+type adapter struct {
+ endpoint *template.Template
+}
+type bidExt struct {
+ MediaType string `json:"mediaType"`
+}
+
+func (adapter *adapter) getRequestData(bidRequest *openrtb2.BidRequest, impExt *openrtb_ext.ExtImpOwnAdx, imps []openrtb2.Imp) (*adapters.RequestData, error) {
+ pbidRequest := createBidRequest(bidRequest, imps)
+ reqJSON, err := json.Marshal(pbidRequest)
+ if err != nil {
+ return nil, &errortypes.BadInput{
+ Message: "Prebid bidder request not valid or can't be marshalled. Err: " + err.Error(),
+ }
+ }
+ url, err := adapter.buildEndpointURL(impExt)
+ if err != nil {
+ return nil, &errortypes.BadInput{
+ Message: "Error while creating endpoint. Err: " + err.Error(),
+ }
+ }
+
+ headers := http.Header{}
+ headers.Add("Content-Type", "application/json;charset=utf-8")
+ headers.Add("Accept", "application/json")
+ headers.Add("x-openrtb-version", "2.5")
+
+ return &adapters.RequestData{
+ Method: "POST",
+ Uri: url,
+ Body: reqJSON,
+ Headers: headers}, nil
+
+}
+func createBidRequest(rtbBidRequest *openrtb2.BidRequest, imps []openrtb2.Imp) *openrtb2.BidRequest {
+ bidRequest := *rtbBidRequest
+ bidRequest.Imp = imps
+ return &bidRequest
+}
+func (adapter *adapter) buildEndpointURL(params *openrtb_ext.ExtImpOwnAdx) (string, error) {
+ endpointParams := macros.EndpointTemplateParams{
+ ZoneID: params.SspId,
+ AccountID: params.SeatId,
+ SourceId: params.TokenId,
+ }
+ return macros.ResolveMacros(adapter.endpoint, endpointParams)
+}
+
+func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpOwnAdx, error) {
+ var bidderExt adapters.ExtImpBidder
+ if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
+ return nil, &errortypes.BadInput{
+ Message: "Bidder extension not valid or can't be unmarshalled",
+ }
+ }
+
+ var ownAdxExt openrtb_ext.ExtImpOwnAdx
+ if err := json.Unmarshal(bidderExt.Bidder, &ownAdxExt); err != nil {
+ return nil, &errortypes.BadInput{
+ Message: "Error while unmarshaling bidder extension",
+ }
+ }
+
+ return &ownAdxExt, nil
+}
+
+func (adapter *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+
+ errs := make([]error, 0, len(request.Imp))
+ if len(request.Imp) == 0 {
+ errs = append(errs, &errortypes.BadInput{
+ Message: "No impression in the bid request"},
+ )
+ return nil, errs
+ }
+ extImps, errors := groupImpsByExt(request.Imp)
+ if len(errors) != 0 {
+ errs = append(errs, errors...)
+ }
+ if len(extImps) == 0 {
+ return nil, errs
+ }
+ reqDetail := make([]*adapters.RequestData, 0, len(extImps))
+ for k, imps := range extImps {
+ bidRequest, err := adapter.getRequestData(request, &k, imps)
+ if err != nil {
+ errs = append(errs, err)
+ } else {
+ reqDetail = append(reqDetail, bidRequest)
+ }
+ }
+ return reqDetail, errs
+}
+func groupImpsByExt(imps []openrtb2.Imp) (map[openrtb_ext.ExtImpOwnAdx][]openrtb2.Imp, []error) {
+ respExt := make(map[openrtb_ext.ExtImpOwnAdx][]openrtb2.Imp)
+ errors := make([]error, 0, len(imps))
+ for _, imp := range imps {
+ ownAdxExt, err := getImpressionExt(&(imp))
+ if err != nil {
+ errors = append(errors, err)
+ continue
+ }
+
+ respExt[*ownAdxExt] = append(respExt[*ownAdxExt], imp)
+ }
+ return respExt, errors
+}
+
+func (adapter *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+ if response.StatusCode == http.StatusNoContent {
+ return nil, nil
+ }
+ if response.StatusCode == http.StatusBadRequest {
+ return nil, []error{
+ &errortypes.BadServerResponse{
+ Message: fmt.Sprintf("Bad request: %d", response.StatusCode),
+ },
+ }
+ }
+ if response.StatusCode != http.StatusOK {
+ return nil, []error{
+ &errortypes.BadServerResponse{
+ Message: fmt.Sprintf("Unexpected status code: %d. Run with request.test = 1 for more info.", response.StatusCode),
+ },
+ }
+ }
+ var bidResp openrtb2.BidResponse
+ if err := json.Unmarshal(response.Body, &bidResp); err != nil {
+ return nil, []error{
+ &errortypes.BadServerResponse{
+ Message: fmt.Sprintf("Bad server response "),
+ },
+ }
+ }
+ if len(bidResp.SeatBid) == 0 {
+ return nil, []error{
+ &errortypes.BadServerResponse{
+ Message: fmt.Sprintf("Array SeatBid cannot be empty "),
+ },
+ }
+ }
+
+ seatBid := bidResp.SeatBid[0]
+ bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))
+ if len(seatBid.Bid) == 0 {
+ return nil, []error{
+ &errortypes.BadServerResponse{
+ Message: fmt.Sprintf("Bid cannot be empty "),
+ },
+ }
+ }
+ for i := 0; i < len(seatBid.Bid); i++ {
+ var bidType openrtb_ext.BidType
+ bid := seatBid.Bid[i]
+
+ bidType, err := getMediaType(bid)
+ if err != nil {
+ return nil, []error{&errortypes.BadServerResponse{
+ Message: "Bid type is invalid",
+ }}
+ }
+ bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+ Bid: &bid,
+ BidType: bidType,
+ })
+ }
+
+ return bidResponse, nil
+}
+
+// Builder builds a new instance of the OwnAdx adapter for the given bidder with the given config
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (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 getMediaType(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
+ switch bid.MType {
+ case openrtb2.MarkupBanner:
+ return openrtb_ext.BidTypeBanner, nil
+ case openrtb2.MarkupVideo:
+ return openrtb_ext.BidTypeVideo, nil
+ case openrtb2.MarkupAudio:
+ return openrtb_ext.BidTypeAudio, nil
+ case openrtb2.MarkupNative:
+ return openrtb_ext.BidTypeNative, nil
+ default:
+ return "", fmt.Errorf("invalid BidType: %d", bid.MType)
+ }
+}
diff --git a/adapters/ownadx/ownadx_test.go b/adapters/ownadx/ownadx_test.go
new file mode 100644
index 00000000000..9bd7ba70353
--- /dev/null
+++ b/adapters/ownadx/ownadx_test.go
@@ -0,0 +1,17 @@
+package ownadx
+
+import (
+ "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"
+ "testing"
+)
+
+func TestJsonSamples(t *testing.T) {
+ bidder, buildErr := Builder(openrtb_ext.BidderOwnAdx, config.Adapter{
+ Endpoint: "https://pbs.prebid-ownadx.com/bidder/bid/{{.AccountID}}/{{.ZoneID}}?token={{.SourceId}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
+
+ assert.NoError(t, buildErr)
+ adapterstest.RunJSONBidderTest(t, "ownadxtest", bidder)
+}
diff --git a/adapters/ownadx/ownadxtest/exemplary/banner.json b/adapters/ownadx/ownadxtest/exemplary/banner.json
new file mode 100644
index 00000000000..f77321c53b1
--- /dev/null
+++ b/adapters/ownadx/ownadxtest/exemplary/banner.json
@@ -0,0 +1,166 @@
+{
+ "mockBidRequest": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://pbs.prebid-ownadx.com/bidder/bid/2/11?token=126151698247",
+ "body": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ }
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "id",
+ "bidid": "id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "mtype": 1,
+ "id": "id",
+ "impid": "id",
+ "price": 0.1,
+ "nurl": "http://test.com/nurl",
+ "burl": "http://test.com/burl",
+ "adm": "Test",
+ "adomain": [
+ "test.com"
+ ],
+ "cat": [
+ "IAB1"
+ ],
+ "cid": "cid",
+ "crid": "crid",
+ "w": 300,
+ "h": 250,
+ "ext": {
+ "mediaType": "banner"
+ }
+ }
+ ],
+ "seat": "seat"
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "mtype": 1,
+ "id": "id",
+ "impid": "id",
+ "price": 0.1,
+ "nurl": "http://test.com/nurl",
+ "burl": "http://test.com/burl",
+ "adm": "Test",
+ "adomain": [
+ "test.com"
+ ],
+ "cat": [
+ "IAB1"
+ ],
+ "cid": "cid",
+ "crid": "crid",
+ "w": 300,
+ "h": 250,
+ "ext": {
+ "mediaType": "banner"
+ }
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/adapters/ownadx/ownadxtest/exemplary/video.json b/adapters/ownadx/ownadxtest/exemplary/video.json
new file mode 100644
index 00000000000..7cac425c7e3
--- /dev/null
+++ b/adapters/ownadx/ownadxtest/exemplary/video.json
@@ -0,0 +1,196 @@
+{
+ "mockBidRequest": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "video": {
+ "mimes": [
+ "video/mp4",
+ "video/ogg",
+ "video/webm"
+ ],
+ "minduration": 3,
+ "maxduration": 3000,
+ "protocols": [
+ 2,
+ 3,
+ 5,
+ 6,
+ 7,
+ 8
+ ],
+ "w": 480,
+ "h": 320,
+ "linearity": 1,
+ "playbackmethod": [
+ 2
+ ],
+ "pos": 0
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://pbs.prebid-ownadx.com/bidder/bid/2/11?token=126151698247",
+ "body": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "video": {
+ "mimes": [
+ "video/mp4",
+ "video/ogg",
+ "video/webm"
+ ],
+ "minduration": 3,
+ "maxduration": 3000,
+ "protocols": [
+ 2,
+ 3,
+ 5,
+ 6,
+ 7,
+ 8
+ ],
+ "w": 480,
+ "h": 320,
+ "linearity": 1,
+ "playbackmethod": [
+ 2
+ ],
+ "pos": 0
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ }
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "id",
+ "bidid": "id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "id",
+ "impid": "id",
+ "price": 0.1,
+ "nurl": "http://test.com/nurl",
+ "burl": "http://test.com/burl",
+ "adm": "",
+ "adomain": [
+ "test.com"
+ ],
+ "cat": [
+ "IAB1"
+ ],
+ "cid": "cid",
+ "crid": "crid",
+ "mtype": 2
+ }
+ ],
+ "seat": "seat"
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "id",
+ "impid": "id",
+ "price": 0.1,
+ "nurl": "http://test.com/nurl",
+ "burl": "http://test.com/burl",
+ "adm": "",
+ "adomain": [
+ "test.com"
+ ],
+ "cat": [
+ "IAB1"
+ ],
+ "cid": "cid",
+ "crid": "crid",
+ "mtype": 2
+ },
+ "type": "video"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/adapters/ownadx/ownadxtest/supplemental/bad-server-response.json b/adapters/ownadx/ownadxtest/supplemental/bad-server-response.json
new file mode 100644
index 00000000000..61b6da04fa8
--- /dev/null
+++ b/adapters/ownadx/ownadxtest/supplemental/bad-server-response.json
@@ -0,0 +1,108 @@
+{
+ "mockBidRequest": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://pbs.prebid-ownadx.com/bidder/bid/2/11?token=126151698247",
+ "body": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ }
+ },
+ "mockResponse": {
+ "status": 200
+
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Bad server response ",
+ "comparison": "literal"
+ }
+ ],
+ "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/ownadx/ownadxtest/supplemental/bid-empty-.json b/adapters/ownadx/ownadxtest/supplemental/bid-empty-.json
new file mode 100644
index 00000000000..8d40e878925
--- /dev/null
+++ b/adapters/ownadx/ownadxtest/supplemental/bid-empty-.json
@@ -0,0 +1,118 @@
+{
+ "mockBidRequest": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://pbs.prebid-ownadx.com/bidder/bid/2/11?token=126151698247",
+ "body": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ }
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "id",
+ "bidid": "id",
+ "seatbid": [
+ {
+ "seat": "seat"
+ }
+ ],
+ "cur": "USD"
+ }
+
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Bid cannot be empty ",
+ "comparison": "literal"
+ }
+ ],
+ "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/ownadx/ownadxtest/supplemental/bidext-type.json b/adapters/ownadx/ownadxtest/supplemental/bidext-type.json
new file mode 100644
index 00000000000..b1d634287d7
--- /dev/null
+++ b/adapters/ownadx/ownadxtest/supplemental/bidext-type.json
@@ -0,0 +1,141 @@
+{
+ "mockBidRequest": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://pbs.prebid-ownadx.com/bidder/bid/2/11?token=126151698247",
+ "body": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ }
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "id",
+ "bidid": "id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "id",
+ "impid": "id",
+ "price": 0.1,
+ "nurl": "http://test.com/nurl",
+ "burl": "http://test.com/burl",
+ "adm": "Test",
+ "adomain": [
+ "test.com"
+ ],
+ "cat": [
+ "IAB1"
+ ],
+ "cid": "cid",
+ "crid": "crid",
+ "w": 300,
+ "h": 250,
+ "ext": {
+
+ }
+ }
+ ],
+ "seat": "seat"
+ }
+ ],
+ "cur": "USD"
+ }
+
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Bid type is invalid",
+ "comparison": "literal"
+ }
+ ],
+ "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/ownadx/ownadxtest/supplemental/http-status-204.json b/adapters/ownadx/ownadxtest/supplemental/http-status-204.json
new file mode 100644
index 00000000000..4b7f8663f02
--- /dev/null
+++ b/adapters/ownadx/ownadxtest/supplemental/http-status-204.json
@@ -0,0 +1,51 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://pbs.prebid-ownadx.com/bidder/bid/2/11?token=126151698247",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ]
+ }
+ },
+ "mockResponse": {
+ "status": 204
+ }
+ }
+ ],
+ "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/ownadx/ownadxtest/supplemental/http-status-400.json b/adapters/ownadx/ownadxtest/supplemental/http-status-400.json
new file mode 100644
index 00000000000..035bc323e38
--- /dev/null
+++ b/adapters/ownadx/ownadxtest/supplemental/http-status-400.json
@@ -0,0 +1,57 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://pbs.prebid-ownadx.com/bidder/bid/2/11?token=126151698247",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ]
+ }
+ },
+ "mockResponse": {
+ "status": 400
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Bad request: 400",
+ "comparison": "literal"
+ }
+ ],
+ "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/ownadx/ownadxtest/supplemental/invalid-req-empty-imp.json b/adapters/ownadx/ownadxtest/supplemental/invalid-req-empty-imp.json
new file mode 100644
index 00000000000..0407ed6cfbf
--- /dev/null
+++ b/adapters/ownadx/ownadxtest/supplemental/invalid-req-empty-imp.json
@@ -0,0 +1,34 @@
+{
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "No impression in the bid request",
+ "comparison": "literal"
+ }
+ ],
+ "mockBidRequest": {
+ "id": "id",
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ },
+ "httpCalls": []
+}
diff --git a/adapters/ownadx/ownadxtest/supplemental/invalid-req-imp-ext.json b/adapters/ownadx/ownadxtest/supplemental/invalid-req-imp-ext.json
new file mode 100644
index 00000000000..9b8ba0d1820
--- /dev/null
+++ b/adapters/ownadx/ownadxtest/supplemental/invalid-req-imp-ext.json
@@ -0,0 +1,47 @@
+{
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "Bidder extension not valid or can't be unmarshalled",
+ "comparison": "literal"
+ }
+ ],
+ "mockBidRequest": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ }
+
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ },
+ "httpCalls": []
+}
diff --git a/adapters/ownadx/ownadxtest/supplemental/invalid-req-imp.ext.bidder.json b/adapters/ownadx/ownadxtest/supplemental/invalid-req-imp.ext.bidder.json
new file mode 100644
index 00000000000..b04e037d0a2
--- /dev/null
+++ b/adapters/ownadx/ownadxtest/supplemental/invalid-req-imp.ext.bidder.json
@@ -0,0 +1,49 @@
+{
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "Error while unmarshaling bidder extension",
+ "comparison": "literal"
+ }
+ ],
+ "mockBidRequest": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": []
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ },
+ "httpCalls": []
+}
diff --git a/adapters/ownadx/ownadxtest/supplemental/seatbid-empty-.json b/adapters/ownadx/ownadxtest/supplemental/seatbid-empty-.json
new file mode 100644
index 00000000000..f49ece3ea2f
--- /dev/null
+++ b/adapters/ownadx/ownadxtest/supplemental/seatbid-empty-.json
@@ -0,0 +1,113 @@
+{
+ "mockBidRequest": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://pbs.prebid-ownadx.com/bidder/bid/2/11?token=126151698247",
+ "body": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ }
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "id",
+ "bidid": "id",
+ "cur": "USD"
+ }
+
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Array SeatBid cannot be empty ",
+ "comparison": "literal"
+ }
+ ],
+ "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/ownadx/ownadxtest/supplemental/unexpected-status.json b/adapters/ownadx/ownadxtest/supplemental/unexpected-status.json
new file mode 100644
index 00000000000..f501a11064e
--- /dev/null
+++ b/adapters/ownadx/ownadxtest/supplemental/unexpected-status.json
@@ -0,0 +1,107 @@
+{
+ "mockBidRequest": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://pbs.prebid-ownadx.com/bidder/bid/2/11?token=126151698247",
+ "body": {
+ "id": "id",
+ "imp": [
+ {
+ "id": "id",
+ "secure": 1,
+ "bidfloor": 0.01,
+ "bidfloorcur": "USD",
+ "banner": {
+ "w": 300,
+ "h": 250
+ },
+ "ext": {
+ "bidder": {
+ "tokenId": "126151698247",
+ "sspId": "11",
+ "seatId": "2"
+ }
+ }
+ }
+ ],
+ "device": {
+ "ua": "UA",
+ "ip": "123.3.4.123"
+ },
+ "regs": {
+ "ext": {
+ "gdpr": 0
+ }
+ },
+ "user": {
+ "id": "userid"
+ },
+ "site": {
+ "id": "id",
+ "domain": "test,com",
+ "cat": [
+ "IAB12"
+ ],
+ "publisher": {
+ "id": "pubid"
+ }
+ }
+ }
+ },
+ "mockResponse": {
+ "status": 403
+ }
+ }
+ ],
+ "expectedMakeBidsErrors": [
+ {
+ "value": "Unexpected status code: 403. Run with request.test = 1 for more info.",
+ "comparison": "literal"
+ }
+ ],
+ "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 96d6aa64b0f..a1038d7152d 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -127,6 +127,7 @@ import (
"github.com/prebid/prebid-server/adapters/operaads"
"github.com/prebid/prebid-server/adapters/orbidder"
"github.com/prebid/prebid-server/adapters/outbrain"
+ "github.com/prebid/prebid-server/adapters/ownadx"
"github.com/prebid/prebid-server/adapters/pangle"
"github.com/prebid/prebid-server/adapters/pubmatic"
"github.com/prebid/prebid-server/adapters/pubnative"
@@ -320,6 +321,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
openrtb_ext.BidderOperaads: operaads.Builder,
openrtb_ext.BidderOrbidder: orbidder.Builder,
openrtb_ext.BidderOutbrain: outbrain.Builder,
+ openrtb_ext.BidderOwnAdx: ownadx.Builder,
openrtb_ext.BidderPangle: pangle.Builder,
openrtb_ext.BidderPGAM: adtelligent.Builder,
openrtb_ext.BidderPubmatic: pubmatic.Builder,
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 2398af8e62a..e9cc81f8c38 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -220,6 +220,7 @@ const (
BidderOperaads BidderName = "operaads"
BidderOrbidder BidderName = "orbidder"
BidderOutbrain BidderName = "outbrain"
+ BidderOwnAdx BidderName = "ownadx"
BidderPangle BidderName = "pangle"
BidderPGAM BidderName = "pgam"
BidderPubmatic BidderName = "pubmatic"
@@ -419,6 +420,7 @@ func CoreBidderNames() []BidderName {
BidderOperaads,
BidderOrbidder,
BidderOutbrain,
+ BidderOwnAdx,
BidderPangle,
BidderPGAM,
BidderPubmatic,
diff --git a/openrtb_ext/imp_ownadx.go b/openrtb_ext/imp_ownadx.go
new file mode 100644
index 00000000000..caac600b50e
--- /dev/null
+++ b/openrtb_ext/imp_ownadx.go
@@ -0,0 +1,7 @@
+package openrtb_ext
+
+type ExtImpOwnAdx struct {
+ SspId string `json:"sspId"`
+ SeatId string `json:"seatId"`
+ TokenId string `json:"tokenId"`
+}
diff --git a/static/bidder-info/ownadx.yaml b/static/bidder-info/ownadx.yaml
new file mode 100644
index 00000000000..37567db1144
--- /dev/null
+++ b/static/bidder-info/ownadx.yaml
@@ -0,0 +1,12 @@
+endpoint: "https://pbs.prebid-ownadx.com/bidder/bid/{{.AccountID}}/{{.ZoneID}}?token={{.SourceId}}"
+maintainer:
+ email: prebid-team@techbravo.com
+capabilities:
+ app:
+ mediaTypes:
+ - banner
+ - video
+ site:
+ mediaTypes:
+ - banner
+ - video
diff --git a/static/bidder-params/ownadx.json b/static/bidder-params/ownadx.json
new file mode 100644
index 00000000000..f529e74cb01
--- /dev/null
+++ b/static/bidder-params/ownadx.json
@@ -0,0 +1,27 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "OwnAdx Adapter Params",
+ "description": "A schema which validates params accepted by the OwnAdx adapter",
+ "type": "object",
+
+ "properties": {
+ "sspId": {
+ "type": "string",
+ "description": "Ssp ID"
+ },
+ "seatId": {
+ "type": "string",
+ "description": "Seat ID"
+ },
+ "tokenId": {
+ "type": "string",
+ "description": "Token ID"
+ }
+ },
+
+ "oneOf": [
+ { "required": ["sspId"] },
+ { "required": ["feedId"] },
+ { "required": ["token"] }
+ ]
+}