adsGenesys SDK

A client library for integrating with the adsGenesys advertising platform. Available for JavaScript / TypeScript (Node.js 18+) and Java 21+.

The SDK handles authentication, token refresh, and all HTTP communication with https://api.adsgenesys.com. It exposes focused clients for each area of the platform: ad delivery, event tracking, frequency capping, video watch history, and campaign management.

What you can do

Installation

JavaScript / TypeScript

Requires Node.js 18 or later. No runtime dependencies.

shell
npm install ads-genesys-sdk
TypeScript
import { AdsGenesysClient } from 'ads-genesys-sdk';

Java

Requires Java 21+. Add to your Maven pom.xml:

xml
<dependency>
  <groupId>com.vio</groupId>
  <artifactId>ads-genesys-sdk</artifactId>
  <version>1.0.0</version>
</dependency>

Quick Start

Create a client instance once and reuse it across your application.

import { AdsGenesysClient, impression, viewComplete } from 'ads-genesys-sdk';

const client = new AdsGenesysClient({
  apiKey:    'vio_your_api_key',
  apiSecret: 'your_api_secret',
});

// Request an ad block
const blocks = await client.chunklist().createChunklist({
  platformId:  'platform-1',
  subscriberId: 'sub-123',
  deviceType:   'TV',
  deviceId:     'device-456',
  channelId:    'channel-789',
  bids: [{ blockId: 'block-1', duration: 30 }],
});

// Track an impression
await client.statistics().sendEvent(
  impression('campaign-1', 'creative-1', 'session-1')
);
import com.vio.sdk.AdsGenesysClient;
import com.vio.sdk.config.AdsGenesysConfig;
import com.vio.sdk.model.AdBlock;
import com.vio.sdk.statistics.AdEventRequest;

AdsGenesysClient client = AdsGenesysClient.create(
  AdsGenesysConfig.builder()
    .apiKey("vio_your_api_key")
    .apiSecret("your_api_secret")
    .build()
);

// Request an ad block
ChunklistRequest req = new ChunklistRequest();
req.setPlatformId("platform-1");
req.setSubscriberId("sub-123");
req.setDeviceType("TV");
req.setChannelId("channel-789");
req.setBids(List.of(new BidRequest("block-1", 30)));

List<AdBlock> blocks = client.chunklist().createChunklist(req);

// Track an impression
client.statistics().sendEvent(
  AdEventRequest.impression("campaign-1", "creative-1", "session-1")
);

Authentication

The SDK exchanges your API key and API secret for a short-lived JWT access token. This happens automatically on the first request and on token expiry — you never manage tokens manually.

POST /authentication/api-key/exchange

Tokens are cached in memory and refreshed 60 seconds before expiry (~15-minute TTL). When a 401 or 403 response is received, the token is invalidated and the request is retried once automatically.

Keep your apiSecret server-side only. Never expose it in browser bundles or mobile apps.

Configuration

FieldTypeDescription
apiKey string required Your adsGenesys API key.
apiSecret string required Your adsGenesys API secret.
baseUrl string optional API base URL. Default: https://api.adsgenesys.com
timeoutMs number optional Request timeout in milliseconds. Default: 10000

Error Handling

All SDK errors are instances of AdsGenesysError (JS) or VioSdkException (Java). They carry an HTTP statusCode when the error originated from an API response.

import { AdsGenesysError } from 'ads-genesys-sdk';

try {
  const blocks = await client.chunklist().createChunklist(request);
} catch (err) {
  if (err instanceof AdsGenesysError) {
    console.error(err.statusCode, err.message);
  }
}
try {
  List<AdBlock> blocks = client.chunklist().createChunklist(request);
} catch (VioSdkException e) {
  System.out.println(e.getStatusCode() + " " + e.getMessage());
}
statusCodeMeaning
401 / 403Invalid or expired credentials. The SDK retries once automatically.
404Resource not found.
422Validation error. Check request parameters.
-1Network or timeout error (no HTTP response received).

Chunklist

Request HLS chunklist ad blocks from the advertisement processor. Returns one AdBlock per bid, each containing an M3U8 chunklist URL and ad metadata.

POST /advirtisement/block/chunklist
const blocks = await client.chunklist().createChunklist({
  platformId:      'platform-1',
  channelId:       'channel-live-1',   // or vodId for VOD
  subscriberId:    'sub-123',
  deviceType:      'TV',
  deviceId:        'device-456',
  playingSessionId: 'session-abc',
  resolution:      '1920x1080',
  ipAddress:       '203.0.113.5',
  bids: [
    { blockId: 'mid-1', duration: 30 },
    { blockId: 'mid-2', duration: 15 },
  ],
});

blocks.forEach(block => {
  console.log(block.blockId, block.chunklist);
});
ChunklistRequest req = new ChunklistRequest();
req.setPlatformId("platform-1");
req.setChannelId("channel-live-1");
req.setSubscriberId("sub-123");
req.setDeviceType("TV");
req.setDeviceId("device-456");
req.setPlayingSessionId("session-abc");
req.setIpAddress("203.0.113.5");
req.setBids(List.of(
  new BidRequest("mid-1", 30),
  new BidRequest("mid-2", 15)
));

List<AdBlock> blocks = client.chunklist().createChunklist(req);

ChunklistRequest fields

FieldTypeDescription
platformIdstringrequiredPlatform identifier.
subscriberIdstringrequiredSubscriber identifier.
deviceTypestringrequiredTV, MOBILE, or WEB.
deviceIdstringrequiredDevice identifier.
bidsBidRequest[]requiredList of ad blocks to fill. Each bid specifies a blockId and duration (seconds).
channelIdstringoptionalLive channel identifier.
vodIdstringoptionalVOD content identifier.
playingSessionIdstringoptionalUnique playback session ID.
ipAddressstringoptionalViewer IP for geo-targeting.
resolutionstringoptionalScreen resolution, e.g. 1920x1080.
genderstringoptionalM or F.
arnumberoptionalViewer age for age-restricted ad filtering.

AdBlock response

FieldTypeDescription
blockIdstringMatches the bid's blockId.
chunkliststringHLS M3U8 URL to insert into the player.
itemsAdItem[]Individual ad segments with tracking URLs.
adsAdMetadata[]Creative metadata: click-through URL, companion banner, duration.

VAST

Returns a VAST 4.2 XML string for use with standard video player ad clients (e.g., Google IMA, Video.js, THEOplayer).

GET /vast/ad
const vastXml = await client.vast().getVastXml({
  platformId:    'platform-1',
  channelId:     'channel-live-1',
  subscriberId:  'sub-123',
  deviceType:    'WEB',
  blockDuration: 30,
  ipAddress:     '203.0.113.5',
});

// Pass vastXml to your video player's ad client
VastRequest request = VastRequest.builder()
  .platformId("platform-1")
  .channelId("channel-live-1")
  .subscriberId("sub-123")
  .deviceType("WEB")
  .blockDuration(30)
  .ipAddress("203.0.113.5")
  .build();

String vastXml = client.vast().getVastXml(request);

Statistics

Send ad lifecycle events to the analytics pipeline and query campaign reports.

Events

The SDK provides factory functions for each event type. All functions accept optional extra fields as a second argument.

POST /api/v1/events
import { impression, viewStart, viewProgress, viewComplete, click, skip, error } from 'ads-genesys-sdk';

const stats = client.statistics();

await stats.sendEvent(impression('campaign-1', 'creative-1', 'sess-1'));
await stats.sendEvent(viewStart('campaign-1', 'creative-1', 'sess-1'));
await stats.sendEvent(viewProgress('campaign-1', 'creative-1', 25, 'sess-1'));
await stats.sendEvent(viewComplete('campaign-1', 'creative-1', 30000, 'sess-1'));
await stats.sendEvent(click('campaign-1', 'creative-1', 'sess-1'));
await stats.sendEvent(skip('campaign-1', 'creative-1', 'sess-1'));
await stats.sendEvent(error('campaign-1', 'creative-1', 'MEDIA_ERR', 'Failed to load', 'sess-1'));
client.statistics().sendEvent(AdEventRequest.impression("campaign-1", "creative-1", "sess-1"));
client.statistics().sendEvent(AdEventRequest.viewProgress("campaign-1", "creative-1", "sess-1", 50));
client.statistics().sendEvent(AdEventRequest.viewComplete("campaign-1", "creative-1", "sess-1", 30000));
Event typeDescription
IMPRESSIONAd was rendered in the player.
VIEW_STARTPlayback of the ad started.
VIEW_PROGRESS_25 / 50 / 75Quartile progress milestones.
VIEW_COMPLETEAd played to completion. Include watchTimeMs.
CLICKUser clicked the ad.
SKIPUser skipped the ad.
ERRORPlayback error. Include errorCode and errorMessage.

Event Batching

Use AdEventBatch to accumulate events and send them as a single request. Useful for high-traffic players where sending one request per event is expensive.

Events flush automatically when the buffer reaches maxBatchSize (default 50) or every flushIntervalMs (default 5 000 ms).

POST /api/v1/events/batch
const batch = client.statistics().createBatch();

batch.add(impression('campaign-1', 'creative-1', 'sess-1'));
batch.add(viewStart('campaign-1', 'creative-1', 'sess-1'));
batch.add(viewComplete('campaign-1', 'creative-1', 30000, 'sess-1'));

await batch.close();  // final flush + stop timer
try (AdEventBatch batch = client.statistics().createBatch()) {
  batch.add(AdEventRequest.impression("camp-1", "cre-1", "sess-1"));
  batch.add(AdEventRequest.viewComplete("camp-1", "cre-1", "sess-1", 30000));
} // auto-closes and flushes

Reports

Query aggregated analytics data by campaign, platform, or creative.

const stats = client.statistics();

const report = await stats.getCampaignReport('campaign-1', {
  from: '2024-01-01',
  to:   '2024-01-31',
});

const creatives = await stats.getCampaignCreatives('campaign-1', { from: '2024-01-01' });
ReportQuery query = ReportQuery.builder()
  .from("2024-01-01")
  .to("2024-01-31")
  .build();

CampaignReport report = client.statistics().getCampaignReport("campaign-1", query);
MethodEndpoint
getCampaignReport(id)GET /api/v1/reports/campaign/{id}
getPlatformReport(id)GET /api/v1/reports/platform/{id}
getCreativeReport(id)GET /api/v1/reports/creative/{id}
getPlatformCampaigns(id)GET /api/v1/reports/platform/{id}/campaigns
getCampaignCreatives(id)GET /api/v1/reports/campaign/{id}/creatives

Frequency Cap

Read how many times a subscriber (or a specific device) has seen ads within each campaign period. Used to enforce per-subscriber and per-device view limits.

// Cross-device: combined view counts for the subscriber
const history = await client.frequencyCap().getUserViews('sub-123');
// { periodViews: { 'period-abc': 3, 'period-xyz': 1 }, ... }

// Per-device view counts
const deviceHistory = await client.frequencyCap().getUserViews(
  'sub-123', 'device-456', 'TV'
);
UserViewHistory history = client.frequencyCap().getUserViews("sub-123");

UserViewHistory deviceHistory = client.frequencyCap().getUserViews(
  "sub-123", "device-456", "TV"
);
EndpointDescription
GET /api/v1/user-views/cross-device Aggregated view counts across all devices for a subscriber.
GET /api/v1/user-views View counts for a specific subscriber + device combination.

Video Watch

Track when subscribers watch video content. This data is used by the idle-based ad scheduling logic inside DAI sessions to decide when to show the first ad.

The SDK caches the last watch time per subscriber in memory for 5 minutes to avoid repeated API calls during a single session.

const watch = client.videoWatch();

// Record that a subscriber started watching
await watch.recordWatchSession('sub-123', 'vod-456');

// Query last watch time
const lastWatch = await watch.getLastWatchTime('sub-123');
// returns Date | null

// Check idle eligibility directly
const eligible = await watch.isAdEligibleByWatchHistory('sub-123', 8400, {
  minContentDurationSeconds: 7200,
  idleThresholdMinutes:      30,
  firstAdOffsetMinSeconds:   600,
  firstAdOffsetMaxSeconds:   900,
});
// Record watch session
client.videoWatch().recordWatchSession("sub-123", "vod-456");

// Query last watch time
Optional<Instant> last = client.videoWatch().getLastWatchTime("sub-123");

VideoWatchConfig cfg = VideoWatchConfig.builder()
  .minContentDurationSeconds(7200)
  .idleThresholdMinutes(30)
  .firstAdOffsetMinSeconds(600)
  .firstAdOffsetMaxSeconds(900)
  .build();
boolean eligible = client.videoWatch().isAdEligibleByWatchHistory("sub-123", 8400, cfg);
EndpointDescription
POST /api/v1/video-watchRecord a watch session. Body: { subscriberId, videoId }.
GET /api/v1/video-watch/lastReturns the last watch record for a subscriber. 404 if none.

Dynamic Ad Insertion (DAI)

DAI sessions manage ad break scheduling for a single VOD playback. The session calculates break points upfront and tracks which breaks have been served.

Configuration

FieldTypeDefaultDescription
firstAdOffsetSecondsnumber600Fallback offset in seconds for the first mid-roll.
subsequentIntervalSecondsnumber3600Interval between subsequent mid-rolls. Set to 0 for a single mid-roll.
maxAdsPerContentnumber5Maximum total ad breaks (pre + mid + post).
defaultBlockDurationSecondsnumber30Duration of each ad block in seconds.
skipPreRollbooleanfalseSkip the pre-roll ad break.
skipPostRollbooleantrueSkip the post-roll ad break.
videoWatchConfigVideoWatchConfignullWhen set, enables idle-based first-ad scheduling. See below.
const session = client.createDaiSession(
  {
    firstAdOffsetSeconds:       900,
    subsequentIntervalSeconds:  1800,
    maxAdsPerContent:            4,
    defaultBlockDurationSeconds: 30,
  },
  'vod-123',    // vodId
  5400,         // contentDurationSeconds (90 min)
  'platform-1',
  'sub-123',
  'TV',
  'device-456',
);

// Inspect planned breaks
session.getAdBreaks().forEach(b => console.log(b.offsetSeconds, b.position));

// During playback loop
const adBreak = session.checkForAdBreak(currentPositionSeconds);
if (adBreak) {
  const ads = await session.requestAdBlock(adBreak);
}
DaiConfig config = DaiConfig.builder()
  .firstAdOffsetSeconds(900)
  .subsequentIntervalSeconds(1800)
  .maxAdsPerContent(4)
  .build();

DaiSession session = client.createDaiSession(
  config, "vod-123", 5400,
  "platform-1", "sub-123", "TV", "device-456"
);

Optional<DaiAdBreak> adBreak = session.checkForAdBreak(currentPositionSeconds);
adBreak.ifPresent(b -> session.requestAdBlock(b));

Idle-based Scheduling

When videoWatchConfig is set on the DaiConfig, the first mid-roll offset is determined dynamically:

then the first mid-roll is placed at a random time between firstAdOffsetMinSeconds and firstAdOffsetMaxSeconds (e.g. 10–15 min). Otherwise, firstAdOffsetSeconds is used as a fallback.

// SDK fetches last watch time automatically and applies the rule
const session = await client.createDaiSessionWithWatchCheck(
  {
    videoWatchConfig: {
      minContentDurationSeconds: 7200,  // 120 min
      idleThresholdMinutes:      30,
      firstAdOffsetMinSeconds:   600,   // 10 min
      firstAdOffsetMaxSeconds:   900,   // 15 min
    },
  },
  'vod-123',
  8400,          // 140 min content — rule applies
  'platform-1',
  'sub-123',
  'TV',
  'device-456',
);

// Or pass the last watch time manually
const lastWatch = await client.videoWatch().getLastWatchTime('sub-123');
const session2 = client.createDaiSession(config, 'vod-123', 8400,
  'platform-1', 'sub-123', 'TV', 'device-456', lastWatch);
DaiConfig config = DaiConfig.builder()
  .videoWatchConfig(VideoWatchConfig.builder()
    .minContentDurationSeconds(7200)
    .idleThresholdMinutes(30)
    .firstAdOffsetMinSeconds(600)
    .firstAdOffsetMaxSeconds(900)
    .build())
  .build();

// Auto-fetches last watch time
DaiSession session = client.createDaiSessionWithWatchCheck(
  config, "vod-123", 8400,
  "platform-1", "sub-123", "TV", "device-456"
);

Management

Read-only access to campaigns and platforms, plus full CRUD for audience segments.

Campaigns & Platforms

const mgmt = client.management();

const campaigns = await mgmt.getCampaignsByProvider('provider-1');
const campaign  = await mgmt.getCampaign('campaign-1', 'provider-1');
const platform  = await mgmt.getPlatform('platform-1');
client.management().getCampaignsByProvider("provider-1");
client.management().getCampaign("campaign-1", "provider-1");
client.management().getPlatform("platform-1");

Audience Segments

Audience segments define targeting criteria (age, gender, geo) scoped to a platform. Active segments are applied automatically during ad selection.

const mgmt = client.management();

// Create
const segment = await mgmt.createAudienceSegment('platform-1', {
  name:      'Adults 25-44',
  ageFrom:   25,
  ageTo:     44,
  countries: ['UA', 'PL'],
});

// Activate / deactivate
await mgmt.activateAudienceSegment('platform-1', segment.uuid);
await mgmt.deactivateAudienceSegment('platform-1', segment.uuid);

// List
const all = await mgmt.getAudienceSegmentsByPlatform('platform-1');

// Delete
await mgmt.deleteAudienceSegment('platform-1', segment.uuid);
AudienceSegmentRequest req = new AudienceSegmentRequest();
req.setName("Adults 25-44");
req.setAgeFrom(25);
req.setAgeTo(44);
req.setCountries(Set.of("UA", "PL"));

AudienceSegment seg = client.management().createAudienceSegment("platform-1", req);
client.management().activateAudienceSegment("platform-1", seg.getUuid());
MethodEndpoint
createAudienceSegmentPOST /api/v1/audience-segments/{platformId}
updateAudienceSegmentPUT /api/v1/audience-segments/{platformId}/{uuid}
getAudienceSegmentGET /api/v1/audience-segments/{platformId}/{uuid}
getAudienceSegmentsByPlatformGET /api/v1/audience-segments/platform/{platformId}
activateAudienceSegmentPUT /api/v1/audience-segments/{platformId}/{uuid}/activate
deactivateAudienceSegmentPUT /api/v1/audience-segments/{platformId}/{uuid}/deactivate
deleteAudienceSegmentDELETE /api/v1/audience-segments/{platformId}/{uuid}

Types

All public types are exported from the package root.

TypeScript
import type {
  // Config
  AdsGenesysConfig,

  // Ad delivery
  ChunklistRequest,  BidRequest,
  AdBlock,           AdItem,           AdMetadata,
  AdPosition,
  VastRequest,

  // Statistics
  AdEventType,
  AdEventRequest,    AdEventData,
  ReportQuery,       CampaignReport,

  // Frequency cap
  UserViewHistory,

  // Video watch
  VideoWatchConfig,  VideoWatchRecord,

  // DAI
  DaiConfig,

  // Management
  AudienceSegment,   AudienceSegmentRequest,
} from 'ads-genesys-sdk';

Downloads

Download the SDK as a standalone package — no package manager required.

JS
JavaScript / TypeScript SDK
Node.js 18+  ·  v1.0.0  ·  .zip

Includes the compiled dist/ folder with .js files and TypeScript declaration files (.d.ts).

↓ Download JS SDK
JAR
Java SDK
Java 21+  ·  v1.0.0  ·  .zip

Includes the compiled .jar and all runtime dependencies (Jackson, SLF4J).

↓ Download Java SDK

Prefer a package manager? See Installation for npm and Maven instructions.