diff --git a/adapters/kargo/kargo.go b/adapters/kargo/kargo.go
new file mode 100644
index 00000000000..8525d771103
--- /dev/null
+++ b/adapters/kargo/kargo.go
@@ -0,0 +1,89 @@
+package kargo
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "github.com/mxmCherry/openrtb/v15/openrtb2"
+ "github.com/prebid/prebid-server/adapters"
+ "github.com/prebid/prebid-server/config"
+ "github.com/prebid/prebid-server/errortypes"
+ "github.com/prebid/prebid-server/openrtb_ext"
+)
+
+type adapter struct {
+ URI string
+}
+type kargoExt struct {
+ MediaType string `json:"mediaType"`
+}
+
+// Builder builds a new instance of the Kargo adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+ bidder := &adapter{
+ URI: config.Endpoint, // base url of bidding server
+ }
+ return bidder, nil
+}
+
+// MakeRequests creates outgoing requests to the Kargo bidding server.
+func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+ requestJSON, err := json.Marshal(request)
+ if err != nil {
+ return nil, []error{err}
+ }
+
+ requestData := &adapters.RequestData{
+ Method: "POST",
+ Uri: a.URI,
+ Body: requestJSON,
+ }
+
+ return []*adapters.RequestData{requestData}, nil
+}
+
+// MakeBids receives a bid response from the Kargo bidding server and creates bids for the publishers auction.
+func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+ if responseData.StatusCode == http.StatusNoContent {
+ return nil, nil
+ }
+
+ if responseData.StatusCode != http.StatusOK {
+ err := &errortypes.BadServerResponse{
+ Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode),
+ }
+ return nil, []error{err}
+ }
+
+ var response openrtb2.BidResponse
+ if err := json.Unmarshal(responseData.Body, &response); err != nil {
+ return nil, []error{err}
+ }
+
+ bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp))
+ bidResponse.Currency = response.Cur
+ for _, seatBid := range response.SeatBid {
+ for i, bid := range seatBid.Bid {
+ b := &adapters.TypedBid{
+ Bid: &seatBid.Bid[i],
+ BidType: getMediaTypeForBid(bid.Ext),
+ }
+ bidResponse.Bids = append(bidResponse.Bids, b)
+ }
+ }
+ return bidResponse, nil
+}
+
+func getMediaTypeForBid(ext json.RawMessage) openrtb_ext.BidType {
+ var impExt kargoExt
+ if err := json.Unmarshal(ext, &impExt); err == nil {
+ switch impExt.MediaType {
+ case string(openrtb_ext.BidTypeVideo):
+ return openrtb_ext.BidTypeVideo
+ case string(openrtb_ext.BidTypeNative):
+ return openrtb_ext.BidTypeNative
+ }
+ }
+ return openrtb_ext.BidTypeBanner
+}
diff --git a/adapters/kargo/kargo_test.go b/adapters/kargo/kargo_test.go
new file mode 100644
index 00000000000..0936cfa4046
--- /dev/null
+++ b/adapters/kargo/kargo_test.go
@@ -0,0 +1,20 @@
+package kargo
+
+import (
+ "testing"
+
+ "github.com/prebid/prebid-server/adapters/adapterstest"
+ "github.com/prebid/prebid-server/config"
+ "github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestJsonSamples(t *testing.T) {
+ bidder, buildErr := Builder(openrtb_ext.BidderKargo, config.Adapter{
+ Endpoint: "http://example.com/bid"})
+
+ if buildErr != nil {
+ t.Fatalf("Builder returned unexpected error %v", buildErr)
+ }
+
+ adapterstest.RunJSONBidderTest(t, "kargotest", bidder)
+}
diff --git a/adapters/kargo/kargotest/exemplary/banner.json b/adapters/kargo/kargotest/exemplary/banner.json
new file mode 100644
index 00000000000..db14ee8b792
--- /dev/null
+++ b/adapters/kargo/kargotest/exemplary/banner.json
@@ -0,0 +1,207 @@
+{
+ "mockBidRequest": {
+ "id": "5f4d1e01",
+ "at": 1,
+ "imp": [
+ {
+ "id": "8b1bdcca",
+ "banner": {
+ "w": 300,
+ "h": 300,
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ],
+ "pos": 0,
+ "expdir": [1, 2, 3, 4, 5]
+ },
+ "tagid": "73",
+ "secure": 1,
+ "iframebuster": ["ALL"],
+ "ext": {
+ "adSlotID": "11523"
+ }
+ }
+ ],
+ "site": {
+ "id": "123",
+ "domain": "www.dailymail.co.uk",
+ "cat": ["IAB7"],
+ "page": "https://www.dailymail.co.uk/",
+ "ref": "https://www.dailymail.co.uk/",
+ "mobile": 1,
+ "publisher": {
+ "id": "1"
+ }
+ },
+ "device": {
+ "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.1 Safari/537",
+ "geo": {
+ "ipservice": 4,
+ "country": "US",
+ "region": "CO",
+ "metro": "751",
+ "city": "SomeCityInCo",
+ "zip": "11223"
+ },
+ "ip": "127.0.0.1",
+ "devicetype": 2,
+ "make": "Apple",
+ "model": "iPhone",
+ "os": "Windows",
+ "osv": "10.0",
+ "carrier": "none",
+ "language": "en",
+ "connectiontype": 2,
+ "dnt": 0
+ },
+ "user": {
+ "id": "07fb48ed",
+ "ext": {
+ },
+ "buyeruid": "345"
+ },
+ "regs": {
+ "ext": {
+ "us_privacy": "1"
+ }
+ },
+ "tmax": 200,
+ "ext": {
+ }
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://example.com/bid",
+ "body": {
+ "id": "5f4d1e01",
+ "at": 1,
+ "imp": [
+ {
+ "id": "8b1bdcca",
+ "banner": {
+ "w": 300,
+ "h": 300,
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ],
+ "pos": 0,
+ "expdir": [1, 2, 3, 4, 5]
+ },
+ "tagid": "73",
+ "secure": 1,
+ "iframebuster": ["ALL"],
+ "ext": {
+ "adSlotID": "11523"
+ }
+ }
+ ],
+ "site": {
+ "id": "123",
+ "domain": "www.dailymail.co.uk",
+ "cat": ["IAB7"],
+ "page": "https://www.dailymail.co.uk/",
+ "ref": "https://www.dailymail.co.uk/",
+ "mobile": 1,
+ "publisher": {
+ "id": "1"
+ }
+ },
+ "device": {
+ "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.1 Safari/537",
+ "geo": {
+ "ipservice": 4,
+ "country": "US",
+ "region": "CO",
+ "metro": "751",
+ "city": "SomeCityInCo",
+ "zip": "11223"
+ },
+ "ip": "127.0.0.1",
+ "devicetype": 2,
+ "make": "Apple",
+ "model": "iPhone",
+ "os": "Windows",
+ "osv": "10.0",
+ "carrier": "none",
+ "language": "en",
+ "connectiontype": 2,
+ "dnt": 0
+ },
+ "user": {
+ "id": "07fb48ed",
+ "ext": {
+ },
+ "buyeruid": "345"
+ },
+ "regs": {
+ "ext": {
+ "us_privacy": "1"
+ }
+ },
+ "tmax": 200,
+ "ext": {
+ }
+ }
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "5f4d1e01",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "67sadsac",
+ "impid": "8b1bdcca",
+ "price": 10,
+ "nurl": "http://example.com/win/10",
+ "adm": "
ad
",
+ "adomain": ["example.com"],
+ "cid": "test-cid",
+ "crid": "test-crid",
+ "cat": ["IAB13"],
+ "w": 300,
+ "h": 300,
+ "ext": {"mediaType": "banner"}
+ }
+ ],
+ "seat": "_b345"
+ }
+ ],
+ "bidid": "67sadsac",
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "bids": [
+ {
+ "bid": {
+ "id": "67sadsac",
+ "impid": "8b1bdcca",
+ "price": 10,
+ "nurl": "http://example.com/win/10",
+ "adm": "ad
",
+ "adomain": ["example.com"],
+ "cid": "test-cid",
+ "crid": "test-crid",
+ "cat": ["IAB13"],
+ "w": 300,
+ "h": 300,
+ "ext": {"mediaType": "banner"}
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/kargo/kargotest/exemplary/native.json b/adapters/kargo/kargotest/exemplary/native.json
new file mode 100644
index 00000000000..d0f03d6104f
--- /dev/null
+++ b/adapters/kargo/kargotest/exemplary/native.json
@@ -0,0 +1,220 @@
+{
+ "mockBidRequest": {
+ "id": "5f4d1e01",
+ "at": 1,
+ "imp": [
+ {
+ "id": "8b1bdcca",
+ "banner": {
+ "w": 300,
+ "h": 300,
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ],
+ "pos": 0,
+ "expdir": [1,2,3,4,5]
+ },
+ "native": {
+ "request" : "{\"plcmttype\":2,\"privacy\":0,\"assets\":[{\"id\":5,\"required\":0,\"title\":{\"len\":90}},{\"id\":6,\"required\":0,\"img\":{\"wmin\":620,\"hmin\":300,\"type\":3}},{\"id\":10,\"required\":0,\"data\":{\"len\":90,\"type\":1}},{\"id\":8,\"required\":0,\"data\":{\"len\":14,\"type\":12}},{\"id\":7,\"required\":0,\"img\":{\"wmin\":80,\"hmin\":80,\"type\":1}},{\"id\":11,\"required\":0,\"data\":{\"len\":140,\"type\":2}}]}"
+ },
+ "tagid": "73",
+ "secure": 1,
+ "iframebuster": [
+ "ALL"
+ ],
+ "ext": {
+ "adSlotID": "11523"
+ }
+ }
+ ],
+ "site": {
+ "id": "123",
+ "domain": "www.dailymail.co.uk",
+ "cat": ["IAB7"],
+ "page": "https://www.dailymail.co.uk/",
+ "ref": "https://www.dailymail.co.uk/",
+ "mobile": 1,
+ "publisher": {
+ "id": "1"
+ }
+ },
+ "device": {
+ "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.1 Safari/537",
+ "geo": {
+ "ipservice": 4,
+ "country": "US",
+ "region": "CO",
+ "metro": "751",
+ "city": "Ft Collins",
+ "zip": "80524"
+ },
+ "ip": "127.0.0.1",
+ "devicetype": 2,
+ "make": "Apple",
+ "model": "iPhone",
+ "os": "Windows",
+ "osv": "10.0",
+ "carrier": "none",
+ "language": "en",
+ "connectiontype": 2,
+ "dnt": 0
+ },
+ "user": {
+ "id": "07fb48ed",
+ "ext": {
+ },
+ "buyeruid": "345"
+ },
+ "regs": {
+ "ext": {
+ "us_privacy": "1"
+ }
+ },
+ "tmax": 200,
+ "ext": {
+ }
+ }
+ ,
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://example.com/bid",
+ "body": {
+ "id": "5f4d1e01",
+ "at": 1,
+ "imp": [
+ {
+ "id": "8b1bdcca",
+ "banner": {
+ "w": 300,
+ "h": 300,
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ],
+ "pos": 0,
+ "expdir": [1,2,3,4,5]
+ },
+ "native": {
+ "request" : "{\"plcmttype\":2,\"privacy\":0,\"assets\":[{\"id\":5,\"required\":0,\"title\":{\"len\":90}},{\"id\":6,\"required\":0,\"img\":{\"wmin\":620,\"hmin\":300,\"type\":3}},{\"id\":10,\"required\":0,\"data\":{\"len\":90,\"type\":1}},{\"id\":8,\"required\":0,\"data\":{\"len\":14,\"type\":12}},{\"id\":7,\"required\":0,\"img\":{\"wmin\":80,\"hmin\":80,\"type\":1}},{\"id\":11,\"required\":0,\"data\":{\"len\":140,\"type\":2}}]}"
+ },
+ "tagid": "73",
+ "secure": 1,
+ "iframebuster": [
+ "ALL"
+ ],
+ "ext": {
+ "adSlotID": "11523"
+ }
+ }
+ ],
+ "site": {
+ "id": "123",
+ "domain": "www.dailymail.co.uk",
+ "cat": ["IAB7"],
+ "page": "https://www.dailymail.co.uk/",
+ "ref": "https://www.dailymail.co.uk/",
+ "mobile": 1,
+ "publisher": {
+ "id": "1"
+ }
+ },
+ "device": {
+ "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.1 Safari/537",
+ "geo": {
+ "ipservice": 4,
+ "country": "US",
+ "region": "CO",
+ "metro": "751",
+ "city": "Ft Collins",
+ "zip": "80524"
+ },
+ "ip": "127.0.0.1",
+ "devicetype": 2,
+ "make": "Apple",
+ "model": "iPhone",
+ "os": "Windows",
+ "osv": "10.0",
+ "carrier": "none",
+ "language": "en",
+ "connectiontype": 2,
+ "dnt": 0
+ },
+ "user": {
+ "id": "07fb48ed",
+ "ext": {
+ },
+ "buyeruid": "345"
+ },
+ "regs": {
+ "ext": {
+ "us_privacy": "1"
+ }
+ },
+ "tmax": 200,
+ "ext": {
+ }
+ }
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "5f4d1e01",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "67sadsac",
+ "impid": "8b1bdcca",
+ "price": 10,
+ "nurl": "http://example.com/win/10",
+ "adm": "ad
",
+ "adomain": ["example.com"],
+ "cid": "test-cid",
+ "crid": "test-crid",
+ "cat": ["IAB13"],
+ "w": 300,
+ "h": 300,
+ "ext": {"mediaType": "native"}
+ }
+ ],
+ "seat": "_b345"
+ }
+ ],
+ "bidid": "67sadsac",
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "67sadsac",
+ "impid": "8b1bdcca",
+ "price": 10,
+ "nurl": "http://example.com/win/10",
+ "adm": "ad
",
+ "adomain": ["example.com"],
+ "cid": "test-cid",
+ "crid": "test-crid",
+ "cat": ["IAB13"],
+ "w": 300,
+ "h": 300,
+ "ext": {"mediaType": "native"}
+ },
+ "type": "native"
+ }
+ ]
+ }
+ ]
+ }
+
\ No newline at end of file
diff --git a/adapters/kargo/kargotest/exemplary/video.json b/adapters/kargo/kargotest/exemplary/video.json
new file mode 100644
index 00000000000..92a2124976f
--- /dev/null
+++ b/adapters/kargo/kargotest/exemplary/video.json
@@ -0,0 +1,224 @@
+{
+ "mockBidRequest": {
+ "id": "5f4d1e01",
+ "at": 1,
+ "imp": [
+ {
+ "id": "8b1bdcca",
+ "banner": {
+ "w": 300,
+ "h": 300,
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ],
+ "pos": 0,
+ "expdir": [1,2,3,4,5]
+ },
+ "video": {
+ "mimes": null,
+ "skip":0,
+ "playbackmethod":[2]
+ },
+ "tagid": "73",
+ "secure": 1,
+ "iframebuster": [
+ "ALL"
+ ],
+ "ext": {
+ "adSlotID": "11523"
+ }
+ }
+ ],
+ "site": {
+ "id": "123",
+ "domain": "www.dailymail.co.uk",
+ "cat": ["IAB7"],
+ "page": "https://www.dailymail.co.uk/",
+ "ref": "https://www.dailymail.co.uk/",
+ "mobile": 1,
+ "publisher": {
+ "id": "1"
+ }
+ },
+ "device": {
+ "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.1 Safari/537",
+ "geo": {
+ "ipservice": 4,
+ "country": "US",
+ "region": "CO",
+ "metro": "751",
+ "city": "Ft Collins",
+ "zip": "80524"
+ },
+ "ip": "127.0.0.1",
+ "devicetype": 2,
+ "make": "Apple",
+ "model": "iPhone",
+ "os": "Windows",
+ "osv": "10.0",
+ "carrier": "none",
+ "language": "en",
+ "connectiontype": 2,
+ "dnt": 0
+ },
+ "user": {
+ "id": "07fb48ed",
+ "ext": {
+ },
+ "buyeruid": "345"
+ },
+ "regs": {
+ "ext": {
+ "us_privacy": "1"
+ }
+ },
+ "tmax": 200,
+ "ext": {
+ }
+ }
+ ,
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://example.com/bid",
+ "body": {
+ "id": "5f4d1e01",
+ "at": 1,
+ "imp": [
+ {
+ "id": "8b1bdcca",
+ "banner": {
+ "w": 300,
+ "h": 300,
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ],
+ "pos": 0,
+ "expdir": [1,2,3,4,5]
+ },
+ "video": {
+ "mimes": null,
+ "skip":0,
+ "playbackmethod":[2]
+ },
+ "tagid": "73",
+ "secure": 1,
+ "iframebuster": [
+ "ALL"
+ ],
+ "ext": {
+ "adSlotID": "11523"
+ }
+ }
+ ],
+ "site": {
+ "id": "123",
+ "domain": "www.dailymail.co.uk",
+ "cat": ["IAB7"],
+ "page": "https://www.dailymail.co.uk/",
+ "ref": "https://www.dailymail.co.uk/",
+ "mobile": 1,
+ "publisher": {
+ "id": "1"
+ }
+ },
+ "device": {
+ "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.1 Safari/537",
+ "geo": {
+ "ipservice": 4,
+ "country": "US",
+ "region": "CO",
+ "metro": "751",
+ "city": "Ft Collins",
+ "zip": "80524"
+ },
+ "ip": "127.0.0.1",
+ "devicetype": 2,
+ "make": "Apple",
+ "model": "iPhone",
+ "os": "Windows",
+ "osv": "10.0",
+ "carrier": "none",
+ "language": "en",
+ "connectiontype": 2,
+ "dnt": 0
+ },
+ "user": {
+ "id": "07fb48ed",
+ "ext": {
+ },
+ "buyeruid": "345"
+ },
+ "regs": {
+ "ext": {
+ "us_privacy": "1"
+ }
+ },
+ "tmax": 200,
+ "ext": {
+ }
+ }
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "5f4d1e01",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "id": "67sadsac",
+ "impid": "8b1bdcca",
+ "price": 10,
+ "nurl": "http://example.com/win/10",
+ "adm": "ad
",
+ "adomain": ["example.com"],
+ "cid": "test-cid",
+ "crid": "test-crid",
+ "cat": ["IAB13"],
+ "w": 300,
+ "h": 300,
+ "ext": {"mediaType": "video"}
+ }
+ ],
+ "seat": "_b345"
+ }
+ ],
+ "bidid": "67sadsac",
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "67sadsac",
+ "impid": "8b1bdcca",
+ "price": 10,
+ "nurl": "http://example.com/win/10",
+ "adm": "ad
",
+ "adomain": ["example.com"],
+ "cid": "test-cid",
+ "crid": "test-crid",
+ "cat": ["IAB13"],
+ "w": 300,
+ "h": 300,
+ "ext": {"mediaType": "video"}
+ },
+ "type": "video"
+ }
+ ]
+ }
+ ]
+ }
+
\ No newline at end of file
diff --git a/adapters/kargo/kargotest/supplemental/status-bad-request.json b/adapters/kargo/kargotest/supplemental/status-bad-request.json
new file mode 100644
index 00000000000..3cb98431def
--- /dev/null
+++ b/adapters/kargo/kargotest/supplemental/status-bad-request.json
@@ -0,0 +1,36 @@
+{
+ "mockBidRequest": {
+ "id": "5f4d1e01",
+ "at": 1,
+ "imp": [
+ ],
+ "tmax": 200
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://example.com/bid",
+ "body": {
+ "id": "5f4d1e01",
+ "at": 1,
+ "imp": [
+ ],
+ "tmax": 200
+ }
+ },
+ "mockResponse": {
+ "status": 400,
+ "body": {
+ }
+ }
+ }
+ ],
+ "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/kargo/kargotest/supplemental/status-no-content.json b/adapters/kargo/kargotest/supplemental/status-no-content.json
new file mode 100644
index 00000000000..8c6e0544589
--- /dev/null
+++ b/adapters/kargo/kargotest/supplemental/status-no-content.json
@@ -0,0 +1,130 @@
+{
+ "mockBidRequest": {
+ "id": "5f4d1e01",
+ "at": 1,
+ "imp": [
+ {
+ "id": "8b1bdcca",
+ "banner": {
+ "w": 300,
+ "h": 300,
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ],
+ "pos": 0,
+ "expdir": [1, 2, 3, 4, 5]
+ },
+ "video": {
+ "mimes": null
+ },
+ "native": {
+ "request": ""
+ },
+ "pmp": {
+ },
+ "tagid": "73",
+ "secure": 1,
+ "iframebuster": ["ALL"],
+ "ext": {}
+ }
+ ],
+ "site": {
+ "id": "123",
+ "domain": "www.dailymail.co.uk",
+ "cat": ["IAB7"],
+ "page": "https://www.dailymail.co.uk/",
+ "ref": "https://www.dailymail.co.uk/",
+ "mobile": 1,
+ "publisher": {
+ "id": "1"
+ }
+ },
+ "user": {
+ "id": "07fb48ed",
+ "ext": {
+ "consent": "consent opt-out"
+ },
+ "buyeruid": "345"
+ },
+ "regs": {
+ "ext": {
+ "us_privacy": "1"
+ }
+ },
+ "tmax": 200,
+ "ext": {}
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://example.com/bid",
+ "body": {
+ "id": "5f4d1e01",
+ "at": 1,
+ "imp": [
+ {
+ "id": "8b1bdcca",
+ "banner": {
+ "w": 300,
+ "h": 300,
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ }
+ ],
+ "pos": 0,
+ "expdir": [1, 2, 3, 4, 5]
+ },
+ "video": {
+ "mimes": null
+ },
+ "native": {
+ "request": ""
+ },
+ "pmp": {
+ },
+ "tagid": "73",
+ "secure": 1,
+ "iframebuster": ["ALL"],
+ "ext": {}
+ }
+ ],
+ "site": {
+ "id": "123",
+ "domain": "www.dailymail.co.uk",
+ "cat": ["IAB7"],
+ "page": "https://www.dailymail.co.uk/",
+ "ref": "https://www.dailymail.co.uk/",
+ "mobile": 1,
+ "publisher": {
+ "id": "1"
+ }
+ },
+ "user": {
+ "id": "07fb48ed",
+ "ext": {
+ "consent": "consent opt-out"
+ },
+ "buyeruid": "345"
+ },
+ "regs": {
+ "ext": {
+ "us_privacy": "1"
+ }
+ },
+ "tmax": 200,
+ "ext": {}
+ }
+ },
+ "mockResponse": {
+ "status": 204,
+ "body": {}
+ }
+ }
+ ],
+ "expectedBidResponses": []
+}
diff --git a/adapters/kargo/params_test.go b/adapters/kargo/params_test.go
new file mode 100644
index 00000000000..44937637480
--- /dev/null
+++ b/adapters/kargo/params_test.go
@@ -0,0 +1,47 @@
+package kargo
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/prebid/prebid-server/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 schema. %v", err)
+ }
+
+ for _, p := range validParams {
+ if err := validator.Validate(openrtb_ext.BidderKargo, json.RawMessage(p)); err != nil {
+ t.Errorf("Schema rejected valid params: %s", p)
+ }
+ }
+}
+
+func TestInvalidParams(t *testing.T) {
+ validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+ if err != nil {
+ t.Fatalf("Failed to fetch the json schema. %v", err)
+ }
+
+ for _, p := range invalidParams {
+ if err := validator.Validate(openrtb_ext.BidderKargo, json.RawMessage(p)); err == nil {
+ t.Errorf("Schema allowed invalid params: %s", p)
+ }
+ }
+}
+
+var validParams = []string{
+ `{"adSlotID": ""}`,
+ `{"adSlotID": "11523"}`,
+}
+
+var invalidParams = []string{
+ `{"adSlotID": 42}`,
+ `{"adSlotID": }`,
+ `{"adSlotId": "32321"}`,
+ `{"id": }`,
+ `{}`,
+}
diff --git a/config/config.go b/config/config.go
index 0b3bed046e6..2a16c10c219 100644
--- a/config/config.go
+++ b/config/config.go
@@ -887,6 +887,7 @@ func SetupViper(v *viper.Viper, filename string) {
v.SetDefault("adapters.ix.disabled", true)
v.SetDefault("adapters.janet.endpoint", "http://ghb.bidder.jmgads.com/pbs/ortb")
v.SetDefault("adapters.jixie.endpoint", "https://hb.jixie.io/v2/hbsvrpost")
+ v.SetDefault("adapters.kargo.endpoint", "https://krk.kargo.com/api/v1/openrtb")
v.SetDefault("adapters.kayzen.endpoint", "https://bids-{{.ZoneID}}.bidder.kayzen.io/?exchange={{.AccountID}}")
v.SetDefault("adapters.krushmedia.endpoint", "http://ads4.krushmedia.com/?c=rtb&m=req&key={{.AccountID}}")
v.SetDefault("adapters.invibes.endpoint", "https://{{.ZoneID}}.videostep.com/bid/ServerBidAdContent")
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 12d31f0d9e3..48b74f1e822 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -72,6 +72,7 @@ import (
"github.com/prebid/prebid-server/adapters/iqzone"
"github.com/prebid/prebid-server/adapters/ix"
"github.com/prebid/prebid-server/adapters/jixie"
+ "github.com/prebid/prebid-server/adapters/kargo"
"github.com/prebid/prebid-server/adapters/kayzen"
"github.com/prebid/prebid-server/adapters/kidoz"
"github.com/prebid/prebid-server/adapters/krushmedia"
@@ -214,6 +215,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
openrtb_ext.BidderIx: ix.Builder,
openrtb_ext.BidderJANet: adtelligent.Builder,
openrtb_ext.BidderJixie: jixie.Builder,
+ openrtb_ext.BidderKargo: kargo.Builder,
openrtb_ext.BidderKayzen: kayzen.Builder,
openrtb_ext.BidderKidoz: kidoz.Builder,
openrtb_ext.BidderKrushmedia: krushmedia.Builder,
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 524ab5e5a95..f010a0193fd 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -149,6 +149,7 @@ const (
BidderIx BidderName = "ix"
BidderJANet BidderName = "janet"
BidderJixie BidderName = "jixie"
+ BidderKargo BidderName = "kargo"
BidderKayzen BidderName = "kayzen"
BidderKidoz BidderName = "kidoz"
BidderKrushmedia BidderName = "krushmedia"
@@ -297,6 +298,7 @@ func CoreBidderNames() []BidderName {
BidderIx,
BidderJANet,
BidderJixie,
+ BidderKargo,
BidderKayzen,
BidderKidoz,
BidderKrushmedia,
diff --git a/openrtb_ext/imp_kargo.go b/openrtb_ext/imp_kargo.go
new file mode 100644
index 00000000000..682561fb1f0
--- /dev/null
+++ b/openrtb_ext/imp_kargo.go
@@ -0,0 +1,5 @@
+package openrtb_ext
+
+type ImpExtKargo struct {
+ AdSlotID string `json:"adSlotID"`
+}
diff --git a/static/bidder-info/kargo.yaml b/static/bidder-info/kargo.yaml
new file mode 100644
index 00000000000..4acfd254f22
--- /dev/null
+++ b/static/bidder-info/kargo.yaml
@@ -0,0 +1,13 @@
+maintainer:
+ email: "kraken@kargo.com"
+gvlVendorID: 972
+modifyingVastXmlAllowed: true
+capabilities:
+ site:
+ mediaTypes:
+ - banner
+ - video
+ - native
+userSync:
+ supports:
+ - redirect
diff --git a/static/bidder-params/kargo.json b/static/bidder-params/kargo.json
new file mode 100644
index 00000000000..15c11526b7c
--- /dev/null
+++ b/static/bidder-params/kargo.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Kargo Adapter Params",
+ "description": "A schema which validates params accepted by the Kargo adapter",
+ "type": "object",
+
+ "properties": {
+ "adSlotID": {
+ "type": "string",
+ "description": "An ID which identifies the adslot placement. Equivalent to the id of target inventory, ad unit code, or placement id"
+ }
+ },
+
+ "required": ["adSlotID"]
+ }