diff --git a/adapters/avocet/avocet.go b/adapters/avocet/avocet.go
new file mode 100644
index 00000000000..918fc23e894
--- /dev/null
+++ b/adapters/avocet/avocet.go
@@ -0,0 +1,124 @@
+package avocet
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "github.com/mxmCherry/openrtb"
+ "github.com/prebid/prebid-server/adapters"
+ "github.com/prebid/prebid-server/errortypes"
+ "github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// AvocetAdapter implements a adapters.Bidder compatible with the Avocet advertising platform.
+type AvocetAdapter struct {
+ // Endpoint is a http endpoint to use when making requests to the Avocet advertising platform.
+ Endpoint string
+}
+
+func (a *AvocetAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+ if len(request.Imp) == 0 {
+ return nil, nil
+ }
+
+ headers := http.Header{}
+ headers.Add("Content-Type", "application/json;charset=utf-8")
+ headers.Add("Accept", "application/json")
+ body, err := json.Marshal(request)
+ if err != nil {
+ return nil, []error{&errortypes.FailedToRequestBids{
+ Message: err.Error(),
+ }}
+ }
+ reqData := &adapters.RequestData{
+ Method: http.MethodPost,
+ Uri: a.Endpoint,
+ Body: body,
+ Headers: headers,
+ }
+ return []*adapters.RequestData{reqData}, nil
+}
+
+type avocetBidExt struct {
+ Avocet avocetBidExtension `json:"avocet"`
+}
+
+type avocetBidExtension struct {
+ Duration int `json:"duration"`
+ DealPriority int `json:"deal_priority"`
+}
+
+func (a *AvocetAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+
+ if response.StatusCode == http.StatusNoContent {
+ return nil, nil
+ }
+
+ if response.StatusCode != http.StatusOK {
+ var errStr string
+ if len(response.Body) > 0 {
+ errStr = string(response.Body)
+ } else {
+ errStr = "no response body"
+ }
+ return nil, []error{&errortypes.BadServerResponse{
+ Message: fmt.Sprintf("received status code: %v error: %s", response.StatusCode, errStr),
+ }}
+ }
+
+ var br openrtb.BidResponse
+ err := json.Unmarshal(response.Body, &br)
+ if err != nil {
+ return nil, []error{&errortypes.BadServerResponse{
+ Message: err.Error(),
+ }}
+ }
+ var errs []error
+
+ bidResponse := adapters.NewBidderResponseWithBidsCapacity(5)
+ for i := range br.SeatBid {
+ for j := range br.SeatBid[i].Bid {
+ var ext avocetBidExt
+ if len(br.SeatBid[i].Bid[j].Ext) > 0 {
+ err := json.Unmarshal(br.SeatBid[i].Bid[j].Ext, &ext)
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ }
+ tbid := &adapters.TypedBid{
+ Bid: &br.SeatBid[i].Bid[j],
+ DealPriority: ext.Avocet.DealPriority,
+ }
+ tbid.BidType = getBidType(br.SeatBid[i].Bid[j], ext)
+ if tbid.BidType == openrtb_ext.BidTypeVideo {
+ tbid.BidVideo = &openrtb_ext.ExtBidPrebidVideo{
+ Duration: ext.Avocet.Duration,
+ }
+ }
+ bidResponse.Bids = append(bidResponse.Bids, tbid)
+ }
+ }
+ return bidResponse, nil
+}
+
+// getBidType returns the openrtb_ext.BidType for the provided bid.
+func getBidType(bid openrtb.Bid, ext avocetBidExt) openrtb_ext.BidType {
+ if ext.Avocet.Duration != 0 {
+ return openrtb_ext.BidTypeVideo
+ }
+ switch bid.API {
+ case openrtb.APIFrameworkVPAID10, openrtb.APIFrameworkVPAID20:
+ return openrtb_ext.BidTypeVideo
+ default:
+ return openrtb_ext.BidTypeBanner
+ }
+}
+
+// NewAvocetAdapter returns a new AvocetAdapter using the provided endpoint.
+func NewAvocetAdapter(endpoint string) *AvocetAdapter {
+ return &AvocetAdapter{
+ Endpoint: endpoint,
+ }
+}
diff --git a/adapters/avocet/avocet/exemplary/banner.json b/adapters/avocet/avocet/exemplary/banner.json
new file mode 100644
index 00000000000..b5e308ea725
--- /dev/null
+++ b/adapters/avocet/avocet/exemplary/banner.json
@@ -0,0 +1,106 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "placement": "5ea9601ac865f911007f1b6a"
+ }
+ }
+ }
+ ]
+ },
+
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://bid.staging.avct.cloud/ortb/bid/5e722ee9bd6df11d063a8013",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "placement": "5ea9601ac865f911007f1b6a"
+ }
+ }
+ }
+ ]
+ }
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "bidid": "dd87f80c-16a0-43c8-a673-b94b3ea4d417",
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "adm": "",
+ "adomain": ["avocet.io"],
+ "cid": "5b51e2d689654741306813a4",
+ "crid": "5b51e49634f2021f127ff7c9",
+ "h": 250,
+ "id": "bc708396-9202-437b-b726-08b9864cb8b8",
+ "impid": "test-imp-id",
+ "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5b51e49634f2021f127ff7c9.jpeg",
+ "language": "en",
+ "price": 15.64434783,
+ "w": 300
+ }
+ ],
+ "seat": "TEST_SEAT_ID"
+ }
+ ]
+ }
+ }
+ }
+ ],
+
+ "expectedBids": [
+ {
+ "bid": {
+ "adm": "",
+ "adomain": ["avocet.io"],
+ "cid": "5b51e2d689654741306813a4",
+ "crid": "5b51e49634f2021f127ff7c9",
+ "h": 250,
+ "id": "bc708396-9202-437b-b726-08b9864cb8b8",
+ "impid": "test-imp-id",
+ "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5b51e49634f2021f127ff7c9.jpeg",
+ "language": "en",
+ "price": 15.64434783,
+ "w": 300
+ },
+ "type": "banner"
+ }
+ ]
+}
diff --git a/adapters/avocet/avocet/exemplary/video.json b/adapters/avocet/avocet/exemplary/video.json
new file mode 100644
index 00000000000..2398256b0dd
--- /dev/null
+++ b/adapters/avocet/avocet/exemplary/video.json
@@ -0,0 +1,104 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": ["video/mp4"],
+ "protocols": [2, 5],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "placement": "5ea9601ac865f911007f1b6a"
+ }
+ }
+ }
+ ]
+ },
+
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "https://bid.staging.avct.cloud/ortb/bid/5e722ee9bd6df11d063a8013",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "video": {
+ "mimes": ["video/mp4"],
+ "protocols": [2, 5],
+ "w": 1920,
+ "h": 1080
+ },
+ "ext": {
+ "bidder": {
+ "placement": "5ea9601ac865f911007f1b6a"
+ }
+ }
+ }
+ ]
+ }
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "bidid": "a0eec3aa-f9f6-42fb-9aa4-f1b5656d4f42",
+ "id": "749d36d7-c993-455f-aefd-ffd8a7e3ccf",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "adm": "Avocet",
+ "adomain": ["avocet.io"],
+ "cid": "5b51e2d689654741306813a4",
+ "crid": "5ec530e32d57fe1100f17d87",
+ "h": 396,
+ "id": "3d4c2d45-5a8c-43b8-9e15-4f48ac45204f",
+ "impid": "dfp-ad--top-above-nav",
+ "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5ec530e32d57fe1100f17d87.jpeg",
+ "language": "en",
+ "price": 15.64434783,
+ "w": 600,
+ "ext": {
+ "avocet": {
+ "duration": 30
+ }
+ }
+ }
+ ],
+ "seat": "TEST_SEAT_ID"
+ }
+ ]
+ }
+ }
+ }
+ ],
+
+ "expectedBids": [
+ {
+ "bid": {
+ "adm": "Avocet",
+ "adomain": ["avocet.io"],
+ "cid": "5b51e2d689654741306813a4",
+ "crid": "5ec530e32d57fe1100f17d87",
+ "h": 396,
+ "id": "3d4c2d45-5a8c-43b8-9e15-4f48ac45204f",
+ "impid": "dfp-ad--top-above-nav",
+ "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5ec530e32d57fe1100f17d87.jpeg",
+ "language": "en",
+ "price": 15.64434783,
+ "w": 600,
+ "ext": {
+ "avocet": {
+ "duration": 30
+ }
+ }
+ },
+ "type": "video"
+ }
+ ]
+}
diff --git a/adapters/avocet/avocet_test.go b/adapters/avocet/avocet_test.go
new file mode 100644
index 00000000000..ff2159bf406
--- /dev/null
+++ b/adapters/avocet/avocet_test.go
@@ -0,0 +1,301 @@
+package avocet
+
+import (
+ "encoding/json"
+ "net/http"
+ "reflect"
+ "testing"
+
+ "github.com/mxmCherry/openrtb"
+ "github.com/prebid/prebid-server/adapters"
+ "github.com/prebid/prebid-server/adapters/adapterstest"
+ "github.com/prebid/prebid-server/errortypes"
+ "github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestJsonSamples(t *testing.T) {
+ adapterstest.RunJSONBidderTest(t, "avocet", NewAvocetAdapter("https://bid.staging.avct.cloud/ortb/bid/5e722ee9bd6df11d063a8013"))
+}
+
+func TestAvocetAdapter_MakeRequests(t *testing.T) {
+ type fields struct {
+ Endpoint string
+ }
+ type args struct {
+ request *openrtb.BidRequest
+ reqInfo *adapters.ExtraRequestInfo
+ }
+ type reqData []*adapters.RequestData
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ want []*adapters.RequestData
+ wantErrs []error
+ }{
+ {
+ name: "return nil if zero imps",
+ fields: fields{Endpoint: "https://bid.avct.cloud"},
+ args: args{
+ &openrtb.BidRequest{},
+ nil,
+ },
+ want: nil,
+ wantErrs: nil,
+ },
+ {
+ name: "makes POST request with JSON content",
+ fields: fields{Endpoint: "https://bid.avct.cloud"},
+ args: args{
+ &openrtb.BidRequest{Imp: []openrtb.Imp{{}}},
+ nil,
+ },
+ want: reqData{
+ &adapters.RequestData{
+ Method: http.MethodPost,
+ Uri: "https://bid.avct.cloud",
+ Body: []byte(`{"id":"","imp":[{"id":""}]}`),
+ Headers: map[string][]string{
+ "Accept": {"application/json"},
+ "Content-Type": {"application/json;charset=utf-8"},
+ },
+ },
+ },
+ wantErrs: nil,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ a := &AvocetAdapter{
+ Endpoint: tt.fields.Endpoint,
+ }
+ got, got1 := a.MakeRequests(tt.args.request, tt.args.reqInfo)
+ if len(got) != len(tt.want) {
+ t.Errorf("AvocetAdapter.MakeRequests() got %v requests, wanted %v requests", len(got), len(tt.want))
+ }
+ if len(got) == len(tt.want) {
+ for i := range tt.want {
+ if !reflect.DeepEqual(got[i], tt.want[i]) {
+ t.Errorf("AvocetAdapter.MakeRequests() got = %v, want %v", got[i], tt.want[i])
+ }
+ }
+ }
+ if !reflect.DeepEqual(got1, tt.wantErrs) {
+ t.Errorf("AvocetAdapter.MakeRequests() got1 = %v, want %v", got1, tt.wantErrs)
+ }
+ })
+ }
+}
+
+func TestAvocetAdapter_MakeBids(t *testing.T) {
+ type fields struct {
+ Endpoint string
+ }
+ type args struct {
+ internalRequest *openrtb.BidRequest
+ externalRequest *adapters.RequestData
+ response *adapters.ResponseData
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ want *adapters.BidderResponse
+ errs []error
+ }{
+ {
+ name: "204 No Content indicates no bids",
+ fields: fields{Endpoint: "https://bid.avct.cloud"},
+ args: args{
+ nil,
+ nil,
+ &adapters.ResponseData{StatusCode: http.StatusNoContent},
+ },
+ want: nil,
+ errs: nil,
+ },
+ {
+ name: "Non-200 return error",
+ fields: fields{Endpoint: "https://bid.avct.cloud"},
+ args: args{
+ nil,
+ nil,
+ &adapters.ResponseData{StatusCode: http.StatusBadRequest, Body: []byte("message")},
+ },
+ want: nil,
+ errs: []error{&errortypes.BadServerResponse{Message: "received status code: 400 error: message"}},
+ },
+ {
+ name: "200 response containing banner bids",
+ fields: fields{Endpoint: "https://bid.avct.cloud"},
+ args: args{
+ nil,
+ nil,
+ &adapters.ResponseData{StatusCode: http.StatusOK, Body: validBannerBidResponseBody},
+ },
+ want: &adapters.BidderResponse{
+ Currency: "USD",
+ Bids: []*adapters.TypedBid{
+ {
+ Bid: &validBannerBid,
+ BidType: openrtb_ext.BidTypeBanner,
+ },
+ },
+ },
+ errs: nil,
+ },
+ {
+ name: "200 response containing video bids",
+ fields: fields{Endpoint: "https://bid.avct.cloud"},
+ args: args{
+ nil,
+ nil,
+ &adapters.ResponseData{StatusCode: http.StatusOK, Body: validVideoBidResponseBody},
+ },
+ want: &adapters.BidderResponse{
+ Currency: "USD",
+ Bids: []*adapters.TypedBid{
+ {
+ Bid: &validVideoBid,
+ BidType: openrtb_ext.BidTypeVideo,
+ BidVideo: &openrtb_ext.ExtBidPrebidVideo{
+ Duration: 30,
+ },
+ },
+ },
+ },
+ errs: nil,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ a := &AvocetAdapter{
+ Endpoint: tt.fields.Endpoint,
+ }
+ got, got1 := a.MakeBids(tt.args.internalRequest, tt.args.externalRequest, tt.args.response)
+ if !reflect.DeepEqual(got, tt.want) {
+ gotb, _ := json.Marshal(got)
+ wantb, _ := json.Marshal(tt.want)
+ t.Errorf("AvocetAdapter.MakeBids() got = %s, want %s", string(gotb), string(wantb))
+ }
+ if !reflect.DeepEqual(got1, tt.errs) {
+ t.Errorf("AvocetAdapter.MakeBids() got1 = %v, want %v", got1, tt.errs)
+ }
+ })
+ }
+}
+
+func Test_getBidType(t *testing.T) {
+ type args struct {
+ bid openrtb.Bid
+ ext avocetBidExt
+ }
+ tests := []struct {
+ name string
+ args args
+ want openrtb_ext.BidType
+ }{
+ {
+ name: "VPAID 1.0",
+ args: args{openrtb.Bid{API: openrtb.APIFrameworkVPAID10}, avocetBidExt{}},
+ want: openrtb_ext.BidTypeVideo,
+ },
+ {
+ name: "VPAID 2.0",
+ args: args{openrtb.Bid{API: openrtb.APIFrameworkVPAID20}, avocetBidExt{}},
+ want: openrtb_ext.BidTypeVideo,
+ },
+ {
+ name: "other",
+ args: args{openrtb.Bid{}, avocetBidExt{}},
+ want: openrtb_ext.BidTypeBanner,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := getBidType(tt.args.bid, tt.args.ext); !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("getBidType() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+var validBannerBid = openrtb.Bid{
+ AdM: "",
+ ADomain: []string{"avocet.io"},
+ CID: "5b51e2d689654741306813a4",
+ CrID: "5b51e49634f2021f127ff7c9",
+ H: 250,
+ ID: "bc708396-9202-437b-b726-08b9864cb8b8",
+ ImpID: "test-imp-id",
+ IURL: "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5b51e49634f2021f127ff7c9.jpeg",
+ Language: "en",
+ Price: 15.64434783,
+ W: 300,
+}
+
+var validBannerBidResponseBody = []byte(`{
+ "bidid": "dd87f80c-16a0-43c8-a673-b94b3ea4d417",
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "adm": "",
+ "adomain": ["avocet.io"],
+ "cid": "5b51e2d689654741306813a4",
+ "crid": "5b51e49634f2021f127ff7c9",
+ "h": 250,
+ "id": "bc708396-9202-437b-b726-08b9864cb8b8",
+ "impid": "test-imp-id",
+ "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5b51e49634f2021f127ff7c9.jpeg",
+ "language": "en",
+ "price": 15.64434783,
+ "w": 300
+ }
+ ],
+ "seat": "TEST_SEAT_ID"
+ }
+ ]
+}`)
+
+var validVideoBid = openrtb.Bid{
+ AdM: "Avocet",
+ ADomain: []string{"avocet.io"},
+ CID: "5b51e2d689654741306813a4",
+ CrID: "5ec530e32d57fe1100f17d87",
+ H: 396,
+ ID: "3d4c2d45-5a8c-43b8-9e15-4f48ac45204f",
+ ImpID: "dfp-ad--top-above-nav",
+ IURL: "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5ec530e32d57fe1100f17d87.jpeg",
+ Language: "en",
+ Price: 15.64434783,
+ W: 600,
+ Ext: []byte(`{"avocet":{"duration":30}}`),
+}
+
+var validVideoBidResponseBody = []byte(`{
+ "bidid": "dd87f80c-16a0-43c8-a673-b94b3ea4d417",
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "bid": [
+ {
+ "adm": "Avocet",
+ "adomain": ["avocet.io"],
+ "cid": "5b51e2d689654741306813a4",
+ "crid": "5ec530e32d57fe1100f17d87",
+ "h": 396,
+ "id": "3d4c2d45-5a8c-43b8-9e15-4f48ac45204f",
+ "impid": "dfp-ad--top-above-nav",
+ "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5ec530e32d57fe1100f17d87.jpeg",
+ "language": "en",
+ "price": 15.64434783,
+ "w": 600,
+ "ext": {"avocet":{"duration":30}}
+ }
+ ],
+ "seat": "TEST_SEAT_ID"
+ }
+ ]
+}`)
diff --git a/adapters/avocet/usersync.go b/adapters/avocet/usersync.go
new file mode 100644
index 00000000000..f1075ab3c52
--- /dev/null
+++ b/adapters/avocet/usersync.go
@@ -0,0 +1,12 @@
+package avocet
+
+import (
+ "text/template"
+
+ "github.com/prebid/prebid-server/adapters"
+ "github.com/prebid/prebid-server/usersync"
+)
+
+func NewAvocetSyncer(temp *template.Template) usersync.Usersyncer {
+ return adapters.NewSyncer("avocet", 63, temp, adapters.SyncTypeRedirect)
+}
diff --git a/adapters/avocet/usersync_test.go b/adapters/avocet/usersync_test.go
new file mode 100644
index 00000000000..8fba403f1b1
--- /dev/null
+++ b/adapters/avocet/usersync_test.go
@@ -0,0 +1,35 @@
+package avocet
+
+import (
+ "testing"
+ "text/template"
+
+ "github.com/prebid/prebid-server/privacy"
+ "github.com/prebid/prebid-server/privacy/ccpa"
+ "github.com/prebid/prebid-server/privacy/gdpr"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAvocetSyncer(t *testing.T) {
+ syncURL := "https://ads.avct.cloud/getuid?&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url=%2Fsetuid%3Fbidder%3Davocet%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7B%7BUUID%7D%7D"
+ syncURLTemplate := template.Must(
+ template.New("sync-template").Parse(syncURL),
+ )
+
+ syncer := NewAvocetSyncer(syncURLTemplate)
+ syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{
+ GDPR: gdpr.Policy{
+ Signal: "1",
+ Consent: "ConsentString",
+ },
+ CCPA: ccpa.Policy{
+ Value: "PrivacyString",
+ },
+ })
+
+ assert.NoError(t, err)
+ assert.Equal(t, "https://ads.avct.cloud/getuid?&gdpr=1&gdpr_consent=ConsentString&us_privacy=PrivacyString&url=%2Fsetuid%3Fbidder%3Davocet%26gdpr%3D1%26gdpr_consent%3DConsentString%26uid%3D%7B%7BUUID%7D%7D", syncInfo.URL)
+ assert.Equal(t, "redirect", syncInfo.Type)
+ assert.EqualValues(t, 63, syncer.GDPRVendorID())
+ assert.Equal(t, false, syncInfo.SupportCORS)
+}
diff --git a/config/config.go b/config/config.go
index 0f470c6a611..01de9b1ab2e 100755
--- a/config/config.go
+++ b/config/config.go
@@ -567,6 +567,7 @@ func (cfg *Configuration) setDerivedDefaults() {
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAdvangelists, "https://nep.advangelists.com/xp/user-sync?acctid={aid}&&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadvangelists%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAJA, "https://ad.as.amanad.adtdp.com/v1/sync/ssp?ssp=4&gdpr={{.GDPR}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Daja%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%25s")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAppnexus, "https://ib.adnxs.com/getuid?"+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadnxs%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
+ setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAvocet, "https://ads.avct.cloud/getuid?&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Davocet%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7B%7BUUID%7D%7D")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeachfront, "https://sync.bfmio.com/sync_s2s?gdpr={{.GDPR}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeachfront%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5Bio_cid%5D")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeintoo, "https://ib.beintoo.com/um?ssp=pbs&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeintoo%26uid%3D%24UID")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBrightroll, "https://pr-bh.ybp.yahoo.com/sync/appnexusprebidserver/?gdpr={{.GDPR}}&euconsent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbrightroll%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
@@ -772,6 +773,7 @@ func SetupViper(v *viper.Viper, filename string) {
v.SetDefault("adapters.applogy.endpoint", "http://rtb.applogy.com/v1/prebid")
v.SetDefault("adapters.appnexus.endpoint", "http://ib.adnxs.com/openrtb2") // Docs: https://wiki.appnexus.com/display/supply/Incoming+Bid+Request+from+SSPs
v.SetDefault("adapters.appnexus.platform_id", "5")
+ v.SetDefault("adapters.avocet.disabled", true)
v.SetDefault("adapters.beachfront.endpoint", "https://display.bfmio.com/prebid_display")
v.SetDefault("adapters.beachfront.extra_info", "{\"video_endpoint\":\"https://reachms.bfmio.com/bid.json?exchange_id\"}")
v.SetDefault("adapters.beintoo.endpoint", "https://ib.beintoo.com/um")
diff --git a/docs/bidders/avocet.md b/docs/bidders/avocet.md
new file mode 100644
index 00000000000..6aa67391af4
--- /dev/null
+++ b/docs/bidders/avocet.md
@@ -0,0 +1,5 @@
+# Avocet Bidder
+
+Please contact Avocet at info@avocet.io if you would like to get started selling inventory via the Avocet platform.
+
+**Note:** Avocet is disabled by default. Please enable it in the app config if you wish to use it. This can be done by setting `adapters.avocet.disabled` to `false` and by setting `adapters.avocet.endpoint` to a valid Avocet endpoint url.
\ No newline at end of file
diff --git a/exchange/adapter_map.go b/exchange/adapter_map.go
index 2ea8f7fb648..6e771236fb7 100755
--- a/exchange/adapter_map.go
+++ b/exchange/adapter_map.go
@@ -25,6 +25,7 @@ import (
"github.com/prebid/prebid-server/adapters/applogy"
"github.com/prebid/prebid-server/adapters/appnexus"
"github.com/prebid/prebid-server/adapters/audienceNetwork"
+ "github.com/prebid/prebid-server/adapters/avocet"
"github.com/prebid/prebid-server/adapters/beachfront"
"github.com/prebid/prebid-server/adapters/beintoo"
"github.com/prebid/prebid-server/adapters/brightroll"
@@ -106,6 +107,7 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter
openrtb_ext.BidderAJA: aja.NewAJABidder(cfg.Adapters[string(openrtb_ext.BidderAJA)].Endpoint),
openrtb_ext.BidderApplogy: applogy.NewApplogyBidder(cfg.Adapters[string(openrtb_ext.BidderApplogy)].Endpoint),
openrtb_ext.BidderAppnexus: appnexus.NewAppNexusBidder(client, cfg.Adapters[string(openrtb_ext.BidderAppnexus)].Endpoint, cfg.Adapters[string(openrtb_ext.BidderAppnexus)].PlatformID),
+ openrtb_ext.BidderAvocet: avocet.NewAvocetAdapter(cfg.Adapters[string(openrtb_ext.BidderAvocet)].Endpoint),
openrtb_ext.BidderBeachfront: beachfront.NewBeachfrontBidder(cfg.Adapters[string(openrtb_ext.BidderBeachfront)].Endpoint, cfg.Adapters[string(openrtb_ext.BidderBeachfront)].ExtraAdapterInfo),
openrtb_ext.BidderBeintoo: beintoo.NewBeintooBidder(cfg.Adapters[string(openrtb_ext.BidderBeintoo)].Endpoint),
openrtb_ext.BidderBrightroll: brightroll.NewBrightrollBidder(cfg.Adapters[string(openrtb_ext.BidderBrightroll)].Endpoint),
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 659c6616fea..416f36d135f 100755
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -40,6 +40,7 @@ const (
BidderApplogy BidderName = "applogy"
BidderAppnexus BidderName = "appnexus"
BidderAdoppler BidderName = "adoppler"
+ BidderAvocet BidderName = "avocet"
BidderBeachfront BidderName = "beachfront"
BidderBeintoo BidderName = "beintoo"
BidderBrightroll BidderName = "brightroll"
@@ -118,6 +119,7 @@ var BidderMap = map[string]BidderName{
"applogy": BidderApplogy,
"appnexus": BidderAppnexus,
"adoppler": BidderAdoppler,
+ "avocet": BidderAvocet,
"beachfront": BidderBeachfront,
"beintoo": BidderBeintoo,
"brightroll": BidderBrightroll,
diff --git a/openrtb_ext/imp_avocet.go b/openrtb_ext/imp_avocet.go
new file mode 100644
index 00000000000..7c9ca8c6eed
--- /dev/null
+++ b/openrtb_ext/imp_avocet.go
@@ -0,0 +1,7 @@
+package openrtb_ext
+
+// ExtImpAvocet defines the contract for bidrequest.imp[i].ext.avocet
+type ExtImpAvocet struct {
+ Placement string `json:"placement,omitempty"`
+ PlacementCode string `json:"placement_code,omitempty"`
+}
diff --git a/static/bidder-info/avocet.yaml b/static/bidder-info/avocet.yaml
new file mode 100644
index 00000000000..ea98982d69c
--- /dev/null
+++ b/static/bidder-info/avocet.yaml
@@ -0,0 +1,11 @@
+maintainer:
+ email: "developers@avocet.io"
+capabilities:
+ app:
+ mediaTypes:
+ - banner
+ - video
+ site:
+ mediaTypes:
+ - banner
+ - video
diff --git a/static/bidder-params/avocet.json b/static/bidder-params/avocet.json
new file mode 100644
index 00000000000..f27e5950f7c
--- /dev/null
+++ b/static/bidder-params/avocet.json
@@ -0,0 +1,24 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Avocet Adapter Params",
+ "description": "A schema which validates params accepted by the Avocet adapter",
+ "type": "object",
+ "properties": {
+ "placement": {
+ "type": "string",
+ "description": "An Avocet placement ID"
+ },
+ "placement_code": {
+ "type": "string",
+ "description": "An Avocet placement external code"
+ }
+ },
+ "oneOf": [
+ {
+ "required": ["placement"]
+ },
+ {
+ "required": ["placement_code"]
+ }
+ ]
+}
diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go
index 751d2aabfbe..1beb9d586df 100755
--- a/usersync/usersyncers/syncer.go
+++ b/usersync/usersyncers/syncer.go
@@ -18,6 +18,7 @@ import (
"github.com/prebid/prebid-server/adapters/aja"
"github.com/prebid/prebid-server/adapters/appnexus"
"github.com/prebid/prebid-server/adapters/audienceNetwork"
+ "github.com/prebid/prebid-server/adapters/avocet"
"github.com/prebid/prebid-server/adapters/beachfront"
"github.com/prebid/prebid-server/adapters/beintoo"
"github.com/prebid/prebid-server/adapters/brightroll"
@@ -90,6 +91,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
insertIntoMap(cfg, syncers, openrtb_ext.BidderAdvangelists, advangelists.NewAdvangelistsSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderAJA, aja.NewAJASyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderAppnexus, appnexus.NewAppnexusSyncer)
+ insertIntoMap(cfg, syncers, openrtb_ext.BidderAvocet, avocet.NewAvocetSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderBeachfront, beachfront.NewBeachfrontSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderBeintoo, beintoo.NewBeintooSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderBrightroll, brightroll.NewBrightrollSyncer)
diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go
index c9ef382fc92..69751dd55f4 100755
--- a/usersync/usersyncers/syncer_test.go
+++ b/usersync/usersyncers/syncer_test.go
@@ -26,6 +26,7 @@ func TestNewSyncerMap(t *testing.T) {
string(openrtb_ext.BidderAdvangelists): syncConfig,
string(openrtb_ext.BidderAJA): syncConfig,
string(openrtb_ext.BidderAppnexus): syncConfig,
+ string(openrtb_ext.BidderAvocet): syncConfig,
string(openrtb_ext.BidderBeachfront): syncConfig,
string(openrtb_ext.BidderBeintoo): syncConfig,
string(openrtb_ext.BidderBrightroll): syncConfig,