diff --git a/adapters/pixfuture/params_test.go b/adapters/pixfuture/params_test.go new file mode 100644 index 00000000000..b1f86b3741b --- /dev/null +++ b/adapters/pixfuture/params_test.go @@ -0,0 +1,71 @@ +package pixfuture + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json schema.") + + tests := []struct { + name string + json string + }{ + { + name: "Minimum length satisfied", + json: `{"pix_id": "123"}`, + }, + { + name: "Longer valid string", + json: `{"pix_id": "abcdef"}`, + }, + } + + for _, tt := range tests { + tt := tt // capture range variable + t.Run(tt.name, func(t *testing.T) { + assert.NoErrorf(t, validator.Validate(openrtb_ext.BidderPixfuture, json.RawMessage(tt.json)), "Schema rejected valid params: %s", tt.json) + }) + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + require.NoError(t, err, "Failed to fetch the json schema.") + + tests := []struct { + name string + json string + }{ + { + name: "Wrong type (integer)", + json: `{"pix_id": 123}`, + }, + { + name: "Too short (minLength: 3)", + json: `{"pix_id": "ab"}`, + }, + { + name: "Missing required pix_id", + json: `{}`, + }, + { + name: "Empty string (violates minLength)", + json: `{"pix_id": ""}`, + }, + } + + for _, tt := range tests { + tt := tt // capture range variable + t.Run(tt.name, func(t *testing.T) { + err := validator.Validate(openrtb_ext.BidderPixfuture, json.RawMessage(tt.json)) + assert.Errorf(t, err, "Schema allowed invalid params: %s", tt.json) + }) + } +} diff --git a/adapters/pixfuture/pixfuture.go b/adapters/pixfuture/pixfuture.go new file mode 100644 index 00000000000..7b3e694f463 --- /dev/null +++ b/adapters/pixfuture/pixfuture.go @@ -0,0 +1,175 @@ +// Package pixfuture implements the Pixfuture adapter for Prebid Server. +// It provides functionality to handle bid requests and responses according to Pixfuture's specifications +package pixfuture + +import ( + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/iterutil" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + return &adapter{ + endpoint: config.Endpoint, + }, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + + var errs []error + var adapterRequests []*adapters.RequestData + headers := http.Header{} + headers.Set("Content-Type", "application/json") + headers.Set("Accept", "application/json") + + for imp := range iterutil.SlicePointerValues(request.Imp) { + + var bidderExt adapters.ExtImpBidder + var pixfutureExt openrtb_ext.ImpExtPixfuture + + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + errs = append(errs, err) + continue + } + if err := jsonutil.Unmarshal(bidderExt.Bidder, &pixfutureExt); err != nil { + errs = append(errs, err) + continue + } + if pixfutureExt.PixID == "" { + errs = append(errs, &errortypes.BadInput{Message: "Missing required parameter pix_id"}) + continue + } + + requestCopy := *request + requestCopy.Imp = []openrtb2.Imp{*imp} // slice notation with dereferencing + + reqJSON, err := jsonutil.Marshal(requestCopy) + if err != nil { + errs = append(errs, err) + continue + } + + adapterRequests = append(adapterRequests, &adapters.RequestData{ + Method: http.MethodPost, + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: []string{imp.ID}, + }) + } + + if len(adapterRequests) == 0 && len(errs) > 0 { + return nil, errs + } + 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 bidResp openrtb2.BidResponse + // Step 1: Check if body is empty to avoid unnecessary unmarshal overhead + if len(response.Body) == 0 { + return nil, nil // Or return a specific error if Pixfuture always expects a body + } + + // Step 2: The Unmarshal call (Lines 88-92) + if err := jsonutil.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Invalid response format: %s", err.Error()), + }} + } + + // Pre-calculate total number of bids + expectedBids := 0 + for i := range bidResp.SeatBid { + expectedBids += len(bidResp.SeatBid[i].Bid) + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(expectedBids) + bidResponse.Currency = bidResp.Cur + + var errs []error + for i := range bidResp.SeatBid { + // Use index j to avoid copying the large openrtb2.Bid struct + for j := range bidResp.SeatBid[i].Bid { + bid := &bidResp.SeatBid[i].Bid[j] + + bidType, err := getMediaTypeForBid(bid) + if err != nil { + errs = append(errs, &errortypes.BadServerResponse{ + Message: "Failed to parse impression \"" + bid.ImpID + "\" mediatype", + }) + continue + } + + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: bid, + BidType: bidType, + }) + } + } + + if len(bidResponse.Bids) == 0 { + return nil, errs + } + + return bidResponse, errs +} + +func getMediaTypeForBid(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { + // First try standard MType field (OpenRTB 2.6) + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + } + + // Fallback to custom extension + var ext struct { + Prebid struct { + Type string `json:"type"` + } `json:"prebid"` + } + + if len(bid.Ext) > 0 { + if err := jsonutil.Unmarshal(bid.Ext, &ext); err != nil { + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Failed to parse bid ext for impression %s: %v", bid.ImpID, err), + } + } + } + + switch ext.Prebid.Type { + case "banner": + return openrtb_ext.BidTypeBanner, nil + case "video": + return openrtb_ext.BidTypeVideo, nil + case "native": + return openrtb_ext.BidTypeNative, nil + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unknown bid type for impression %s", bid.ImpID), + } + } +} diff --git a/adapters/pixfuture/pixfuture_test.go b/adapters/pixfuture/pixfuture_test.go new file mode 100644 index 00000000000..8c068b4d6c9 --- /dev/null +++ b/adapters/pixfuture/pixfuture_test.go @@ -0,0 +1,19 @@ +package pixfuture + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/stretchr/testify/require" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderPixfuture, config.Adapter{ + Endpoint: "http://any.url", + }, config.Server{}) + require.NoError(t, buildErr, "Builder returned unexpected error") + + adapterstest.RunJSONBidderTest(t, "pixfuturetest", bidder) +} diff --git a/adapters/pixfuture/pixfuturetest/exemplary/banner-site.json b/adapters/pixfuture/pixfuturetest/exemplary/banner-site.json new file mode 100644 index 00000000000..a1e8e1ae3ac --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/exemplary/banner-site.json @@ -0,0 +1,111 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "impIDs": [ + "imp1" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "
Banner Ad
", + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "
Banner Ad
", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ], + "currency": "USD" + } + ] +} \ No newline at end of file diff --git a/adapters/pixfuture/pixfuturetest/exemplary/native.json b/adapters/pixfuture/pixfuturetest/exemplary/native.json new file mode 100644 index 00000000000..405c3f6a607 --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/exemplary/native.json @@ -0,0 +1,93 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "native": { + "request": "{\"ver\":\"1.2\",\"context\":1,\"plcmttype\":1,\"assets\":[]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "native": { + "request": "{\"ver\":\"1.2\",\"context\":1,\"plcmttype\":1,\"assets\":[]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "{\"ver\":\"1.2\",\"native\":{\"assets\":[]}}", + "ext": { + "prebid": { + "type": "native" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "{\"ver\":\"1.2\",\"native\":{\"assets\":[]}}", + "ext": { + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ], + "currency": "USD" + } + ] +} \ No newline at end of file diff --git a/adapters/pixfuture/pixfuturetest/exemplary/video-app.json b/adapters/pixfuture/pixfuturetest/exemplary/video-app.json new file mode 100644 index 00000000000..981eb0b0c9a --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/exemplary/video-app.json @@ -0,0 +1,101 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "id": "app1" + }, + "imp": [ + { + "id": "imp1", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "app": { + "id": "app1" + }, + "imp": [ + { + "id": "imp1", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "", + "ext": { + "prebid": { + "type": "video" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "", + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ], + "currency": "USD" + } + ] +} \ No newline at end of file diff --git a/adapters/pixfuture/pixfuturetest/exemplary/video.json b/adapters/pixfuture/pixfuturetest/exemplary/video.json new file mode 100644 index 00000000000..78d57d0d4c8 --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/exemplary/video.json @@ -0,0 +1,95 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 360 + }, + "ext": { + "bidder": { + "pix_id": "55463" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "", + "ext": { + "prebid": { + "type": "video" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "", + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ], + "currency": "USD" + } + ] +} \ No newline at end of file diff --git a/adapters/pixfuture/pixfuturetest/supplemental/bad_status.json b/adapters/pixfuture/pixfuturetest/supplemental/bad_status.json new file mode 100644 index 00000000000..4cd7ffb3fdb --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/supplemental/bad_status.json @@ -0,0 +1,60 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 400, + "headers": {}, + "body": "Bad Request" + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/pixfuture/pixfuturetest/supplemental/no_bids.json b/adapters/pixfuture/pixfuturetest/supplemental/no_bids.json new file mode 100644 index 00000000000..5f2ccb6748d --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/supplemental/no_bids.json @@ -0,0 +1,54 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 204, + "headers": {}, + "body": "" + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/pixfuture/pixfuturetest/supplemental/status_204.json b/adapters/pixfuture/pixfuturetest/supplemental/status_204.json new file mode 100644 index 00000000000..5f2ccb6748d --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/supplemental/status_204.json @@ -0,0 +1,54 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 204, + "headers": {}, + "body": "" + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/pixfuture/pixfuturetest/supplemental/unknown_type.json b/adapters/pixfuture/pixfuturetest/supplemental/unknown_type.json new file mode 100644 index 00000000000..b6edf18ecf7 --- /dev/null +++ b/adapters/pixfuture/pixfuturetest/supplemental/unknown_type.json @@ -0,0 +1,83 @@ +{ + "description": "Tests an unknown bid type response", + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://any.url", + "headers": { + "Content-Type": ["application/json"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "imp1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "pix_id": "123" + } + } + } + ] + }, + "impIDs": ["imp1"] + }, + "mockResponse": { + "status": 200, + "headers": { + "Content-Type": ["application/json"] + }, + "body": { + "id": "test-response-id", + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid1", + "impid": "imp1", + "price": 1.23, + "adm": "
Ad
", + "ext": { + "prebid": { + "type": "unknown" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Failed to parse impression \"imp1\" mediatype", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 9a2aaa0bd21..4a14a04964f 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -182,6 +182,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/ownadx" "github.com/prebid/prebid-server/v3/adapters/pangle" "github.com/prebid/prebid-server/v3/adapters/pgamssp" + "github.com/prebid/prebid-server/v3/adapters/pixfuture" "github.com/prebid/prebid-server/v3/adapters/playdigo" "github.com/prebid/prebid-server/v3/adapters/pubmatic" "github.com/prebid/prebid-server/v3/adapters/pubnative" @@ -451,6 +452,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderOwnAdx: ownadx.Builder, openrtb_ext.BidderPangle: pangle.Builder, openrtb_ext.BidderPGAMSsp: pgamssp.Builder, + openrtb_ext.BidderPixfuture: pixfuture.Builder, openrtb_ext.BidderPlaydigo: playdigo.Builder, openrtb_ext.BidderPubmatic: pubmatic.Builder, openrtb_ext.BidderPubnative: pubnative.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 8cd543c1f16..c2185bb363a 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -200,6 +200,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderOwnAdx, BidderPangle, BidderPGAMSsp, + BidderPixfuture, BidderPlaydigo, BidderPubmatic, BidderPubrise, @@ -573,6 +574,7 @@ const ( BidderOwnAdx BidderName = "ownadx" BidderPangle BidderName = "pangle" BidderPGAMSsp BidderName = "pgamssp" + BidderPixfuture BidderName = "pixfuture" BidderPlaydigo BidderName = "playdigo" BidderPubmatic BidderName = "pubmatic" BidderPubrise BidderName = "pubrise" diff --git a/openrtb_ext/imp_pixfuture.go b/openrtb_ext/imp_pixfuture.go new file mode 100644 index 00000000000..be8bf36531f --- /dev/null +++ b/openrtb_ext/imp_pixfuture.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ImpExtPixfuture struct { + PixID string `json:"pix_id"` +} diff --git a/static/bidder-info/pixfuture.yaml b/static/bidder-info/pixfuture.yaml new file mode 100644 index 00000000000..1f1e78b6b8e --- /dev/null +++ b/static/bidder-info/pixfuture.yaml @@ -0,0 +1,19 @@ +endpoint: "https://pbs-pix.pixfuture.com/pixservices" +maintainer: + email: "client-support@pixfuture.com" +gvlVendorID: 839 +capabilities: + site: + mediaTypes: + - banner + - video + - native + app: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: "https://sync.pixfuture.com/cookiesync?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}" + userMacro: "${UID}" diff --git a/static/bidder-params/pixfuture.json b/static/bidder-params/pixfuture.json new file mode 100644 index 00000000000..19df80995df --- /dev/null +++ b/static/bidder-params/pixfuture.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "PixFuture Adapter Params", + "description": "A schema which validates params accepted by the PixFuture adapter", + "type": "object", + "properties": { + "pix_id": { + "type": "string", + "description": "PixFuture placement ID", + "minLength": 3 + } + }, + "required": [ + "pix_id" + ] +} \ No newline at end of file