From 18b45e047507f60b7858a313087fa6ef5f9edb7e Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Mon, 1 Dec 2025 17:34:21 +0200 Subject: [PATCH 01/14] fresh --- adapters/scalibur/params.go | 8 + adapters/scalibur/scalibur.go | 278 +++++++++++++++++++++++++++++ adapters/scalibur/scalibur_test.go | 264 +++++++++++++++++++++++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + static/bidder-info/scalibur.yaml | 33 ++++ static/bidder-params/scalibur.json | 22 +++ 7 files changed, 609 insertions(+) create mode 100644 adapters/scalibur/params.go create mode 100644 adapters/scalibur/scalibur.go create mode 100644 adapters/scalibur/scalibur_test.go create mode 100644 static/bidder-info/scalibur.yaml create mode 100644 static/bidder-params/scalibur.json diff --git a/adapters/scalibur/params.go b/adapters/scalibur/params.go new file mode 100644 index 00000000000..88adb76174d --- /dev/null +++ b/adapters/scalibur/params.go @@ -0,0 +1,8 @@ +package scalibur + +// ExtImpScalibur mirrors the bidder params from Prebid.js. +type ExtImpScalibur struct { + PlacementID string `json:"placementId"` // required + BidFloor *float64 `json:"bidfloor,omitempty"` // optional, used as fallback + BidFloorCur string `json:"bidfloorcur,omitempty"` // optional, defaults to USD if empty +} diff --git a/adapters/scalibur/scalibur.go b/adapters/scalibur/scalibur.go new file mode 100644 index 00000000000..81ed1c13dc9 --- /dev/null +++ b/adapters/scalibur/scalibur.go @@ -0,0 +1,278 @@ +package scalibur + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/adcom1" + "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" +) + +type adapter struct { + endpoint string +} + +// Builder builds a new instance of the Scalibur adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + return &adapter{ + endpoint: config.Endpoint, + }, nil +} + +// MakeRequests creates the HTTP requests which should be made to fetch bids from Scalibur. +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var errs []error + var validImps []openrtb2.Imp + + // Process each impression + for _, imp := range request.Imp { + scaliburExt, err := parseScaliburExt(imp.Ext) + if err != nil { + errs = append(errs, err) + continue + } + + impCopy := imp + + // Apply bid floor from params as fallback (matching JS logic) + if scaliburExt.BidFloor != nil && *scaliburExt.BidFloor > 0 { + if impCopy.BidFloor == 0 { + impCopy.BidFloor = *scaliburExt.BidFloor + } + } + + // Apply bid floor currency from params + if scaliburExt.BidFloorCur != "" && impCopy.BidFloorCur == "" { + impCopy.BidFloorCur = scaliburExt.BidFloorCur + } + if impCopy.BidFloorCur == "" { + impCopy.BidFloorCur = "USD" + } + + // Prepare imp.ext with placementId and params + impExtData := make(map[string]interface{}) + impExtData["placementId"] = scaliburExt.PlacementID + + if scaliburExt.BidFloor != nil { + impExtData["bidfloor"] = *scaliburExt.BidFloor + } + if scaliburExt.BidFloorCur != "" { + impExtData["bidfloorcur"] = scaliburExt.BidFloorCur + } + + // Preserve GPID if present + var rawExt map[string]json.RawMessage + if err := json.Unmarshal(imp.Ext, &rawExt); err == nil { + if gpid, ok := rawExt["gpid"]; ok { + impExtData["gpid"] = json.RawMessage(gpid) + } + } + + impExt, err := json.Marshal(impExtData) + if err != nil { + errs = append(errs, err) + continue + } + impCopy.Ext = impExt + + // Apply video defaults (matching JS defaults) + if impCopy.Video != nil { + videoCopy := *impCopy.Video + + // Note: In openrtb v20, field names are capitalized (MIMEs not Mimes) + if len(videoCopy.MIMEs) == 0 { + videoCopy.MIMEs = []string{"video/mp4"} + } + if videoCopy.MinDuration == 0 { + videoCopy.MinDuration = 1 + } + if videoCopy.MaxDuration == 0 { + videoCopy.MaxDuration = 180 + } + if videoCopy.MaxBitRate == 0 { + videoCopy.MaxBitRate = 30000 + } + if len(videoCopy.Protocols) == 0 { + // Use adcom1.MediaCreativeSubtype for protocols in v20 + videoCopy.Protocols = []adcom1.MediaCreativeSubtype{2, 3, 5, 6} + } + // Note: In openrtb v20, W and H are pointers + if videoCopy.W == nil || *videoCopy.W == 0 { + w := int64(640) + videoCopy.W = &w + } + if videoCopy.H == nil || *videoCopy.H == 0 { + h := int64(480) + videoCopy.H = &h + } + if videoCopy.Placement == 0 { + videoCopy.Placement = 1 + } + if videoCopy.Linearity == 0 { + videoCopy.Linearity = 1 + } + + impCopy.Video = &videoCopy + } + + validImps = append(validImps, impCopy) + } + + // If no valid impressions, return errors + if len(validImps) == 0 { + return nil, errs + } + + // Create the outgoing request + requestCopy := *request + requestCopy.Imp = validImps + requestCopy.Cur = nil + requestCopy.Ext = nil + + reqJSON, err := json.Marshal(requestCopy) + if err != nil { + return nil, append(errs, err) + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), + } + + return []*adapters.RequestData{requestData}, errs +} + +// MakeBids unpacks the server's response into bids. +func (a *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.StatusOK { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 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("Failed to unmarshal response: %s", err.Error()), + }} + } + + // Parse the external request to get impression details + var bidReq openrtb2.BidRequest + if err := json.Unmarshal(externalRequest.Body, &bidReq); err != nil { + return nil, []error{err} + } + + // Build impression map for lookup + impMap := make(map[string]*openrtb2.Imp, len(bidReq.Imp)) + for i := range bidReq.Imp { + impMap[bidReq.Imp[i].ID] = &bidReq.Imp[i] + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidReq.Imp)) + + // Set currency + if bidResp.Cur != "" { + bidResponse.Currency = bidResp.Cur + } else { + bidResponse.Currency = "USD" + } + + // Process each seat bid + for _, seatBid := range bidResp.SeatBid { + for _, bid := range seatBid.Bid { + // Find the corresponding imp + imp, found := impMap[bid.ImpID] + if !found { + continue + } + + // Determine bid type based on imp + bidType, err := getBidMediaType(imp) + if err != nil { + continue + } + + bidCopy := bid + + // Handle video VAST + if bidType == openrtb_ext.BidTypeVideo { + // Try to extract custom fields vastXml and vastUrl from bid response + var bidExtData map[string]interface{} + if bidBytes, err := json.Marshal(bid); err == nil { + if err := json.Unmarshal(bidBytes, &bidExtData); err == nil { + if vastXML, ok := bidExtData["vastXml"].(string); ok && vastXML != "" { + bidCopy.AdM = vastXML + } else if vastURL, ok := bidExtData["vastUrl"].(string); ok && vastURL != "" && bidCopy.AdM == "" { + // Wrap VAST URL in VAST wrapper + bidCopy.AdM = fmt.Sprintf(``, vastURL) + } + } + } + } + + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &bidCopy, + BidType: bidType, + }) + } + } + + if len(bidResponse.Bids) == 0 { + return nil, nil + } + + return bidResponse, nil +} + +// parseScaliburExt extracts Scalibur-specific parameters from the impression extension. +func parseScaliburExt(impExt json.RawMessage) (*ExtImpScalibur, error) { + var bidderExt adapters.ExtImpBidder + if err := json.Unmarshal(impExt, &bidderExt); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("Failed to parse imp.ext: %s", err.Error()), + } + } + + var scaliburExt ExtImpScalibur + if err := json.Unmarshal(bidderExt.Bidder, &scaliburExt); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("Failed to parse Scalibur params: %s", err.Error()), + } + } + + if scaliburExt.PlacementID == "" { + return nil, &errortypes.BadInput{ + Message: "placementId is required", + } + } + + return &scaliburExt, nil +} + +// getBidMediaType determines the media type based on the impression +func getBidMediaType(imp *openrtb2.Imp) (openrtb_ext.BidType, error) { + if imp.Banner != nil { + return openrtb_ext.BidTypeBanner, nil + } + if imp.Video != nil { + return openrtb_ext.BidTypeVideo, nil + } + return "", fmt.Errorf("unsupported media type for imp id=%s", imp.ID) +} diff --git a/adapters/scalibur/scalibur_test.go b/adapters/scalibur/scalibur_test.go new file mode 100644 index 00000000000..c235b8af431 --- /dev/null +++ b/adapters/scalibur/scalibur_test.go @@ -0,0 +1,264 @@ +package scalibur + +import ( + "encoding/json" + "net/http" + "testing" + + "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/openrtb_ext" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func newTestAdapter() adapters.Bidder { + adapter, _ := Builder( + openrtb_ext.BidderScalibur, + config.Adapter{Endpoint: "https://dev101.scalibur.io/adserver/ortb?type=prebid"}, + config.Server{}, + ) + return adapter +} + +// +// ------------------------------------------------------------------------------------------ +// MAKE REQUESTS TESTS +// ------------------------------------------------------------------------------------------ +// + +func TestMakeRequests_SuccessBanner(t *testing.T) { + bidder := newTestAdapter() + + ext, _ := json.Marshal(adapters.ExtImpBidder{ + Bidder: json.RawMessage(`{ + "placementId": "p123", + "bidfloor": 1.25, + "bidfloorcur": "EUR" + }`), + }) + + req := &openrtb2.BidRequest{ + ID: "req1", + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Ext: ext, + Banner: &openrtb2.Banner{ + W: ptrInt64(300), H: ptrInt64(250), + }, + }, + }, + Site: &openrtb2.Site{Page: "https://test.com"}, + } + + requests, errs := bidder.MakeRequests(req, &adapters.ExtraRequestInfo{}) + + require.Len(t, errs, 0) + require.Len(t, requests, 1) + + r := requests[0] + assert.Equal(t, "https://dev101.scalibur.io/adserver/ortb?type=prebid", r.Uri) + assert.Equal(t, "POST", r.Method) + assert.Contains(t, r.Headers.Get("Content-Type"), "application/json") + + // Ensure body contains rewritten ext fields + var out openrtb2.BidRequest + require.NoError(t, json.Unmarshal(r.Body, &out)) + require.Len(t, out.Imp, 1) + + imp := out.Imp[0] + + assert.Equal(t, float64(1.25), imp.BidFloor) + assert.Equal(t, "EUR", imp.BidFloorCur) + + var outExt map[string]interface{} + require.NoError(t, json.Unmarshal(imp.Ext, &outExt)) + assert.Equal(t, "p123", outExt["placementId"]) +} + +func TestMakeRequests_InvalidExt(t *testing.T) { + bidder := newTestAdapter() + + // Missing placementId + badExt, _ := json.Marshal(adapters.ExtImpBidder{ + Bidder: json.RawMessage(`{"bidfloor": 1.5}`), + }) + + req := &openrtb2.BidRequest{ + ID: "req2", + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Ext: badExt, + Banner: &openrtb2.Banner{ + W: ptrInt64(300), H: ptrInt64(250), + }, + }, + }, + } + + requests, errs := bidder.MakeRequests(req, &adapters.ExtraRequestInfo{}) + + require.Len(t, requests, 0) + require.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "placementId is required") +} + +func TestMakeRequests_VideoDefaultsApplied(t *testing.T) { + bidder := newTestAdapter() + + ext, _ := json.Marshal(adapters.ExtImpBidder{ + Bidder: json.RawMessage(`{"placementId": "p123"}`), + }) + + req := &openrtb2.BidRequest{ + ID: "req-video", + Imp: []openrtb2.Imp{ + { + ID: "v1", + Ext: ext, + Video: &openrtb2.Video{ + // Intentionally empty → should fill defaults + }, + }, + }, + } + + requests, errs := bidder.MakeRequests(req, &adapters.ExtraRequestInfo{}) + require.Len(t, errs, 0) + require.Len(t, requests, 1) + + var out openrtb2.BidRequest + require.NoError(t, json.Unmarshal(requests[0].Body, &out)) + + v := out.Imp[0].Video + require.NotNil(t, v) + + assert.NotEmpty(t, v.MIMEs) + assert.NotZero(t, v.MinDuration) + assert.NotZero(t, v.MaxDuration) + assert.NotZero(t, v.MaxBitRate) + assert.NotEmpty(t, v.Protocols) + assert.NotNil(t, v.W) + assert.NotNil(t, v.H) + assert.NotZero(t, v.Placement) + assert.NotZero(t, v.Linearity) +} + +// +// ------------------------------------------------------------------------------------------ +// MAKE BIDS TESTS +// ------------------------------------------------------------------------------------------ +// + +func TestMakeBids_SuccessBanner(t *testing.T) { + bidder := newTestAdapter() + + mockReq := &openrtb2.BidRequest{ + ID: "req1", + Imp: []openrtb2.Imp{ + { + ID: "1", + Banner: &openrtb2.Banner{W: ptrInt64(300), H: ptrInt64(250)}, + }, + }, + } + + mockReqData := &adapters.RequestData{ + Body: func() []byte { + b, _ := json.Marshal(mockReq) + return b + }(), + } + + mockResp := &openrtb2.BidResponse{ + ID: "resp1", + Cur: "USD", + SeatBid: []openrtb2.SeatBid{ + { + Bid: []openrtb2.Bid{ + { + ID: "b1", + ImpID: "1", + Price: 2.5, + AdM: "
ad markup
", + W: 300, + H: 250, + }, + }, + }, + }, + } + + respData := &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: func() []byte { + b, _ := json.Marshal(mockResp) + return b + }(), + } + + bidderResp, errs := bidder.MakeBids(mockReq, mockReqData, respData) + + require.Len(t, errs, 0) + require.NotNil(t, bidderResp) + require.Len(t, bidderResp.Bids, 1) + + b := bidderResp.Bids[0] + assert.Equal(t, openrtb_ext.BidTypeBanner, b.BidType) + assert.Equal(t, float64(2.5), b.Bid.Price) + assert.Equal(t, "
ad markup
", b.Bid.AdM) +} + +func TestMakeBids_EmptySeatBid(t *testing.T) { + bidder := newTestAdapter() + + mockReq := &openrtb2.BidRequest{ + ID: "req2", + Imp: []openrtb2.Imp{}, + } + + mockReqData := &adapters.RequestData{ + Body: []byte(`{"id":"req2","imp":[]}`), + } + + respData := &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"id":"resp","seatbid":[]}`), + } + + bidderResp, errs := bidder.MakeBids(mockReq, mockReqData, respData) + + require.Len(t, errs, 0) + assert.Nil(t, bidderResp) +} + +func TestMakeBids_Status204(t *testing.T) { + bidder := newTestAdapter() + + respData := &adapters.ResponseData{ + StatusCode: http.StatusNoContent, + } + + resp, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, respData) + + assert.Nil(t, resp) + assert.Nil(t, errs) +} + +func TestMakeBids_InvalidJSON(t *testing.T) { + bidder := newTestAdapter() + + respData := &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`not-json`), + } + + _, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, respData) + require.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "Failed to unmarshal") +} + +func ptrInt64(x int64) *int64 { return &x } diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index e6bba140a57..0cf2ba3cd2c 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -204,6 +204,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/rtbhouse" "github.com/prebid/prebid-server/v3/adapters/rubicon" salunamedia "github.com/prebid/prebid-server/v3/adapters/sa_lunamedia" + "github.com/prebid/prebid-server/v3/adapters/scalibur" "github.com/prebid/prebid-server/v3/adapters/screencore" "github.com/prebid/prebid-server/v3/adapters/seedingAlliance" "github.com/prebid/prebid-server/v3/adapters/seedtag" @@ -479,6 +480,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderSeedingAlliance: seedingAlliance.Builder, openrtb_ext.BidderSeedtag: seedtag.Builder, openrtb_ext.BidderSaLunaMedia: salunamedia.Builder, + openrtb_ext.BidderScalibur: scalibur.Builder, openrtb_ext.BidderScreencore: screencore.Builder, openrtb_ext.BidderSharethrough: sharethrough.Builder, openrtb_ext.BidderShowheroes: showheroes.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 82a6df4f77c..90ced984f56 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -224,6 +224,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderSeedingAlliance, BidderSeedtag, BidderSaLunaMedia, + BidderScalibur, BidderScreencore, BidderSharethrough, BidderShowheroes, @@ -601,6 +602,7 @@ const ( BidderSeedingAlliance BidderName = "seedingAlliance" BidderSeedtag BidderName = "seedtag" BidderSaLunaMedia BidderName = "sa_lunamedia" + BidderScalibur BidderName = "scalibur" BidderScreencore BidderName = "screencore" BidderSharethrough BidderName = "sharethrough" BidderShowheroes BidderName = "showheroes" diff --git a/static/bidder-info/scalibur.yaml b/static/bidder-info/scalibur.yaml new file mode 100644 index 00000000000..fc6fc003459 --- /dev/null +++ b/static/bidder-info/scalibur.yaml @@ -0,0 +1,33 @@ +endpoint: "https://srv.scalibur.io/adserver/ortb?type=prebid" +endpointCompression: GZIP + +# Leave disabled: false → adapter enabled +disabled: false + +maintainer: + email: "you@example.com" + +gvlVendorID: 1471 + +openrtb: + version: 2.6 + gpp-supported: true + +capabilities: + site: + mediaTypes: + - banner + - video + app: + mediaTypes: + - banner + - video + +userSync: + iframe: + url: "https://srv.scalibur.io/adserver/sync?type=iframe" + pixel: + url: "https://srv.scalibur.io/adserver/sync?type=pixel" + supports: + - iframe + - pixel diff --git a/static/bidder-params/scalibur.json b/static/bidder-params/scalibur.json new file mode 100644 index 00000000000..05a12e99f24 --- /dev/null +++ b/static/bidder-params/scalibur.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Scalibur Adapter Params", + "description": "A valid BidderParams object for the Scalibur adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "minLength": 1 + }, + "bidfloor": { + "type": "number", + "minimum": 0 + }, + "bidfloorcur": { + "type": "string" + } + }, + "required": [ + "placementId" + ] +} From 9806d5d2ff19025e99cf1a48e181b18793f90136 Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Sun, 21 Dec 2025 14:51:33 +0200 Subject: [PATCH 02/14] fix ortb and sync server support --- adapters/scalibur/scalibur.go | 18 +++++++++++++++--- static/bidder-info/scalibur.yaml | 15 +++++++-------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/adapters/scalibur/scalibur.go b/adapters/scalibur/scalibur.go index 81ed1c13dc9..6e1d5ed3d88 100644 --- a/adapters/scalibur/scalibur.go +++ b/adapters/scalibur/scalibur.go @@ -1,9 +1,11 @@ package scalibur import ( + "bytes" "encoding/json" "fmt" "net/http" + "text/template" "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" @@ -14,13 +16,18 @@ import ( ) type adapter struct { - endpoint string + endpoint *template.Template } // Builder builds a new instance of the Scalibur adapter for the given bidder with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + temp, err := template.New("endpointTemplate").Parse(config.Endpoint) + if err != nil { + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) + } + return &adapter{ - endpoint: config.Endpoint, + endpoint: temp, }, nil } @@ -139,13 +146,18 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E return nil, append(errs, err) } + var endpointBuffer bytes.Buffer + if err := a.endpoint.Execute(&endpointBuffer, nil); err != nil { + return nil, []error{err} + } + headers := http.Header{} headers.Add("Content-Type", "application/json;charset=utf-8") headers.Add("Accept", "application/json") requestData := &adapters.RequestData{ Method: "POST", - Uri: a.endpoint, + Uri: endpointBuffer.String(), Body: reqJSON, Headers: headers, ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), diff --git a/static/bidder-info/scalibur.yaml b/static/bidder-info/scalibur.yaml index fc6fc003459..e2610bf8071 100644 --- a/static/bidder-info/scalibur.yaml +++ b/static/bidder-info/scalibur.yaml @@ -1,11 +1,13 @@ -endpoint: "https://srv.scalibur.io/adserver/ortb?type=prebid" -endpointCompression: GZIP +endpoint: "https://srv.scalibur.io/adserver/ortb?type=prebid-server" # Leave disabled: false → adapter enabled disabled: false maintainer: - email: "you@example.com" + email: "support@scalibur.io" +supported-media-types: + - banner + - video gvlVendorID: 1471 @@ -25,9 +27,6 @@ capabilities: userSync: iframe: - url: "https://srv.scalibur.io/adserver/sync?type=iframe" - pixel: - url: "https://srv.scalibur.io/adserver/sync?type=pixel" + url: "https://srv.scalibur.io/adserver/sync?pbs=1&type=iframe&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}" supports: - - iframe - - pixel + - iframe \ No newline at end of file From e20d4e973ee1daef309c7de036397923979b9a2c Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Sun, 21 Dec 2025 15:24:23 +0200 Subject: [PATCH 03/14] finish scalibur prebid adapter --- adapters/scalibur/scalibur.go | 4 +- adapters/scalibur/scalibur_test.go | 13 +++-- .../scalibur/scaliburtest/success_banner.json | 54 +++++++++++++++++++ adapters/scalibur/scaliburtest/video.json | 52 ++++++++++++++++++ .../scalibur/scaliburtest/video_vast_url.json | 41 ++++++++++++++ .../params.go => openrtb_ext/imp_scalibur.go | 3 +- 6 files changed, 159 insertions(+), 8 deletions(-) create mode 100644 adapters/scalibur/scaliburtest/success_banner.json create mode 100644 adapters/scalibur/scaliburtest/video.json create mode 100644 adapters/scalibur/scaliburtest/video_vast_url.json rename adapters/scalibur/params.go => openrtb_ext/imp_scalibur.go (77%) diff --git a/adapters/scalibur/scalibur.go b/adapters/scalibur/scalibur.go index 6e1d5ed3d88..a00ca7015c5 100644 --- a/adapters/scalibur/scalibur.go +++ b/adapters/scalibur/scalibur.go @@ -254,7 +254,7 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest } // parseScaliburExt extracts Scalibur-specific parameters from the impression extension. -func parseScaliburExt(impExt json.RawMessage) (*ExtImpScalibur, error) { +func parseScaliburExt(impExt json.RawMessage) (*openrtb_ext.ExtImpScalibur, error) { var bidderExt adapters.ExtImpBidder if err := json.Unmarshal(impExt, &bidderExt); err != nil { return nil, &errortypes.BadInput{ @@ -262,7 +262,7 @@ func parseScaliburExt(impExt json.RawMessage) (*ExtImpScalibur, error) { } } - var scaliburExt ExtImpScalibur + var scaliburExt openrtb_ext.ExtImpScalibur if err := json.Unmarshal(bidderExt.Bidder, &scaliburExt); err != nil { return nil, &errortypes.BadInput{ Message: fmt.Sprintf("Failed to parse Scalibur params: %s", err.Error()), diff --git a/adapters/scalibur/scalibur_test.go b/adapters/scalibur/scalibur_test.go index c235b8af431..84c019f545e 100644 --- a/adapters/scalibur/scalibur_test.go +++ b/adapters/scalibur/scalibur_test.go @@ -7,6 +7,7 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/adapters" + "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/assert" @@ -16,7 +17,7 @@ import ( func newTestAdapter() adapters.Bidder { adapter, _ := Builder( openrtb_ext.BidderScalibur, - config.Adapter{Endpoint: "https://dev101.scalibur.io/adserver/ortb?type=prebid"}, + config.Adapter{Endpoint: "https://srv.scalibur.io/adserver/ortb?type=prebid"}, config.Server{}, ) return adapter @@ -28,6 +29,10 @@ func newTestAdapter() adapters.Bidder { // ------------------------------------------------------------------------------------------ // +func TestJsonSamples(t *testing.T) { + adapterstest.RunJSONBidderTest(t, "scaliburtest", newTestAdapter()) +} + func TestMakeRequests_SuccessBanner(t *testing.T) { bidder := newTestAdapter() @@ -59,7 +64,7 @@ func TestMakeRequests_SuccessBanner(t *testing.T) { require.Len(t, requests, 1) r := requests[0] - assert.Equal(t, "https://dev101.scalibur.io/adserver/ortb?type=prebid", r.Uri) + assert.Equal(t, "https://srv.scalibur.io/adserver/ortb?type=prebid", r.Uri) assert.Equal(t, "POST", r.Method) assert.Contains(t, r.Headers.Get("Content-Type"), "application/json") @@ -117,8 +122,8 @@ func TestMakeRequests_VideoDefaultsApplied(t *testing.T) { ID: "req-video", Imp: []openrtb2.Imp{ { - ID: "v1", - Ext: ext, + ID: "v1", + Ext: ext, Video: &openrtb2.Video{ // Intentionally empty → should fill defaults }, diff --git a/adapters/scalibur/scaliburtest/success_banner.json b/adapters/scalibur/scaliburtest/success_banner.json new file mode 100644 index 00000000000..fa80ebb6b9c --- /dev/null +++ b/adapters/scalibur/scaliburtest/success_banner.json @@ -0,0 +1,54 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { "bidder": { "placementId": "test-scl-placement" } } + }] + }, + "httpCalls": [{ + "expectedUri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "expectedRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { "placementId": "test-scl-placement" } + }] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "...", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }] + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "...", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/scalibur/scaliburtest/video.json b/adapters/scalibur/scaliburtest/video.json new file mode 100644 index 00000000000..e78cab6bbcb --- /dev/null +++ b/adapters/scalibur/scaliburtest/video.json @@ -0,0 +1,52 @@ +{ + "mockBidRequest": { + "id": "test-video-req", + "imp": [{ + "id": "video-imp-1", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "placementId": "46" + } + } + }] + }, + "httpCalls": [{ + "expectedUri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "mockResponse": { + "status": 200, + "body": { + "id": "test-video-req", + "seatbid": [{ + "bid": [{ + "id": "bid-v1", + "impid": "video-imp-1", + "price": 1.5, + "crid": "cr-video", + "ext": { + "vastXml": "..." + } + }] + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "bid-v1", + "impid": "video-imp-1", + "price": 1.5, + "adm": "...", + "crid": "cr-video" + }, + "type": "video" + }] + }] +} \ No newline at end of file diff --git a/adapters/scalibur/scaliburtest/video_vast_url.json b/adapters/scalibur/scaliburtest/video_vast_url.json new file mode 100644 index 00000000000..38498ddd058 --- /dev/null +++ b/adapters/scalibur/scaliburtest/video_vast_url.json @@ -0,0 +1,41 @@ +{ + "mockBidRequest": { + "id": "test-video-url-req", + "imp": [{ + "id": "video-imp-2", + "video": { "mimes": ["video/mp4"] }, + "ext": { "bidder": { "placementId": "46" } } + }] + }, + "httpCalls": [{ + "expectedUri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "mockResponse": { + "status": 200, + "body": { + "id": "test-video-url-req", + "seatbid": [{ + "bid": [{ + "id": "bid-v2", + "impid": "video-imp-2", + "price": 2.0, + "ext": { + "vastUrl": "https://cdn.scalibur.io/vast.xml" + } + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "bid-v2", + "impid": "video-imp-2", + "price": 2.0, + "adm": "" + }, + "type": "video" + }] + }] +} \ No newline at end of file diff --git a/adapters/scalibur/params.go b/openrtb_ext/imp_scalibur.go similarity index 77% rename from adapters/scalibur/params.go rename to openrtb_ext/imp_scalibur.go index 88adb76174d..a29eb25d16c 100644 --- a/adapters/scalibur/params.go +++ b/openrtb_ext/imp_scalibur.go @@ -1,6 +1,5 @@ -package scalibur +package openrtb_ext -// ExtImpScalibur mirrors the bidder params from Prebid.js. type ExtImpScalibur struct { PlacementID string `json:"placementId"` // required BidFloor *float64 `json:"bidfloor,omitempty"` // optional, used as fallback From a87ab0940cf388f644ea868b39b891e8ca7f3643 Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Sun, 21 Dec 2025 16:14:25 +0200 Subject: [PATCH 04/14] Add Scalibur bid adapter with Banner, Video, and User Sync support --- docs/bidders/scalibur.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/bidders/scalibur.md diff --git a/docs/bidders/scalibur.md b/docs/bidders/scalibur.md new file mode 100644 index 00000000000..e69de29bb2d From c4e722065fcdfda920a1751e4f9b1682cd13fb0c Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Mon, 22 Dec 2025 11:35:32 +0200 Subject: [PATCH 05/14] add ext debug --- adapters/scalibur/scalibur.go | 18 +++++++++++++++++- docs/bidders/scalibur.md | 16 ++++++++++++++++ openrtb_ext/imp_scalibur.go | 4 ++++ static/bidder-info/scalibur.yaml | 2 +- 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/adapters/scalibur/scalibur.go b/adapters/scalibur/scalibur.go index a00ca7015c5..21ed0f00f75 100644 --- a/adapters/scalibur/scalibur.go +++ b/adapters/scalibur/scalibur.go @@ -139,7 +139,23 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E requestCopy := *request requestCopy.Imp = validImps requestCopy.Cur = nil - requestCopy.Ext = nil + + isDebug := request.Test == 1 + if !isDebug && len(request.Ext) > 0 { + var extRequest openrtb_ext.ExtRequest + if err := json.Unmarshal(request.Ext, &extRequest); err == nil { + isDebug = extRequest.Prebid.Debug + } + } + + if isDebug { + reqExt := openrtb_ext.ExtRequestScalibur{IsDebug: 1} + if reqExtJSON, err := json.Marshal(reqExt); err == nil { + requestCopy.Ext = reqExtJSON + } + } else { + requestCopy.Ext = nil + } reqJSON, err := json.Marshal(requestCopy) if err != nil { diff --git a/docs/bidders/scalibur.md b/docs/bidders/scalibur.md index e69de29bb2d..95f409b997d 100644 --- a/docs/bidders/scalibur.md +++ b/docs/bidders/scalibur.md @@ -0,0 +1,16 @@ +# Scalibur + +The Scalibur adapter supports Banner and Video media types via OpenRTB 2.6. + +## Registration +Contact [support@scalibur.io](mailto:support@scalibur.io) to obtain a valid `placementId`. + +## Bid Params +| Name | Type | Description | Notes | +| :--- | :--- | :--- |:----------------------| +| `placementId` | string | **Required**. Scalibur placement identifier. | Example: `"468acd11"` | +| `bidfloor` | number | Optional. Minimum bid floor price. | | +| `bidfloorcur` | string | Optional. Currency for the bid floor. | Default is `USD`. | + +## User Sync +Supports iframe synchronization. Prebid Server handles the mapping of the sync ID to the `user.buyeruid` field in outgoing OpenRTB requests. \ No newline at end of file diff --git a/openrtb_ext/imp_scalibur.go b/openrtb_ext/imp_scalibur.go index a29eb25d16c..9a0ff7902f5 100644 --- a/openrtb_ext/imp_scalibur.go +++ b/openrtb_ext/imp_scalibur.go @@ -5,3 +5,7 @@ type ExtImpScalibur struct { BidFloor *float64 `json:"bidfloor,omitempty"` // optional, used as fallback BidFloorCur string `json:"bidfloorcur,omitempty"` // optional, defaults to USD if empty } + +type ExtRequestScalibur struct { + IsDebug int `json:"isDebug,omitempty"` +} diff --git a/static/bidder-info/scalibur.yaml b/static/bidder-info/scalibur.yaml index e2610bf8071..46a0590845a 100644 --- a/static/bidder-info/scalibur.yaml +++ b/static/bidder-info/scalibur.yaml @@ -27,6 +27,6 @@ capabilities: userSync: iframe: - url: "https://srv.scalibur.io/adserver/sync?pbs=1&type=iframe&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}" + url: "https://srv.scalibur.io/adserver/sync?type=iframe&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}[PBS_UID]" supports: - iframe \ No newline at end of file From 088c8072a3ca1b63c3a4d6c5ceb572d82f66b140 Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Mon, 22 Dec 2025 13:41:11 +0200 Subject: [PATCH 06/14] add gzip compression support --- static/bidder-info/scalibur.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/static/bidder-info/scalibur.yaml b/static/bidder-info/scalibur.yaml index 46a0590845a..1b945799a73 100644 --- a/static/bidder-info/scalibur.yaml +++ b/static/bidder-info/scalibur.yaml @@ -1,6 +1,7 @@ endpoint: "https://srv.scalibur.io/adserver/ortb?type=prebid-server" # Leave disabled: false → adapter enabled +compression: gzip disabled: false maintainer: From 60a0c74af9299b5be10caa79362993b96e9792ad Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Mon, 22 Dec 2025 14:29:57 +0200 Subject: [PATCH 07/14] resolve multi type response --- adapters/scalibur/scalibur.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/adapters/scalibur/scalibur.go b/adapters/scalibur/scalibur.go index 21ed0f00f75..ada02e7c88b 100644 --- a/adapters/scalibur/scalibur.go +++ b/adapters/scalibur/scalibur.go @@ -232,7 +232,7 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest } // Determine bid type based on imp - bidType, err := getBidMediaType(imp) + bidType, err := getBidMediaType(bid, imp) if err != nil { continue } @@ -295,12 +295,22 @@ func parseScaliburExt(impExt json.RawMessage) (*openrtb_ext.ExtImpScalibur, erro } // getBidMediaType determines the media type based on the impression -func getBidMediaType(imp *openrtb2.Imp) (openrtb_ext.BidType, error) { - if imp.Banner != nil { +func getBidMediaType(bid openrtb2.Bid, imp *openrtb2.Imp) (openrtb_ext.BidType, error) { + // 1 = Banner, 2 = Video, 3 = Audio, 4 = Native + switch bid.MType { + case 1: return openrtb_ext.BidTypeBanner, nil + case 2: + return openrtb_ext.BidTypeVideo, nil } - if imp.Video != nil { + + // Fallback for bidders not supporting mtype (non-multi-format requests) + if imp.Banner != nil && imp.Video == nil { + return openrtb_ext.BidTypeBanner, nil + } + if imp.Video != nil && imp.Banner == nil { return openrtb_ext.BidTypeVideo, nil } - return "", fmt.Errorf("unsupported media type for imp id=%s", imp.ID) + + return "", fmt.Errorf("unsupported or ambiguous media type for bid id=%s", bid.ID) } From 8ae7336b05def94d01511ae588fb959e800e15df Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Mon, 12 Jan 2026 11:09:20 +0200 Subject: [PATCH 08/14] address PR review feedback and fix bidder implementation --- adapters/scalibur/params_test.go | 51 +++++++++++ adapters/scalibur/scalibur.go | 84 +++++++++++-------- adapters/scalibur/scalibur_test.go | 30 +++++-- .../{ => exemplary}/success_banner.json | 21 +++-- .../scaliburtest/{ => exemplary}/video.json | 30 ++++++- .../{ => exemplary}/video_vast_url.json | 30 ++++++- static/bidder-info/scalibur.yaml | 3 +- 7 files changed, 194 insertions(+), 55 deletions(-) create mode 100644 adapters/scalibur/params_test.go rename adapters/scalibur/scaliburtest/{ => exemplary}/success_banner.json (70%) rename adapters/scalibur/scaliburtest/{ => exemplary}/video.json (55%) rename adapters/scalibur/scaliburtest/{ => exemplary}/video_vast_url.json (54%) diff --git a/adapters/scalibur/params_test.go b/adapters/scalibur/params_test.go new file mode 100644 index 00000000000..e03d549f366 --- /dev/null +++ b/adapters/scalibur/params_test.go @@ -0,0 +1,51 @@ +package scalibur + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, validParam := range validParams { + if err := validator.Validate(openrtb_ext.BidderScalibur, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected scalibur params: %s", validParam) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, invalidParam := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderScalibur, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"placementId":"p123"}`, + `{"placementId":"p123", "bidfloor": 1.5}`, + `{"placementId":"p123", "bidfloor": 1.5, "bidfloorcur": "USD"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `[]`, + `{}`, + `{"placementId": 123}`, + `{"bidfloor": 1.5}`, +} diff --git a/adapters/scalibur/scalibur.go b/adapters/scalibur/scalibur.go index ada02e7c88b..5ed40168ff7 100644 --- a/adapters/scalibur/scalibur.go +++ b/adapters/scalibur/scalibur.go @@ -13,6 +13,7 @@ import ( "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/jsonutil" ) type adapter struct { @@ -21,7 +22,11 @@ type adapter struct { // Builder builds a new instance of the Scalibur adapter for the given bidder with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { - temp, err := template.New("endpointTemplate").Parse(config.Endpoint) + endpoint := config.Endpoint + if endpoint == "" { + endpoint = "https://srv.scalibur.io/adserver/ortb?type=prebid-server" + } + temp, err := template.New("endpointTemplate").Parse(endpoint) if err != nil { return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) } @@ -46,17 +51,24 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E impCopy := imp - // Apply bid floor from params as fallback (matching JS logic) + // Apply bid floor and currency if scaliburExt.BidFloor != nil && *scaliburExt.BidFloor > 0 { - if impCopy.BidFloor == 0 { - impCopy.BidFloor = *scaliburExt.BidFloor + impCopy.BidFloor = *scaliburExt.BidFloor + if scaliburExt.BidFloorCur != "" { + impCopy.BidFloorCur = scaliburExt.BidFloorCur } } - // Apply bid floor currency from params - if scaliburExt.BidFloorCur != "" && impCopy.BidFloorCur == "" { - impCopy.BidFloorCur = scaliburExt.BidFloorCur + if impCopy.BidFloor > 0 && impCopy.BidFloorCur != "" && impCopy.BidFloorCur != "USD" { + convertedValue, err := reqInfo.ConvertCurrency(impCopy.BidFloor, impCopy.BidFloorCur, "USD") + if err != nil { + errs = append(errs, err) + continue + } + impCopy.BidFloor = convertedValue + impCopy.BidFloorCur = "USD" } + if impCopy.BidFloorCur == "" { impCopy.BidFloorCur = "USD" } @@ -65,22 +77,20 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E impExtData := make(map[string]interface{}) impExtData["placementId"] = scaliburExt.PlacementID - if scaliburExt.BidFloor != nil { - impExtData["bidfloor"] = *scaliburExt.BidFloor - } - if scaliburExt.BidFloorCur != "" { - impExtData["bidfloorcur"] = scaliburExt.BidFloorCur + if impCopy.BidFloor > 0 { + impExtData["bidfloor"] = impCopy.BidFloor } + impExtData["bidfloorcur"] = impCopy.BidFloorCur // Preserve GPID if present var rawExt map[string]json.RawMessage - if err := json.Unmarshal(imp.Ext, &rawExt); err == nil { + if err := jsonutil.Unmarshal(imp.Ext, &rawExt); err == nil { if gpid, ok := rawExt["gpid"]; ok { impExtData["gpid"] = json.RawMessage(gpid) } } - impExt, err := json.Marshal(impExtData) + impExt, err := jsonutil.Marshal(impExtData) if err != nil { errs = append(errs, err) continue @@ -143,21 +153,21 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E isDebug := request.Test == 1 if !isDebug && len(request.Ext) > 0 { var extRequest openrtb_ext.ExtRequest - if err := json.Unmarshal(request.Ext, &extRequest); err == nil { + if err := jsonutil.Unmarshal(request.Ext, &extRequest); err == nil { isDebug = extRequest.Prebid.Debug } } if isDebug { reqExt := openrtb_ext.ExtRequestScalibur{IsDebug: 1} - if reqExtJSON, err := json.Marshal(reqExt); err == nil { + if reqExtJSON, err := jsonutil.Marshal(reqExt); err == nil { requestCopy.Ext = reqExtJSON } } else { requestCopy.Ext = nil } - reqJSON, err := json.Marshal(requestCopy) + reqJSON, err := jsonutil.Marshal(requestCopy) if err != nil { return nil, append(errs, err) } @@ -195,15 +205,13 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest } var bidResp openrtb2.BidResponse - if err := json.Unmarshal(response.Body, &bidResp); err != nil { - return nil, []error{&errortypes.BadServerResponse{ - Message: fmt.Sprintf("Failed to unmarshal response: %s", err.Error()), - }} + if err := jsonutil.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{err} } // Parse the external request to get impression details var bidReq openrtb2.BidRequest - if err := json.Unmarshal(externalRequest.Body, &bidReq); err != nil { + if err := jsonutil.Unmarshal(externalRequest.Body, &bidReq); err != nil { return nil, []error{err} } @@ -241,15 +249,18 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest // Handle video VAST if bidType == openrtb_ext.BidTypeVideo { - // Try to extract custom fields vastXml and vastUrl from bid response - var bidExtData map[string]interface{} - if bidBytes, err := json.Marshal(bid); err == nil { - if err := json.Unmarshal(bidBytes, &bidExtData); err == nil { - if vastXML, ok := bidExtData["vastXml"].(string); ok && vastXML != "" { - bidCopy.AdM = vastXML - } else if vastURL, ok := bidExtData["vastUrl"].(string); ok && vastURL != "" && bidCopy.AdM == "" { + // Try to extract custom fields vastXml and vastUrl from bid.ext + var bidExtData struct { + VastXML string `json:"vastXml"` + VastURL string `json:"vastUrl"` + } + if bid.Ext != nil { + if err := jsonutil.Unmarshal(bid.Ext, &bidExtData); err == nil { + if bidExtData.VastXML != "" { + bidCopy.AdM = bidExtData.VastXML + } else if bidExtData.VastURL != "" && bidCopy.AdM == "" { // Wrap VAST URL in VAST wrapper - bidCopy.AdM = fmt.Sprintf(``, vastURL) + bidCopy.AdM = fmt.Sprintf(``, bidExtData.VastURL) } } } @@ -272,14 +283,14 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest // parseScaliburExt extracts Scalibur-specific parameters from the impression extension. func parseScaliburExt(impExt json.RawMessage) (*openrtb_ext.ExtImpScalibur, error) { var bidderExt adapters.ExtImpBidder - if err := json.Unmarshal(impExt, &bidderExt); err != nil { + if err := jsonutil.Unmarshal(impExt, &bidderExt); err != nil { return nil, &errortypes.BadInput{ Message: fmt.Sprintf("Failed to parse imp.ext: %s", err.Error()), } } var scaliburExt openrtb_ext.ExtImpScalibur - if err := json.Unmarshal(bidderExt.Bidder, &scaliburExt); err != nil { + if err := jsonutil.Unmarshal(bidderExt.Bidder, &scaliburExt); err != nil { return nil, &errortypes.BadInput{ Message: fmt.Sprintf("Failed to parse Scalibur params: %s", err.Error()), } @@ -296,12 +307,15 @@ func parseScaliburExt(impExt json.RawMessage) (*openrtb_ext.ExtImpScalibur, erro // getBidMediaType determines the media type based on the impression func getBidMediaType(bid openrtb2.Bid, imp *openrtb2.Imp) (openrtb_ext.BidType, error) { - // 1 = Banner, 2 = Video, 3 = Audio, 4 = Native switch bid.MType { - case 1: + case openrtb2.MarkupBanner: return openrtb_ext.BidTypeBanner, nil - case 2: + case openrtb2.MarkupVideo: return openrtb_ext.BidTypeVideo, nil + case openrtb2.MarkupAudio: + return openrtb_ext.BidTypeAudio, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil } // Fallback for bidders not supporting mtype (non-multi-format requests) diff --git a/adapters/scalibur/scalibur_test.go b/adapters/scalibur/scalibur_test.go index 84c019f545e..92c0edc8f97 100644 --- a/adapters/scalibur/scalibur_test.go +++ b/adapters/scalibur/scalibur_test.go @@ -17,7 +17,7 @@ import ( func newTestAdapter() adapters.Bidder { adapter, _ := Builder( openrtb_ext.BidderScalibur, - config.Adapter{Endpoint: "https://srv.scalibur.io/adserver/ortb?type=prebid"}, + config.Adapter{Endpoint: "https://srv.scalibur.io/adserver/ortb?type=prebid-server"}, config.Server{}, ) return adapter @@ -58,13 +58,15 @@ func TestMakeRequests_SuccessBanner(t *testing.T) { Site: &openrtb2.Site{Page: "https://test.com"}, } - requests, errs := bidder.MakeRequests(req, &adapters.ExtraRequestInfo{}) + requests, errs := bidder.MakeRequests(req, &adapters.ExtraRequestInfo{ + CurrencyConversions: &mockConversions{}, + }) require.Len(t, errs, 0) require.Len(t, requests, 1) r := requests[0] - assert.Equal(t, "https://srv.scalibur.io/adserver/ortb?type=prebid", r.Uri) + assert.Equal(t, "https://srv.scalibur.io/adserver/ortb?type=prebid-server", r.Uri) assert.Equal(t, "POST", r.Method) assert.Contains(t, r.Headers.Get("Content-Type"), "application/json") @@ -76,7 +78,7 @@ func TestMakeRequests_SuccessBanner(t *testing.T) { imp := out.Imp[0] assert.Equal(t, float64(1.25), imp.BidFloor) - assert.Equal(t, "EUR", imp.BidFloorCur) + assert.Equal(t, "USD", imp.BidFloorCur) var outExt map[string]interface{} require.NoError(t, json.Unmarshal(imp.Ext, &outExt)) @@ -122,8 +124,8 @@ func TestMakeRequests_VideoDefaultsApplied(t *testing.T) { ID: "req-video", Imp: []openrtb2.Imp{ { - ID: "v1", - Ext: ext, + ID: "v1", + Ext: ext, Video: &openrtb2.Video{ // Intentionally empty → should fill defaults }, @@ -131,7 +133,10 @@ func TestMakeRequests_VideoDefaultsApplied(t *testing.T) { }, } - requests, errs := bidder.MakeRequests(req, &adapters.ExtraRequestInfo{}) + requests, errs := bidder.MakeRequests(req, &adapters.ExtraRequestInfo{ + CurrencyConversions: &mockConversions{}, + }) + require.Len(t, errs, 0) require.Len(t, requests, 1) @@ -152,6 +157,16 @@ func TestMakeRequests_VideoDefaultsApplied(t *testing.T) { assert.NotZero(t, v.Linearity) } +type mockConversions struct{} + +func (m *mockConversions) GetRate(from string, to string) (float64, error) { + return 1.0, nil +} + +func (m *mockConversions) GetRates() *map[string]map[string]float64 { + return nil +} + // // ------------------------------------------------------------------------------------------ // MAKE BIDS TESTS @@ -263,7 +278,6 @@ func TestMakeBids_InvalidJSON(t *testing.T) { _, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, respData) require.Len(t, errs, 1) - assert.Contains(t, errs[0].Error(), "Failed to unmarshal") } func ptrInt64(x int64) *int64 { return &x } diff --git a/adapters/scalibur/scaliburtest/success_banner.json b/adapters/scalibur/scaliburtest/exemplary/success_banner.json similarity index 70% rename from adapters/scalibur/scaliburtest/success_banner.json rename to adapters/scalibur/scaliburtest/exemplary/success_banner.json index fa80ebb6b9c..aabe2beb479 100644 --- a/adapters/scalibur/scaliburtest/success_banner.json +++ b/adapters/scalibur/scaliburtest/exemplary/success_banner.json @@ -8,14 +8,21 @@ }] }, "httpCalls": [{ - "expectedUri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", "expectedRequest": { - "id": "test-request-id", - "imp": [{ - "id": "test-imp-id", - "banner": { "format": [{"w": 300, "h": 250}] }, - "ext": { "placementId": "test-scl-placement" } - }] + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-scl-placement", + "bidfloorcur": "USD" + } + }] + } }, "mockResponse": { "status": 200, diff --git a/adapters/scalibur/scaliburtest/video.json b/adapters/scalibur/scaliburtest/exemplary/video.json similarity index 55% rename from adapters/scalibur/scaliburtest/video.json rename to adapters/scalibur/scaliburtest/exemplary/video.json index e78cab6bbcb..7eaea7a2895 100644 --- a/adapters/scalibur/scaliburtest/video.json +++ b/adapters/scalibur/scaliburtest/exemplary/video.json @@ -16,7 +16,32 @@ }] }, "httpCalls": [{ - "expectedUri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["video-imp-1"], + "body": { + "id": "test-video-req", + "imp": [{ + "id": "video-imp-1", + "video": { + "mimes": ["video/mp4"], + "minduration": 1, + "maxduration": 180, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480, + "placement": 1, + "linearity": 1, + "maxbitrate": 30000 + }, + "bidfloorcur": "USD", + "ext": { + "placementId": "46", + "bidfloorcur": "USD" + } + }] + } + }, "mockResponse": { "status": 200, "body": { @@ -44,7 +69,8 @@ "impid": "video-imp-1", "price": 1.5, "adm": "...", - "crid": "cr-video" + "crid": "cr-video", + "ext": { "vastXml": "..." } }, "type": "video" }] diff --git a/adapters/scalibur/scaliburtest/video_vast_url.json b/adapters/scalibur/scaliburtest/exemplary/video_vast_url.json similarity index 54% rename from adapters/scalibur/scaliburtest/video_vast_url.json rename to adapters/scalibur/scaliburtest/exemplary/video_vast_url.json index 38498ddd058..f00833b95b9 100644 --- a/adapters/scalibur/scaliburtest/video_vast_url.json +++ b/adapters/scalibur/scaliburtest/exemplary/video_vast_url.json @@ -8,7 +8,32 @@ }] }, "httpCalls": [{ - "expectedUri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["video-imp-2"], + "body": { + "id": "test-video-url-req", + "imp": [{ + "id": "video-imp-2", + "video": { + "mimes": ["video/mp4"], + "minduration": 1, + "maxduration": 180, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480, + "placement": 1, + "linearity": 1, + "maxbitrate": 30000 + }, + "bidfloorcur": "USD", + "ext": { + "placementId": "46", + "bidfloorcur": "USD" + } + }] + } + }, "mockResponse": { "status": 200, "body": { @@ -33,7 +58,8 @@ "id": "bid-v2", "impid": "video-imp-2", "price": 2.0, - "adm": "" + "adm": "", + "ext": { "vastUrl": "https://cdn.scalibur.io/vast.xml" } }, "type": "video" }] diff --git a/static/bidder-info/scalibur.yaml b/static/bidder-info/scalibur.yaml index 1b945799a73..4b6a081d81a 100644 --- a/static/bidder-info/scalibur.yaml +++ b/static/bidder-info/scalibur.yaml @@ -28,6 +28,7 @@ capabilities: userSync: iframe: - url: "https://srv.scalibur.io/adserver/sync?type=iframe&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}[PBS_UID]" + url: "https://srv.scalibur.io/adserver/sync?type=iframe&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}" + userMacro: "[PBS_UID]" supports: - iframe \ No newline at end of file From 98d3567d93ee8fee1145ef7d250a62937c5ba524 Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Wed, 14 Jan 2026 11:10:39 +0200 Subject: [PATCH 09/14] address PR feedback for Scalibur adapter --- adapters/scalibur/scalibur.go | 14 ++-- adapters/scalibur/scalibur_test.go | 60 ++++++++++++++++- .../scaliburtest/exemplary/debug.json | 59 +++++++++++++++++ .../scaliburtest/exemplary/debug_prebid.json | 62 ++++++++++++++++++ .../scalibur/scaliburtest/exemplary/gpid.json | 65 +++++++++++++++++++ .../scaliburtest/exemplary/mtype.json | 58 +++++++++++++++++ 6 files changed, 309 insertions(+), 9 deletions(-) create mode 100644 adapters/scalibur/scaliburtest/exemplary/debug.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/debug_prebid.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/gpid.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/mtype.json diff --git a/adapters/scalibur/scalibur.go b/adapters/scalibur/scalibur.go index 5ed40168ff7..291807462ee 100644 --- a/adapters/scalibur/scalibur.go +++ b/adapters/scalibur/scalibur.go @@ -22,11 +22,7 @@ type adapter struct { // Builder builds a new instance of the Scalibur adapter for the given bidder with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { - endpoint := config.Endpoint - if endpoint == "" { - endpoint = "https://srv.scalibur.io/adserver/ortb?type=prebid-server" - } - temp, err := template.New("endpointTemplate").Parse(endpoint) + temp, err := template.New("endpointTemplate").Parse(config.Endpoint) if err != nil { return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) } @@ -236,13 +232,17 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest // Find the corresponding imp imp, found := impMap[bid.ImpID] if !found { - continue + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Invalid bid imp ID %s", bid.ImpID), + }} } // Determine bid type based on imp bidType, err := getBidMediaType(bid, imp) if err != nil { - continue + return nil, []error{&errortypes.BadServerResponse{ + Message: err.Error(), + }} } bidCopy := bid diff --git a/adapters/scalibur/scalibur_test.go b/adapters/scalibur/scalibur_test.go index 92c0edc8f97..2979cba817c 100644 --- a/adapters/scalibur/scalibur_test.go +++ b/adapters/scalibur/scalibur_test.go @@ -124,8 +124,8 @@ func TestMakeRequests_VideoDefaultsApplied(t *testing.T) { ID: "req-video", Imp: []openrtb2.Imp{ { - ID: "v1", - Ext: ext, + ID: "v1", + Ext: ext, Video: &openrtb2.Video{ // Intentionally empty → should fill defaults }, @@ -280,4 +280,60 @@ func TestMakeBids_InvalidJSON(t *testing.T) { require.Len(t, errs, 1) } +func TestMakeBids_ImpNotFound(t *testing.T) { + bidder := newTestAdapter() + + mockReq := &openrtb2.BidRequest{ + ID: "req1", + Imp: []openrtb2.Imp{ + {ID: "1"}, + }, + } + + mockReqData := &adapters.RequestData{ + Body: []byte(`{"id":"req1","imp":[{"id":"1"}]}`), + } + + mockResp := &openrtb2.BidResponse{ + ID: "resp1", + SeatBid: []openrtb2.SeatBid{ + { + Bid: []openrtb2.Bid{ + { + ID: "b1", + ImpID: "non-existent", + }, + }, + }, + }, + } + + respData := &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: func() []byte { + b, _ := json.Marshal(mockResp) + return b + }(), + } + + _, errs := bidder.MakeBids(mockReq, mockReqData, respData) + require.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "Invalid bid imp ID non-existent") +} + +func TestGetBidMediaType_Error(t *testing.T) { + bid := openrtb2.Bid{ + ID: "bid1", + ImpID: "imp1", + } + imp := &openrtb2.Imp{ + ID: "imp1", + // No banner or video + } + + _, err := getBidMediaType(bid, imp) + assert.Error(t, err) + assert.Contains(t, err.Error(), "unsupported or ambiguous media type") +} + func ptrInt64(x int64) *int64 { return &x } diff --git a/adapters/scalibur/scaliburtest/exemplary/debug.json b/adapters/scalibur/scaliburtest/exemplary/debug.json new file mode 100644 index 00000000000..4422ffb07ee --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/debug.json @@ -0,0 +1,59 @@ +{ + "mockBidRequest": { + "id": "test-debug-request", + "test": 1, + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { "bidder": { "placementId": "test-placement" } } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-debug-request", + "test": 1, + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-placement", + "bidfloorcur": "USD" + } + }], + "ext": { "isDebug": 1 } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-debug-request", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "...", + "crid": "test-creative-id" + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "...", + "crid": "test-creative-id" + }, + "type": "banner" + }] + }] +} diff --git a/adapters/scalibur/scaliburtest/exemplary/debug_prebid.json b/adapters/scalibur/scaliburtest/exemplary/debug_prebid.json new file mode 100644 index 00000000000..5f780c6810f --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/debug_prebid.json @@ -0,0 +1,62 @@ +{ + "mockBidRequest": { + "id": "test-debug-prebid-request", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { "bidder": { "placementId": "test-placement" } } + }], + "ext": { + "prebid": { + "debug": true + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-debug-prebid-request", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-placement", + "bidfloorcur": "USD" + } + }], + "ext": { "isDebug": 1 } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-debug-prebid-request", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "...", + "crid": "test-creative-id" + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "...", + "crid": "test-creative-id" + }, + "type": "banner" + }] + }] +} diff --git a/adapters/scalibur/scaliburtest/exemplary/gpid.json b/adapters/scalibur/scaliburtest/exemplary/gpid.json new file mode 100644 index 00000000000..393c8a86ddb --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/gpid.json @@ -0,0 +1,65 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { + "bidder": { "placementId": "test-scl-placement" }, + "gpid": "test-gpid-value" + } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-scl-placement", + "bidfloorcur": "USD", + "gpid": "test-gpid-value" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "...", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }] + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "...", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }, + "type": "banner" + }] + }] +} diff --git a/adapters/scalibur/scaliburtest/exemplary/mtype.json b/adapters/scalibur/scaliburtest/exemplary/mtype.json new file mode 100644 index 00000000000..4256373d8f8 --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/mtype.json @@ -0,0 +1,58 @@ +{ + "mockBidRequest": { + "id": "test-mtype-request", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { "bidder": { "placementId": "test-placement" } } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-mtype-request", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-placement", + "bidfloorcur": "USD" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-mtype-request", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "...", + "crid": "test-creative-id", + "mtype": 1 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "...", + "crid": "test-creative-id", + "mtype": 1 + }, + "type": "banner" + }] + }] +} From 544969ce3b86522606d0910a87d07b14824c379e Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Sun, 18 Jan 2026 09:45:05 +0200 Subject: [PATCH 10/14] fix(scalibur): address additional PR feedback - Remove unsupported audio/native types from getBidMediaType - Add JSON test for video mtype - Add unit tests for parseScaliburExt error cases --- adapters/scalibur/scalibur.go | 4 -- adapters/scalibur/scalibur_test.go | 12 ++++ .../scaliburtest/exemplary/mtype_video.json | 68 +++++++++++++++++++ 3 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 adapters/scalibur/scaliburtest/exemplary/mtype_video.json diff --git a/adapters/scalibur/scalibur.go b/adapters/scalibur/scalibur.go index 291807462ee..c3ae2377bf6 100644 --- a/adapters/scalibur/scalibur.go +++ b/adapters/scalibur/scalibur.go @@ -312,10 +312,6 @@ func getBidMediaType(bid openrtb2.Bid, imp *openrtb2.Imp) (openrtb_ext.BidType, 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 } // Fallback for bidders not supporting mtype (non-multi-format requests) diff --git a/adapters/scalibur/scalibur_test.go b/adapters/scalibur/scalibur_test.go index 2979cba817c..331ab039d20 100644 --- a/adapters/scalibur/scalibur_test.go +++ b/adapters/scalibur/scalibur_test.go @@ -336,4 +336,16 @@ func TestGetBidMediaType_Error(t *testing.T) { assert.Contains(t, err.Error(), "unsupported or ambiguous media type") } +func TestParseScaliburExt_ErrorCases(t *testing.T) { + // Case 1: Invalid JSON for imp.ext + _, err := parseScaliburExt(json.RawMessage(`{invalid`)) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Failed to parse imp.ext") + + // Case 2: Missing placementId + _, err = parseScaliburExt(json.RawMessage(`{"bidder": {"bidfloor": 1.0}}`)) + assert.Error(t, err) + assert.Contains(t, err.Error(), "placementId is required") +} + func ptrInt64(x int64) *int64 { return &x } diff --git a/adapters/scalibur/scaliburtest/exemplary/mtype_video.json b/adapters/scalibur/scaliburtest/exemplary/mtype_video.json new file mode 100644 index 00000000000..32121a1a083 --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/mtype_video.json @@ -0,0 +1,68 @@ +{ + "mockBidRequest": { + "id": "test-mtype-video-request", + "imp": [{ + "id": "test-imp-id", + "video": { "mimes": ["video/mp4"] }, + "ext": { "bidder": { "placementId": "test-placement" } } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-mtype-video-request", + "imp": [{ + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "minduration": 1, + "maxduration": 180, + "maxbitrate": 30000, + "protocols": [2, 3, 5, 6], + "w": 640, + "h": 480, + "placement": 1, + "linearity": 1 + }, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-placement", + "bidfloorcur": "USD" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-mtype-video-request", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "...", + "crid": "test-creative-id", + "mtype": 2 + }] + }] + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "...", + "crid": "test-creative-id", + "mtype": 2 + }, + "type": "video" + }] + }] +} From 794aff1e209c98fd321a295b007ceb7433a5551f Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Sun, 8 Feb 2026 10:09:39 +0200 Subject: [PATCH 11/14] address pr comments --- exchange/adapter_builders.go | 2 -- openrtb_ext/bidders.go | 2 -- 2 files changed, 4 deletions(-) diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 6141e6e0c9c..c434b5d69d8 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -201,7 +201,6 @@ import ( "github.com/prebid/prebid-server/v3/adapters/rubicon" salunamedia "github.com/prebid/prebid-server/v3/adapters/sa_lunamedia" "github.com/prebid/prebid-server/v3/adapters/scalibur" - "github.com/prebid/prebid-server/v3/adapters/screencore" "github.com/prebid/prebid-server/v3/adapters/seedingAlliance" "github.com/prebid/prebid-server/v3/adapters/seedtag" "github.com/prebid/prebid-server/v3/adapters/sharethrough" @@ -474,7 +473,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderSeedtag: seedtag.Builder, openrtb_ext.BidderSaLunaMedia: salunamedia.Builder, openrtb_ext.BidderScalibur: scalibur.Builder, - openrtb_ext.BidderScreencore: screencore.Builder, openrtb_ext.BidderSharethrough: sharethrough.Builder, openrtb_ext.BidderShowheroes: showheroes.Builder, openrtb_ext.BidderSilverMob: silvermob.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 284fd635cab..a7f4aadec12 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -221,7 +221,6 @@ var coreBidderNames []BidderName = []BidderName{ BidderSeedtag, BidderSaLunaMedia, BidderScalibur, - BidderScreencore, BidderSharethrough, BidderShowheroes, BidderSilverMob, @@ -596,7 +595,6 @@ const ( BidderSeedtag BidderName = "seedtag" BidderSaLunaMedia BidderName = "sa_lunamedia" BidderScalibur BidderName = "scalibur" - BidderScreencore BidderName = "screencore" BidderSharethrough BidderName = "sharethrough" BidderShowheroes BidderName = "showheroes" BidderSilverMob BidderName = "silvermob" From e1b3d3b5096741e7138b4fc4590e09d031ca1e8c Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Thu, 26 Mar 2026 19:49:25 +0200 Subject: [PATCH 12/14] update to v4 --- adapters/scalibur/params_test.go | 2 +- adapters/scalibur/scalibur.go | 10 +++++----- adapters/scalibur/scalibur_test.go | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/adapters/scalibur/params_test.go b/adapters/scalibur/params_test.go index e03d549f366..994a8fb23b0 100644 --- a/adapters/scalibur/params_test.go +++ b/adapters/scalibur/params_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v4/openrtb_ext" ) func TestValidParams(t *testing.T) { diff --git a/adapters/scalibur/scalibur.go b/adapters/scalibur/scalibur.go index c3ae2377bf6..20c33c1ceff 100644 --- a/adapters/scalibur/scalibur.go +++ b/adapters/scalibur/scalibur.go @@ -9,11 +9,11 @@ import ( "github.com/prebid/openrtb/v20/adcom1" "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/jsonutil" + "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" ) type adapter struct { diff --git a/adapters/scalibur/scalibur_test.go b/adapters/scalibur/scalibur_test.go index 331ab039d20..2ac483343ac 100644 --- a/adapters/scalibur/scalibur_test.go +++ b/adapters/scalibur/scalibur_test.go @@ -6,10 +6,10 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" - "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/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/adapters/adapterstest" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/openrtb_ext" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) From 69e2c7d5458484a67f54a24598aece6ce6c632de Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Wed, 13 May 2026 14:10:00 +0300 Subject: [PATCH 13/14] fix all last pr comments and merge with master --- adapters/scalibur/scalibur.go | 6 -- adapters/scalibur/scalibur.out | 101 ++++++++++++++++++ adapters/scalibur/scalibur_test.go | 11 +- .../exemplary/bid-floor-eur-to-usd.json | 80 ++++++++++++++ .../scaliburtest/exemplary/bid-floor-usd.json | 69 ++++++++++++ .../bid-floor-currency-conversion-error.json | 34 ++++++ docs/bidders/scalibur.md | 16 --- static/bidder-info/scalibur.yaml | 3 - 8 files changed, 286 insertions(+), 34 deletions(-) create mode 100644 adapters/scalibur/scalibur.out create mode 100644 adapters/scalibur/scaliburtest/exemplary/bid-floor-eur-to-usd.json create mode 100644 adapters/scalibur/scaliburtest/exemplary/bid-floor-usd.json create mode 100644 adapters/scalibur/scaliburtest/supplemental/bid-floor-currency-conversion-error.json delete mode 100644 docs/bidders/scalibur.md diff --git a/adapters/scalibur/scalibur.go b/adapters/scalibur/scalibur.go index 20c33c1ceff..f4c77ffa5ba 100644 --- a/adapters/scalibur/scalibur.go +++ b/adapters/scalibur/scalibur.go @@ -296,12 +296,6 @@ func parseScaliburExt(impExt json.RawMessage) (*openrtb_ext.ExtImpScalibur, erro } } - if scaliburExt.PlacementID == "" { - return nil, &errortypes.BadInput{ - Message: "placementId is required", - } - } - return &scaliburExt, nil } diff --git a/adapters/scalibur/scalibur.out b/adapters/scalibur/scalibur.out new file mode 100644 index 00000000000..ac7672b616d --- /dev/null +++ b/adapters/scalibur/scalibur.out @@ -0,0 +1,101 @@ +mode: set +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:24.119,26.16 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:26.16,28.3 1 0 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:30.2,32.8 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:36.133,41.34 3 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:41.34,43.17 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:43.17,45.12 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:48.3,51.63 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:51.63,53.37 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:53.37,55.5 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:58.3,58.88 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:58.88,60.18 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:60.18,62.13 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:64.4,65.31 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:68.3,68.32 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:68.32,70.4 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:73.3,76.27 3 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:76.27,78.4 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:79.3,83.62 3 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:83.62,84.38 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:84.38,86.5 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:89.3,90.17 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:90.17,92.12 2 0 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:94.3,97.27 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:97.27,101.33 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:101.33,103.5 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:104.4,104.34 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:104.34,106.5 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:107.4,107.34 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:107.34,109.5 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:110.4,110.33 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:110.33,112.5 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:113.4,113.37 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:113.37,116.5 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:118.4,118.47 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:118.47,121.5 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:122.4,122.47 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:122.47,125.5 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:126.4,126.32 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:126.32,128.5 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:129.4,129.32 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:129.32,131.5 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:133.4,133.30 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:136.3,136.41 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:140.2,140.25 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:140.25,142.3 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:145.2,150.38 5 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:150.38,152.70 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:152.70,154.4 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:157.2,157.13 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:157.13,159.62 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:159.62,161.4 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:162.8,164.3 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:166.2,167.16 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:167.16,169.3 1 0 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:171.2,172.65 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:172.65,174.3 1 0 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:176.2,188.51 5 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:192.174,193.49 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:193.49,195.3 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:197.2,197.42 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:197.42,201.3 1 0 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:203.2,204.68 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:204.68,206.3 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:209.2,210.74 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:210.74,212.3 1 0 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:215.2,216.28 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:216.28,218.3 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:220.2,223.23 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:223.23,225.3 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:225.8,227.3 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:230.2,230.42 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:230.42,231.35 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:231.35,234.14 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:234.14,238.5 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:241.4,242.18 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:242.18,246.5 1 0 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:248.4,251.43 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:251.43,257.23 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:257.23,258.69 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:258.69,259.35 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:259.35,261.8 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:261.13,261.63 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:261.63,264.8 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:269.4,272.6 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:276.2,276.32 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:276.32,278.3 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:280.2,280.25 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:284.84,286.63 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:286.63,290.3 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:292.2,293.75 2 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:293.75,297.3 1 0 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:299.2,299.26 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:303.88,304.19 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:305.29,306.40 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:307.28,308.39 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:312.2,312.43 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:312.43,314.3 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:315.2,315.43 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:315.43,317.3 1 1 +github.com/prebid/prebid-server/v4/adapters/scalibur/scalibur.go:319.2,319.84 1 1 diff --git a/adapters/scalibur/scalibur_test.go b/adapters/scalibur/scalibur_test.go index 2ac483343ac..3199e8ef661 100644 --- a/adapters/scalibur/scalibur_test.go +++ b/adapters/scalibur/scalibur_test.go @@ -88,9 +88,8 @@ func TestMakeRequests_SuccessBanner(t *testing.T) { func TestMakeRequests_InvalidExt(t *testing.T) { bidder := newTestAdapter() - // Missing placementId badExt, _ := json.Marshal(adapters.ExtImpBidder{ - Bidder: json.RawMessage(`{"bidfloor": 1.5}`), + Bidder: json.RawMessage(`{invalid`), }) req := &openrtb2.BidRequest{ @@ -110,7 +109,7 @@ func TestMakeRequests_InvalidExt(t *testing.T) { require.Len(t, requests, 0) require.Len(t, errs, 1) - assert.Contains(t, errs[0].Error(), "placementId is required") + assert.Contains(t, errs[0].Error(), "Failed to parse imp.ext") } func TestMakeRequests_VideoDefaultsApplied(t *testing.T) { @@ -337,15 +336,9 @@ func TestGetBidMediaType_Error(t *testing.T) { } func TestParseScaliburExt_ErrorCases(t *testing.T) { - // Case 1: Invalid JSON for imp.ext _, err := parseScaliburExt(json.RawMessage(`{invalid`)) assert.Error(t, err) assert.Contains(t, err.Error(), "Failed to parse imp.ext") - - // Case 2: Missing placementId - _, err = parseScaliburExt(json.RawMessage(`{"bidder": {"bidfloor": 1.0}}`)) - assert.Error(t, err) - assert.Contains(t, err.Error(), "placementId is required") } func ptrInt64(x int64) *int64 { return &x } diff --git a/adapters/scalibur/scaliburtest/exemplary/bid-floor-eur-to-usd.json b/adapters/scalibur/scaliburtest/exemplary/bid-floor-eur-to-usd.json new file mode 100644 index 00000000000..c9d3b37c396 --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/bid-floor-eur-to-usd.json @@ -0,0 +1,80 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { + "bidder": { + "placementId": "test-scl-placement", + "bidfloor": 1.0, + "bidfloorcur": "EUR" + } + } + }], + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2 + } + } + } + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloor": 1.2, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-scl-placement", + "bidfloor": 1.2, + "bidfloorcur": "USD" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.2, + "adm": "...", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }] + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.2, + "adm": "...", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/scalibur/scaliburtest/exemplary/bid-floor-usd.json b/adapters/scalibur/scaliburtest/exemplary/bid-floor-usd.json new file mode 100644 index 00000000000..2549a4d7e0a --- /dev/null +++ b/adapters/scalibur/scaliburtest/exemplary/bid-floor-usd.json @@ -0,0 +1,69 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { + "bidder": { + "placementId": "test-scl-placement", + "bidfloor": 1.5, + "bidfloorcur": "USD" + } + } + }] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://srv.scalibur.io/adserver/ortb?type=prebid-server", + "impIDs": ["test-imp-id"], + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "bidfloor": 1.5, + "bidfloorcur": "USD", + "ext": { + "placementId": "test-scl-placement", + "bidfloor": 1.5, + "bidfloorcur": "USD" + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "bid": [{ + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "...", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }] + }], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-bid-id", + "impid": "test-imp-id", + "price": 1.5, + "adm": "...", + "crid": "test-creative-id", + "w": 300, + "h": 250 + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/scalibur/scaliburtest/supplemental/bid-floor-currency-conversion-error.json b/adapters/scalibur/scaliburtest/supplemental/bid-floor-currency-conversion-error.json new file mode 100644 index 00000000000..a1543139343 --- /dev/null +++ b/adapters/scalibur/scaliburtest/supplemental/bid-floor-currency-conversion-error.json @@ -0,0 +1,34 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { "format": [{"w": 300, "h": 250}] }, + "ext": { + "bidder": { + "placementId": "test-scl-placement", + "bidfloor": 1.5, + "bidfloorcur": "EUR" + } + } + }], + "ext": { + "prebid": { + "currency": { + "rates": { + "GBP": { + "USD": 1.3 + } + } + } + } + } + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "Currency conversion rate not found: 'EUR' => 'USD'", + "comparison": "literal" + } + ] +} diff --git a/docs/bidders/scalibur.md b/docs/bidders/scalibur.md deleted file mode 100644 index 95f409b997d..00000000000 --- a/docs/bidders/scalibur.md +++ /dev/null @@ -1,16 +0,0 @@ -# Scalibur - -The Scalibur adapter supports Banner and Video media types via OpenRTB 2.6. - -## Registration -Contact [support@scalibur.io](mailto:support@scalibur.io) to obtain a valid `placementId`. - -## Bid Params -| Name | Type | Description | Notes | -| :--- | :--- | :--- |:----------------------| -| `placementId` | string | **Required**. Scalibur placement identifier. | Example: `"468acd11"` | -| `bidfloor` | number | Optional. Minimum bid floor price. | | -| `bidfloorcur` | string | Optional. Currency for the bid floor. | Default is `USD`. | - -## User Sync -Supports iframe synchronization. Prebid Server handles the mapping of the sync ID to the `user.buyeruid` field in outgoing OpenRTB requests. \ No newline at end of file diff --git a/static/bidder-info/scalibur.yaml b/static/bidder-info/scalibur.yaml index 4b6a081d81a..a1aaf50c80b 100644 --- a/static/bidder-info/scalibur.yaml +++ b/static/bidder-info/scalibur.yaml @@ -6,9 +6,6 @@ disabled: false maintainer: email: "support@scalibur.io" -supported-media-types: - - banner - - video gvlVendorID: 1471 From 4e79921a74ffcab00750495163246283e2999368 Mon Sep 17 00:00:00 2001 From: Timor Bibi Date: Wed, 13 May 2026 14:12:04 +0300 Subject: [PATCH 14/14] remove blank lines from scalibur yaml --- static/bidder-info/scalibur.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/static/bidder-info/scalibur.yaml b/static/bidder-info/scalibur.yaml index a1aaf50c80b..8b82f56a3f5 100644 --- a/static/bidder-info/scalibur.yaml +++ b/static/bidder-info/scalibur.yaml @@ -1,18 +1,13 @@ endpoint: "https://srv.scalibur.io/adserver/ortb?type=prebid-server" - # Leave disabled: false → adapter enabled compression: gzip disabled: false - maintainer: email: "support@scalibur.io" - gvlVendorID: 1471 - openrtb: version: 2.6 gpp-supported: true - capabilities: site: mediaTypes: @@ -22,7 +17,6 @@ capabilities: mediaTypes: - banner - video - userSync: iframe: url: "https://srv.scalibur.io/adserver/sync?type=iframe&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}"