diff --git a/modules/ssmasBidAdapter.js b/modules/ssmasBidAdapter.js
new file mode 100644
index 00000000000..9ed1ec90dd8
--- /dev/null
+++ b/modules/ssmasBidAdapter.js
@@ -0,0 +1,126 @@
+import { BANNER } from '../src/mediaTypes.js';
+import { registerBidder } from '../src/adapters/bidderFactory.js';
+import { triggerPixel, deepSetValue } from '../src/utils.js';
+import { ortbConverter } from '../libraries/ortbConverter/converter.js';
+import {config} from '../src/config.js';
+
+export const SSMAS_CODE = 'ssmas';
+const SSMAS_SERVER = 'ads.ssmas.com';
+export const SSMAS_ENDPOINT = `http://${SSMAS_SERVER}/ortb`;
+const SYNC_URL = `http://sync.ssmas.com/user_sync`;
+export const SSMAS_REQUEST_METHOD = 'POST';
+const GDPR_VENDOR_ID = 1183;
+
+export const ssmasOrtbConverter = ortbConverter({
+ context: {
+ netRevenue: true,
+ ttl: 300,
+ mediaType: BANNER,
+ },
+ imp(buildImp, bidRequest, context) {
+ const imp = buildImp(bidRequest, context);
+ deepSetValue(imp, 'ext.placementId', bidRequest.params.placementId);
+ return imp;
+ },
+});
+
+export const spec = {
+ code: SSMAS_CODE,
+ supportedMediaTypes: [BANNER],
+ gvlid: GDPR_VENDOR_ID,
+
+ isBidRequestValid: (bid) => {
+ return !!bid.params.placementId && !!bid.bidId && bid.bidder === SSMAS_CODE;
+ },
+
+ buildRequests: (bidRequests, bidderRequest) => {
+ const data = ssmasOrtbConverter.toORTB({ bidRequests, bidderRequest });
+
+ const options = {
+ contentType: 'application/json',
+ withCredentials: false,
+ };
+
+ data.imp && data.imp.forEach(imp => {
+ if (imp.ext && imp.ext.placementId) {
+ imp.tagId = imp.ext.placementId;
+ }
+ });
+
+ data.regs = data.regs || {};
+ data.regs.ext = data.regs.ext || {};
+
+ if (bidderRequest.gdprConsent) {
+ data.regs.ext.consent = bidderRequest.gdprConsent.consentString;
+ data.regs.ext.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0;
+ }
+ if (bidderRequest.uspConsent) {
+ data.regs.ext.consent = bidderRequest.uspConsent.consentString;
+ data.regs.ext.ccpa = 1;
+ }
+ if (config.getConfig('coppa') === true) {
+ data.regs.coppa = 1;
+ }
+
+ return [
+ {
+ method: SSMAS_REQUEST_METHOD,
+ url: SSMAS_ENDPOINT,
+ data,
+ options,
+ },
+ ];
+ },
+
+ interpretResponse: (serverResponse, bidRequest) => {
+ const bids = ssmasOrtbConverter.fromORTB({
+ response: serverResponse.body,
+ request: bidRequest.data,
+ }).bids;
+
+ return bids.filter((bid) => {
+ return bid.cpm > 0;
+ });
+ },
+
+ onBidWon: (bid) => {
+ if (bid.burl) {
+ triggerPixel(bid.burl);
+ }
+ },
+
+ getUserSyncs: (
+ syncOptions,
+ serverResponses,
+ gdprConsent,
+ uspConsent
+ ) => {
+ const syncs = [];
+
+ let params = ['pbjs=1'];
+
+ if (gdprConsent) {
+ if (typeof gdprConsent.gdprApplies === 'boolean') {
+ params.push(`gdpr=${Boolean(gdprConsent.gdprApplies)}&gdpr_consent=${
+ gdprConsent.consentString
+ }`);
+ } else {
+ params.push(`gdpr_consent=${gdprConsent.consentString}`);
+ }
+ }
+
+ if (uspConsent && uspConsent.consentString) {
+ params.push(`ccpa_consent=${uspConsent.consentString}`);
+ }
+
+ if (syncOptions.pixelEnabled && serverResponses.length > 0) {
+ syncs.push({
+ type: 'image',
+ url: `${SYNC_URL}?${params.join('&')}`
+ });
+ }
+ return syncs;
+ },
+};
+
+registerBidder(spec);
diff --git a/modules/ssmasBidAdapter.md b/modules/ssmasBidAdapter.md
new file mode 100644
index 00000000000..1b15764a54d
--- /dev/null
+++ b/modules/ssmasBidAdapter.md
@@ -0,0 +1,35 @@
+# Overview
+
+Module Name: SSMas Bidder Adapter
+Module Type: Bidder Adapter
+Maintainer: hzchen.work@gmail.com
+
+# Description
+
+Module that connects to Sem Seo & Mas header bidding endpoint to fetch bids.
+Supports Banner
+Supported currencies: EUR
+
+Required parameters:
+- placement id
+
+# Test Parameters
+```
+var adUnits = [
+ // Banner adUnit
+ {
+ code: 'banner-div',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]]
+ }
+ },
+ bids: [{
+ bidder: 'ssmas',
+ params: {
+ placementId: "10336"
+ }
+ }]
+ }
+];
+```
diff --git a/test/spec/modules/ssmasBidAdapter_spec.js b/test/spec/modules/ssmasBidAdapter_spec.js
new file mode 100644
index 00000000000..26c6f60da4b
--- /dev/null
+++ b/test/spec/modules/ssmasBidAdapter_spec.js
@@ -0,0 +1,244 @@
+import { expect } from 'chai';
+import { spec, SSMAS_CODE, SSMAS_ENDPOINT, SSMAS_REQUEST_METHOD } from 'modules/ssmasBidAdapter.js';
+import {newBidder} from 'src/adapters/bidderFactory.js';
+import * as utils from 'src/utils.js';
+
+describe('ssmasBidAdapter', function () {
+ const bid = {
+ bidder: SSMAS_CODE,
+ adUnitCode: 'adunit-code',
+ sizes: [[300, 250]],
+ bidId: '30b31c1838de1e',
+ bidderRequestId: '22edbae2733bf6',
+ auctionId: '1d1a030790a475',
+ params: {
+ placementId: '1'
+ }
+ };
+
+ const bidderRequest = {
+ 'bidderCode': SSMAS_CODE,
+ 'auctionId': 'd912faa2-174f-4636-b755-7396a0a964d8',
+ 'bidderRequestId': '109db5a5f5c6788',
+ 'bids': [
+ bid
+ ],
+ 'auctionStart': 1684799653734,
+ 'timeout': 20000,
+ 'metrics': {},
+ 'ortb2': {
+ 'site': {
+ 'domain': 'localhost:9999',
+ 'publisher': {
+ 'domain': 'localhost:9999'
+ },
+ 'page': 'http://localhost:9999/integrationExamples/noadserver/basic_noadserver.html',
+ 'ref': 'http://localhost:9999/integrationExamples/noadserver/'
+ },
+ 'device': {
+ 'w': 1536,
+ 'h': 711,
+ 'dnt': 0,
+ 'ua': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0',
+ 'language': 'es'
+ }
+ },
+ 'start': 1684799653737
+ };
+
+ describe('Build Requests', () => {
+ it('Check bid request', function () {
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request[0].method).to.equal(SSMAS_REQUEST_METHOD);
+ expect(request[0].url).to.equal(SSMAS_ENDPOINT);
+ });
+ });
+
+ describe('register adapter functions', () => {
+ const adapter = newBidder(spec);
+ it('is registered', () => {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ it('validate bid request building', function () {
+ expect(spec.isBidRequestValid(bid)).to.be.true;
+ });
+
+ it('test bad bid request', function () {
+ // empty bid
+ expect(spec.isBidRequestValid({bidId: '', params: {}})).to.be.false;
+
+ // empty bidId
+ bid.bidId = '';
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+
+ // empty placementId
+ bid.bidId = '1231';
+ bid.params.placementId = '';
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+ });
+
+ it('check bid request bidder is Sem Seo & Mas', function() {
+ const invalidBid = {
+ ...bid, bidder: 'invalidBidder'
+ };
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+ });
+
+ describe('interpretResponse', function () {
+ let bidOrtbResponse = {
+ 'id': 'aa02e2fe-56d9-4713-88f9-d8672ceae8ab',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': '0001',
+ 'impid': '3919400af0b73e8',
+ 'price': 7.01,
+ 'adid': null,
+ 'nurl': null,
+ 'adm': '',
+ 'adomain': [
+ 'ssmas.com'
+ ],
+ 'iurl': null,
+ 'cid': null,
+ 'crid': '3547894',
+ 'attr': [],
+ 'api': 0,
+ 'protocol': 0,
+ 'dealid': null,
+ 'h': 600,
+ 'w': 300,
+ 'cat': null,
+ 'ext': null,
+ 'builder': {
+ 'id': '0001',
+ 'adid': null,
+ 'impid': '3919400af0b73e8',
+ 'adomainList': [
+ 'ssmas.com'
+ ],
+ 'attrList': []
+ },
+ 'adomainList': [
+ 'ssmas.com'
+ ],
+ 'attrList': []
+ }
+ ],
+ 'seat': null,
+ 'group': 0
+ }
+ ],
+ 'bidid': '408731cc-c018-4976-bfc6-89f9c61e97a0',
+ 'cur': 'EUR',
+ 'nbr': -1
+ };
+ let bidResponse = {
+ 'mediaType': 'banner',
+ 'ad': '',
+ 'requestId': '37c658fe8ba57b',
+ 'seatBidId': '0001',
+ 'cpm': 10,
+ 'currency': 'EUR',
+ 'width': 300,
+ 'height': 250,
+ 'dealId': null,
+ 'creative_id': '3547894',
+ 'creativeId': '3547894',
+ 'ttl': 30,
+ 'netRevenue': true,
+ 'meta': {
+ 'advertiserDomains': [
+ 'ssmas.com'
+ ]
+ }
+ };
+ let bidRequest = {
+ 'imp': [
+ {
+ 'ext': {
+ 'tid': '937db9c3-c22d-4454-b786-fcad76a349e5',
+ 'data': {
+ 'pbadslot': 'test-div'
+ }
+ },
+ 'id': '3919400af0b73e8',
+ 'banner': {
+ 'topframe': 1,
+ 'format': [
+ {
+ 'w': 300,
+ 'h': 600
+ }
+ ]
+ }
+ },
+ {
+ 'ext': {
+ 'tid': '0c0d3d1b-0ad0-4786-896d-24c15fc6531d',
+ 'data': {
+ 'pbadslot': 'test-div2'
+ }
+ },
+ 'id': '3919400af0b73e8',
+ 'banner': {
+ 'topframe': 1,
+ 'format': [
+ {
+ 'w': 300,
+ 'h': 600
+ }
+ ]
+ }
+ }
+ ],
+ 'site': {
+ 'domain': 'localhost:9999',
+ 'publisher': {
+ 'domain': 'localhost:9999'
+ },
+ 'page': 'http://localhost:9999/integrationExamples/noadserver/basic_noadserver.html',
+ 'ref': 'http://localhost:9999/integrationExamples/noadserver/',
+ 'id': 1,
+ 'ext': {
+ 'placementId': 13144370
+ }
+ },
+ 'device': {
+ 'w': 1536,
+ 'h': 711,
+ 'dnt': 0,
+ 'ua': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0',
+ 'language': 'es'
+ },
+ 'id': '8cc2f4b0-084d-4f40-acfa-5bec2023b1ab',
+ 'test': 0,
+ 'tmax': 20000,
+ 'source': {
+ 'tid': '8cc2f4b0-084d-4f40-acfa-5bec2023b1ab'
+ }
+ }
+ });
+
+ describe('test onBidWon function', function () {
+ beforeEach(function() {
+ sinon.stub(utils, 'triggerPixel');
+ });
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ });
+ it('exists and is a function', () => {
+ expect(spec.onBidWon).to.exist.and.to.be.a('function');
+ });
+ it('should return nothing', function () {
+ var response = spec.onBidWon({});
+ expect(response).to.be.an('undefined')
+ expect(utils.triggerPixel.called).to.equal(false);
+ });
+ });
+});