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