diff --git a/adapters/revx/revx.go b/adapters/revx/revx.go
new file mode 100644
index 00000000000..e18c23b5602
--- /dev/null
+++ b/adapters/revx/revx.go
@@ -0,0 +1,115 @@
+package revx
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/prebid/openrtb/v20/openrtb2"
+ "github.com/prebid/prebid-server/v3/adapters"
+ "github.com/prebid/prebid-server/v3/config"
+ "github.com/prebid/prebid-server/v3/errortypes"
+ "github.com/prebid/prebid-server/v3/openrtb_ext"
+ "github.com/prebid/prebid-server/v3/util/jsonutil"
+)
+
+// RevXAdapter struct
+type adapter struct {
+ endPoint string
+}
+
+// Builder builds a new instance of the RevX adapter.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
+ return &adapter{
+ endPoint: config.Endpoint, // Default endpoint
+ }, nil
+}
+
+// MakeRequests handles the OpenRTB bid request and returns адаптер.RequestData
+func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+ var errors []error
+
+ // Build headers
+ headers := http.Header{}
+ headers.Add("Content-Type", "application/json;charset=utf-8")
+ headers.Add("Accept", "application/json")
+
+ // Marshal request
+ reqJson, err := jsonutil.Marshal(request)
+ if err != nil {
+ return nil, []error{&errortypes.BadInput{Message: fmt.Sprintf("Failed to marshal request: %s", err)}} // skip append
+ }
+
+ requestData := &adapters.RequestData{
+ Method: http.MethodPost,
+ Uri: a.endPoint,
+ Body: reqJson,
+ Headers: headers,
+ ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
+ }
+
+ return []*adapters.RequestData{requestData}, errors
+}
+
+// MakeBids handles the OpenRTB bid response.
+func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+ if externalRequest == nil {
+ return nil, nil
+ }
+
+ // Handle specific status codes first
+ if adapters.IsResponseStatusCodeNoContent(response) {
+ return nil, nil
+ }
+
+ // For all other status codes
+ if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil {
+ return nil, []error{err}
+ }
+
+ // Proceed with normal parsing
+ var serverBidResponse openrtb2.BidResponse
+ if err := jsonutil.Unmarshal(response.Body, &serverBidResponse); err != nil {
+ return nil, []error{err}
+ }
+
+ var typedBids []*adapters.TypedBid
+ var errs []error
+ for _, sb := range serverBidResponse.SeatBid {
+ for i := range sb.Bid {
+ mediaType, err := getMediaTypeForImp(sb.Bid[i])
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ typedBids = append(typedBids, &adapters.TypedBid{
+ Bid: &sb.Bid[i],
+ BidType: mediaType,
+ })
+ }
+ }
+
+ if len(typedBids) == 0 {
+ return nil, errs
+ }
+
+ bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(typedBids))
+ bidResponse.Bids = typedBids
+ bidResponse.Currency = serverBidResponse.Cur
+
+ return bidResponse, errs
+}
+
+func getMediaTypeForImp(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
+ switch bid.MType {
+ case openrtb2.MarkupBanner:
+ return openrtb_ext.BidTypeBanner, nil
+ case openrtb2.MarkupVideo:
+ return openrtb_ext.BidTypeVideo, nil
+ case openrtb2.MarkupNative:
+ return openrtb_ext.BidTypeNative, nil
+ default:
+ return "", &errortypes.BadServerResponse{
+ Message: fmt.Sprintf("Unsupported mtype %d for bid %s", bid.MType, bid.ID),
+ }
+ }
+}
diff --git a/adapters/revx/revx_external_null_test.go b/adapters/revx/revx_external_null_test.go
new file mode 100644
index 00000000000..0b3f5ed32f3
--- /dev/null
+++ b/adapters/revx/revx_external_null_test.go
@@ -0,0 +1,35 @@
+package revx_test
+
+import (
+ "testing"
+
+ "github.com/prebid/openrtb/v20/openrtb2"
+ "github.com/prebid/prebid-server/v3/adapters"
+ "github.com/prebid/prebid-server/v3/adapters/revx"
+ "github.com/prebid/prebid-server/v3/config"
+ "github.com/prebid/prebid-server/v3/openrtb_ext"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestMakeBids_NilExternalRequest(t *testing.T) {
+ // Arrange
+ bidder, buildErr := revx.Builder(openrtb_ext.BidderRevX, config.Adapter{
+ Endpoint: "prebid-use.atomex.net/ag=PUB123",
+ }, config.Server{
+ ExternalUrl: "http://hosturl.com",
+ GvlID: 375,
+ DataCenter: "2",
+ })
+
+ var internalReq *openrtb2.BidRequest
+ var response *adapters.ResponseData
+ if buildErr != nil {
+ t.Logf("RevX Builder created successfully: %+v", bidder)
+ }
+ // Act
+ bidderResponse, errs := bidder.MakeBids(internalReq, nil, response)
+
+ // Assert
+ assert.Nil(t, bidderResponse, "Expected bidderResponse to be nil when externalRequest is nil")
+ assert.Nil(t, errs, "Expected errors to be nil when externalRequest is nil")
+}
diff --git a/adapters/revx/revx_test.go b/adapters/revx/revx_test.go
new file mode 100644
index 00000000000..68275877cea
--- /dev/null
+++ b/adapters/revx/revx_test.go
@@ -0,0 +1,27 @@
+package revx_test
+
+import (
+ "testing"
+
+ "github.com/prebid/prebid-server/v3/adapters/adapterstest"
+ "github.com/prebid/prebid-server/v3/adapters/revx"
+ "github.com/prebid/prebid-server/v3/config"
+ "github.com/prebid/prebid-server/v3/openrtb_ext"
+)
+
+func TestJsonSamples(t *testing.T) {
+ bidder, buildErr := revx.Builder(openrtb_ext.BidderRevX, config.Adapter{
+ Endpoint: "prebid-use.atomex.net/ag=PUB123",
+ }, config.Server{
+ ExternalUrl: "http://hosturl.com",
+ GvlID: 375,
+ DataCenter: "2",
+ })
+
+ if buildErr != nil {
+
+ t.Logf("RevX Builder created successfully: %+v", bidder)
+ }
+
+ adapterstest.RunJSONBidderTest(t, "revxtest", bidder)
+}
diff --git a/adapters/revx/revxtest/exemplary/simple-app-banner.json b/adapters/revx/revxtest/exemplary/simple-app-banner.json
new file mode 100644
index 00000000000..f36257ec3ac
--- /dev/null
+++ b/adapters/revx/revxtest/exemplary/simple-app-banner.json
@@ -0,0 +1,109 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "site": {
+ "page": "https://good.site/url"
+ },
+ "imp": [
+ {
+ "id": "imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 111,
+ "h": 111
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "pubname": "PUB123"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "prebid-use.atomex.net/ag=PUB123",
+
+ "body": {
+ "id": "test-request-id",
+ "site": {
+ "page": "https://good.site/url"
+ },
+ "imp": [
+ {
+ "id": "imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 111,
+ "h": 111
+ }
+ ]
+ },
+ "ext": {
+ "bidder": {
+ "pubname": "PUB123"
+ }
+ }
+ }
+ ]
+ },
+ "impIDs": [
+ "imp-id"
+ ]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "seat": "interactiveoffers",
+ "bid": [
+ {
+ "id": "randomid",
+ "impid": "imp-id",
+ "price": 0.5,
+ "adid": "12345678",
+ "adm": "some-test-ad",
+ "cid": "987",
+ "crid": "12345678",
+ "h": 111,
+ "w": 111,
+ "mtype": 1
+ }
+ ]
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "randomid",
+ "impid": "imp-id",
+ "price": 0.5,
+ "adm": "some-test-ad",
+ "adid": "12345678",
+ "cid": "987",
+ "crid": "12345678",
+ "w": 111,
+ "h": 111,
+ "mtype": 1
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/revx/revxtest/exemplary/simple-app-native.json b/adapters/revx/revxtest/exemplary/simple-app-native.json
new file mode 100644
index 00000000000..81c77915a25
--- /dev/null
+++ b/adapters/revx/revxtest/exemplary/simple-app-native.json
@@ -0,0 +1,99 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "app": {
+ "publisher": {
+ "name": "PUB123"
+ }
+ },
+ "imp": [
+ {
+ "id": "imp-id",
+ "native": {
+ "request": "{\"native\":{\"ver\":\"1.2\",\"api\":[1],\"battr\":[1,3,9],\"assets\":[{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"id\":1,\"required\":1,\"img\":{\"type\":3,\"wmin\":100,\"hmin\":50}},{\"id\":2,\"required\":0,\"data\":{\"type\":2,\"len\":200}},{\"id\":3,\"required\":0,\"data\":{\"type\":12}},{\"id\":4,\"required\":0,\"data\":{\"type\":1}}]}}"
+ },
+ "ext": {
+ "bidder": {
+ "pubname": "PUB123"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "prebid-use.atomex.net/ag=PUB123",
+ "body": {
+ "id": "test-request-id",
+ "app": {
+ "publisher": {
+ "name": "PUB123"
+ }
+ },
+ "imp": [
+ {
+ "id": "imp-id",
+ "native": {
+ "request": "{\"native\":{\"ver\":\"1.2\",\"api\":[1],\"battr\":[1,3,9],\"assets\":[{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"id\":1,\"required\":1,\"img\":{\"type\":3,\"wmin\":100,\"hmin\":50}},{\"id\":2,\"required\":0,\"data\":{\"type\":2,\"len\":200}},{\"id\":3,\"required\":0,\"data\":{\"type\":12}},{\"id\":4,\"required\":0,\"data\":{\"type\":1}}]}}"
+ },
+ "ext": {
+ "bidder": {
+ "pubname": "PUB123"
+ }
+ }
+ }
+ ]
+ },
+ "impIDs": [
+ "imp-id"
+ ]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "seat": "interactiveoffers",
+ "bid": [
+ {
+ "id": "randomid",
+ "impid": "imp-id",
+ "price": 0.5,
+ "adid": "12345678",
+ "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"title\":{\"text\":\"Test Title\"}},{\"id\":1,\"img\":{\"url\":\"http://some.image.url\",\"w\":100,\"h\":50}},{\"id\":2,\"data\":{\"type\":2,\"value\":\"Test Body\"}},{\"id\":3,\"data\":{\"type\":12,\"value\":\"Test Sponsored\"}},{\"id\":4,\"data\":{\"type\":1,\"value\":\"Test Display URL\"}}],\"link\":{\"url\":\"http://click.url\"},\"imptrackers\":[\"http://impression.url\"]}}",
+ "cid": "987",
+ "crid": "12345678",
+ "mtype": 4
+
+ }
+ ]
+ }
+ ],
+ "cur": "USD"
+ }
+ }
+ }
+ ],
+ "expectedBidResponses": [
+ {
+ "currency": "USD",
+ "bids": [
+ {
+ "bid": {
+ "id": "randomid",
+ "impid": "imp-id",
+ "price": 0.5,
+ "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"title\":{\"text\":\"Test Title\"}},{\"id\":1,\"img\":{\"url\":\"http://some.image.url\",\"w\":100,\"h\":50}},{\"id\":2,\"data\":{\"type\":2,\"value\":\"Test Body\"}},{\"id\":3,\"data\":{\"type\":12,\"value\":\"Test Sponsored\"}},{\"id\":4,\"data\":{\"type\":1,\"value\":\"Test Display URL\"}}],\"link\":{\"url\":\"http://click.url\"},\"imptrackers\":[\"http://impression.url\"]}}",
+ "adid": "12345678",
+ "cid": "987",
+ "crid": "12345678",
+ "mtype": 4
+ },
+ "type": "native"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/adapters/revx/revxtest/exemplary/simple-app-video.json b/adapters/revx/revxtest/exemplary/simple-app-video.json
new file mode 100644
index 00000000000..6db4f7abcf9
--- /dev/null
+++ b/adapters/revx/revxtest/exemplary/simple-app-video.json
@@ -0,0 +1,122 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "app": {
+ "publisher": {
+ "name": "PUB123"
+ }
+ },
+ "imp": [
+ {
+ "id": "imp-id",
+ "video": {
+ "mimes": [
+ "application/x-mpegURL",
+ "video/mp4"
+ ],
+ "protocols": [
+ 2,
+ 5
+ ],
+ "w": 640,
+ "h": 480,
+ "placement": 1
+ },
+ "ext": {
+ "bidder": {
+ "pubname": "PUB123"
+ }
+ }
+ }
+ ]
+ },
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "prebid-use.atomex.net/ag=PUB123",
+ "body": {
+ "id": "test-request-id",
+ "app": {
+ "publisher": {
+ "name": "PUB123"
+ }
+ },
+ "imp": [
+ {
+ "id": "imp-id",
+ "video": {
+ "mimes": [
+ "application/x-mpegURL",
+ "video/mp4"
+ ],
+ "protocols": [
+ 2,
+ 5
+ ],
+ "w": 640,
+ "h": 480,
+ "placement": 1
+ },
+ "ext": {
+ "bidder": {
+ "pubname": "PUB123"
+ }
+ }
+ }
+ ]
+ },
+ "impIDs": [
+ "imp-id"
+ ]
+ },
+ "mockResponse": {
+ "status": 200,
+ "body": {
+ "id": "test-request-id",
+ "seatbid": [
+ {
+ "seat": "interactiveoffers",
+ "bid": [
+ {
+ "id": "randomid",
+ "impid": "imp-id",
+ "price": 0.5,
+ "adid": "12345678",
+ "adm": "