Adverteks API Reference
Complete reference for the Adverteks programmatic advertising platform. Connect external DSPs and SSPs, manage campaigns, and integrate with the OpenRTB 2.5 auction engine.
Base URL
https://adverteks.com
Authentication
Two authentication methods depending on integration type.
JWT Bearer Token (DSP and SSP APIs)
User-facing endpoints require a signed JWT. Obtain one via the login endpoint and include it as a Bearer token.
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
{
"email": "your@email.com",
"password": "your-password"
}
{
"success": true,
"token": "eyJhbGci...",
"user": { "id": 42, "email": "your@email.com", "role": "advertiser" }
}
Tokens expire after 7 days. Re-authenticate to refresh.
API Key (RTB / OpenRTB 2.5 Endpoints)
External DSP partners authenticate using an API key issued by Adverteks. Contact partners@adverteks.com to obtain credentials.
X-Api-Key: adtks_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx # or Authorization: Bearer adtks_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Rate Limits & SLA — Per Endpoint
Limits enforced per IP or API key, sliding windows. RTB limits key on the X-Api-Key header; all others key on client IP (behind Cloudflare/Render proxy). When exceeded, the API returns 429 with a Retry-After header (seconds until window resets).
| Endpoint Group | Limit | Window | Key By | Notes |
|---|---|---|---|---|
| /api/rtb/bid | 1,000 req | 1 min | API key | Core RTB endpoint — configurable per partner |
| /api/rtb/win | 1,000 req | 1 min | API key | Win notice endpoint |
| /api/rtb/event | 1,000 req | 1 min | API key | Event tracking endpoint |
| /api/rtb/external/* | 1,000 req | 1 min | API key | External partner RTB endpoints |
| /api/hb/bid | 500 req | 1 min | IP | Header bidding — no auth required (browser calls) |
| /api/hb/win | 500 req | 1 min | IP | Header bidding win notice |
| /api/ad/serve/* | 1,000 req | 1 min | Zone key | Ad tag serving (public endpoint) |
| /api/ad/click/* | 500 req | 1 min | IP | Click tracking redirect |
| /api/auth/login | 5 failures | 1 min | IP | Only failed attempts count; successes don't |
| /api/auth/signup | 3 req | 1 hour | IP | Account creation throttle |
| /api/auth/forgot-password | 3 req | 1 hour | IP | Password reset requests |
| /api/auth/mfa/* | 10 req | 15 min | IP | MFA setup and verification attempts |
| /api/auth/resend-verification | 3 req | 1 hour | IP | Email verification resend |
| /api/advertiser/billing/deposit | 10 req | 1 hour | User | Deposit initiation; requires re-auth |
| /api/publisher/earnings/withdraw | 5 req | 1 hour | User | Withdrawal initiation; requires re-auth |
| /api/v1/affiliate/* | 60 req | 1 min | IP | Affiliate program endpoints |
| /api/* (general) | 60 req | 1 min | IP | Default for all unspecified endpoints |
adtks_test_* keys. All other sandbox limits match production.Latency SLA
tmax milliseconds, treat the response as a no-bid (204). The tmax field in your BidRequest is honored; minimum accepted value is 50ms, maximum is 30,000ms. We recommend 150ms for competitive fill.Auth Endpoints
Full endpoint reference for user registration, login, token refresh, and account management. All user-facing APIs require a valid JWT obtained from /api/auth/login.
Creates a publisher account. Returns a JWT on success and sends an email verification link.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| string | Required | Valid email address. Must be unique. | |
| password | string | Required | Minimum 8 characters. |
| company_name | string | Optional | Publisher company or website name. |
curl -X POST https://adverteks.com/api/auth/signup \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"securepass123","company_name":"My Site"}'
{"success":true,"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","user":{"id":42,"email":"you@example.com","role":"publisher"}}
Creates an advertiser (DSP) account with a wallet initialized to $0.00. Requires email verification before campaigns can go live.
{"email":"ads@agency.com","password":"securepass123","company_name":"Agency Inc"}
Validates credentials and returns a short-lived access token (15 minutes) and a long-lived refresh token (7 days). Re-authenticate to get a new pair before the access token expires.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| string | Required | Registered email address. | |
| password | string | Required | Account password. |
| mfa_code | string | Conditional | 6-digit TOTP code. Required if MFA is enabled on account. |
curl -X POST https://adverteks.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"securepass123"}'
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 42,
"email": "you@example.com",
"role": "publisher",
"email_verified": true,
"mfa_enabled": false
}
}
Issue a fresh JWT without requiring the user to re-enter credentials. Use this to maintain sessions beyond the 15-minute access token window.
{"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
{"success":true,"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
Invalidates the current access and refresh tokens. Subsequent requests with the old token return 401.
curl -X POST https://adverteks.com/api/auth/logout \ -H "Authorization: Bearer YOUR_JWT_TOKEN"
Returns the user object for the authenticated token. Use to verify token validity and read account state.
{
"success": true,
"user": {
"id": 42,
"email": "you@example.com",
"role": "publisher",
"email_verified": true,
"mfa_enabled": true,
"created_at": "2026-01-15T10:23:00Z"
}
}
Password Reset
{"email": "you@example.com"}
Sends a password reset link valid for 1 hour. Always returns 200 to prevent email enumeration.
{"token": "RESET_TOKEN_FROM_EMAIL", "password": "newSecurePass123"}
Multi-Factor Authentication (TOTP)
Adverteks supports TOTP-based MFA (compatible with Google Authenticator, Authy, 1Password, etc.) and hardware keys via WebAuthn/FIDO2.
| Endpoint | Method | Description |
|---|---|---|
| /api/auth/mfa/setup | POST | Generate TOTP secret + QR code URI. Auth required. |
| /api/auth/mfa/verify | POST | Submit first TOTP code to complete MFA enrollment. |
| /api/auth/mfa/disable | POST | Disable TOTP. Requires current TOTP code + password. |
| /api/auth/mfa/status | GET | Returns {"enabled": true/false}. |
| /api/auth/v2/mfa/regenerate-recovery | POST | Generate new single-use recovery codes (invalidates old set). |
# Step 1 — get secret + QR
curl -X POST https://adverteks.com/api/auth/mfa/setup \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json"
# → returns: {"secret":"BASE32SECRET","qr":"otpauth://totp/..."}
# Step 2 — confirm with first TOTP code to activate
curl -X POST https://adverteks.com/api/auth/mfa/verify \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","mfa_code":"123456"}'
WebAuthn / Passkeys
Passwordless login via hardware security keys (YubiKey, Touch ID, Windows Hello). Registration and authentication use the WebAuthn Ceremony API.
| Endpoint | Method | Description |
|---|---|---|
| /api/auth/webauthn/register/options | POST | Start registration ceremony — returns challenge. |
| /api/auth/webauthn/register | POST | Complete registration with authenticator response. |
| /api/auth/webauthn/authenticate/options | POST | Start authentication ceremony — returns challenge. |
| /api/auth/webauthn/authenticate | POST | Complete authentication — returns JWT on success. |
| /api/auth/webauthn/credentials | GET | List registered passkeys/credentials. |
| /api/auth/webauthn/credentials/:id | DELETE | Revoke a passkey credential. |
RTB Integration (OpenRTB 2.5)
Adverteks implements IAB OpenRTB 2.5 for inbound bid requests. External DSPs submit a BidRequest and receive a BidResponse or HTTP 204 for no-bid.
HMAC-SHA256 Request Signing
Adverteks supports optional HMAC-SHA256 request signing for RTB partners. When enabled, every BidRequest must include an X-Signature-SHA256 header. Requests without a valid signature are rejected with 401.
Signature Format
| Header | Value Format |
|---|---|
| X-Signature-SHA256 | sha256=<hex-digest> |
| X-Api-Key | Your partner API key (always required) |
The signature is computed as HMAC-SHA256 over the raw request body bytes using your HMAC secret (different from your API key). Both credentials are issued together during partner onboarding.
const crypto = require('crypto');
const https = require('https');
const API_KEY = 'adtks_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const HMAC_SECRET = 'your-hmac-secret-from-onboarding';
const HOST = 'adverteks.com';
function buildSignatureHeaders(bodyString, apiKey, secret) {
const sig = crypto
.createHmac('sha256', secret)
.update(bodyString, 'utf8')
.digest('hex');
return {
'Content-Type': 'application/json',
'X-Api-Key': apiKey,
'X-OpenRTB-Version': '2.5',
'X-Signature-SHA256': `sha256=${sig}`,
};
}
async function sendBidRequest(bidRequest) {
const body = JSON.stringify(bidRequest);
const headers = buildSignatureHeaders(body, API_KEY, HMAC_SECRET);
const res = await fetch(`https://${HOST}/api/rtb/bid`, {
method: 'POST',
headers,
body,
});
if (res.status === 204) return null; // no-bid
return res.json();
}
import hmac
import hashlib
import json
import urllib.request
API_KEY = 'adtks_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
HMAC_SECRET = 'your-hmac-secret-from-onboarding'
ENDPOINT = 'https://adverteks.com/api/rtb/bid'
def build_signature_headers(body_bytes: bytes, api_key: str, secret: str) -> dict:
sig = hmac.new(
secret.encode('utf-8'),
body_bytes,
hashlib.sha256
).hexdigest()
return {
'Content-Type': 'application/json',
'X-Api-Key': api_key,
'X-OpenRTB-Version': '2.5',
'X-Signature-SHA256': f'sha256={sig}',
}
def send_bid_request(bid_request: dict):
body = json.dumps(bid_request).encode('utf-8')
headers = build_signature_headers(body, API_KEY, HMAC_SECRET)
req = urllib.request.Request(ENDPOINT, data=body, headers=headers, method='POST')
try:
with urllib.request.urlopen(req, timeout=0.2) as resp:
if resp.status == 200:
return json.loads(resp.read())
return None # 204 no-bid
except urllib.error.HTTPError as e:
if e.code == 204:
return None # no-bid
raise
The primary inbound RTB endpoint. Submit an OpenRTB 2.5 BidRequest and receive a BidResponse, or 204 No Content when no eligible bid exists.
Request Headers
| Header | Required | Description |
|---|---|---|
| Content-Type | required | Must be application/json |
| X-Api-Key | optional | DSP partner API key. If omitted, processed as anonymous. |
| X-OpenRTB-Version | optional | Should be 2.5 |
BidRequest Fields
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | required | Unique auction ID (UUID recommended) |
| imp | array | required | Array of impression objects; at least one must have a banner child |
| imp[].id | string | required | Impression identifier within this request |
| imp[].banner | object | required | Banner object with w x h or format array |
| imp[].bidfloor | float | optional | Minimum bid CPM USD. Effective floor = max(bidfloor, partner floor) |
| imp[].bidfloorcur | string | optional | Currency of bidfloor. Default: USD |
| site | object | optional | Site context (page, domain, cat) |
| user | object | optional | User context (id, buyeruid) |
| geo | object | optional | Geo targeting (lat, lon, country, city) |
| tmax | integer | optional | Max response time ms. Default 200. |
Supported Banner Sizes
| Format | Dimensions | IAB Name |
|---|---|---|
| leaderboard | 728 x 90 | IAB Leaderboard |
| medium_rectangle | 300 x 250 | IAB Medium Rectangle |
| mobile_banner | 320 x 50 | IAB Mobile Banner |
| wide_skyscraper | 160 x 600 | IAB Wide Skyscraper |
{
"id": "7f3d2a11-c4b8-4e9a-b2f1-a3c9e8d72f01",
"imp": [{
"id": "1",
"banner": {
"w": 300,
"h": 250,
"format": [{ "w": 300, "h": 250 }],
"pos": 1
},
"bidfloor": 0.50,
"bidfloorcur": "USD"
}],
"site": {
"page": "https://example.com/article",
"domain": "example.com",
"cat": ["IAB1", "IAB12"]
},
"geo": {
"lat": 40.7128,
"lon": -74.0060,
"country": "USA",
"city": "New York"
},
"user": { "id": "user-seg-abc123" },
"tmax": 150
}
Response
200 OK Bid found — returns OpenRTB 2.5 BidResponse.
204 No Content No eligible bid (below floor, no banner, or no budget).
400 Bad Request Invalid BidRequest.
{
"id": "7f3d2a11-c4b8-4e9a-b2f1-a3c9e8d72f01",
"seatbid": [{
"bid": [{
"id": "bid-a9c3e1f2",
"impid": "1",
"price": 1.85,
"adid": "creative-78",
"adm": "",
"adomain": ["brand.com"],
"crid": "cr-4d9a2f",
"w": 300,
"h": 250,
"nurl": "https://adverteks.com/api/rtb/win?aid=${AUCTION_ID}&price=${AUCTION_PRICE}"
}],
"seat": "adverteks"
}],
"cur": "USD"
}
Notify Adverteks when a bid wins downstream. The nurl in BidResponse uses macro substitution.
Win Notice Macros
| Macro | Description |
|---|---|
| ${AUCTION_ID} | Unique auction ID from BidRequest id field |
| ${AUCTION_PRICE} | Winning clearing price in CPM USD (second-price) |
| ${AUCTION_IMP_ID} | Impression ID from imp[].id |
| ${AUCTION_BID_ID} | Bid ID from the BidResponse |
{
"auction_id": "7f3d2a11-c4b8-4e9a-b2f1-a3c9e8d72f01",
"clearing_price": 1.42,
"imp_id": "1"
}
Returns 200 OK on success.
Send downstream event notifications for attribution and analytics.
| Field | Type | Required | Description |
|---|---|---|---|
| auction_id | string | required | Auction ID from the original BidRequest |
| event_type | string | required | impression | click | conversion |
| timestamp | integer | optional | Unix timestamp ms. Defaults to server receive time. |
| revenue | float | optional | Conversion revenue in USD |
External RTB Partner Endpoints
Dedicated endpoints for external DSP/SSP partners integrated via the Adverteks Exchange. These mirror the core RTB endpoints but use partner-specific authentication and logging.
/api/rtb/external/* endpoints requires a confirmed RTB partner agreement. Contact partners@adverteks.com to begin onboarding.Identical to /api/rtb/bid in request/response format. Uses separate partner rate limits and bid-log tracking for attribution and reconciliation. HMAC-SHA256 signing follows the same scheme (see HMAC Signing).
Partner-Specific Headers
| Header | Required | Description |
|---|---|---|
| X-Api-Key | Required | Your partner API key (prefix: adtks_live_) |
| X-Partner-ID | Optional | Your registered partner ID for enhanced logging |
| X-Signature-SHA256 | Optional | HMAC-SHA256 of raw body. Required for production partners. |
curl -X POST https://adverteks.com/api/rtb/external/bid \
-H "Content-Type: application/json" \
-H "X-Api-Key: adtks_live_YOUR_KEY" \
-H "X-OpenRTB-Version: 2.5" \
-d '{
"id": "ext-auction-001",
"imp": [{"id":"1","banner":{"w":300,"h":250},"bidfloor":0.50}],
"site": {"page":"https://partner-site.com/page","domain":"partner-site.com"},
"tmax": 150
}'
Notify Adverteks of a win on external inventory. Triggers billing, publisher revenue credit, and impression recording with demand_source: 'external_rtb'.
POST /api/rtb/external/win?aid=ext-auction-001&price=1.42 X-Api-Key: adtks_live_YOUR_KEY
Same payload schema as /api/rtb/event. Records impression, click, and conversion events attributed to external partner demand.
{"auction_id":"ext-auction-001","event_type":"impression"}
Header Bidding (Prebid.js)
Adverteks provides a native Prebid.js bid adapter. Publishers using Prebid can include Adverteks demand alongside other bidders without additional server-side infrastructure.
tmax enforcementSetup — Prebid.js via CDN
# Build Prebid.js bundle including the Adverteks adapter: gulp build --modules=adverteksBidAdapter # Or use the pre-built bundle from Adverteks CDN: # https://adverteks.com/sdk/adverteksBidAdapter.js
const adUnits = [{
code: 'div-header-banner',
mediaTypes: {
banner: { sizes: [[728, 90], [300, 250]] }
},
bids: [{
bidder: 'adverteks',
params: {
publisherId: 42, // Your Adverteks publisher user ID (required)
siteId: 'site-001', // Optional: your registered site ID
floorCpm: 0.50 // Optional: minimum CPM you'll accept
}
}]
}];
pbjs.addAdUnits(adUnits);
pbjs.requestBids({ bidsBackHandler: sendAdServerRequest, timeout: 1000 });
Called automatically by the Adverteks Prebid.js adapter. Publishers building custom integrations can call this endpoint directly. No API key required — authentication is via params.publisherId.
Request Body (Prebid bid request format)
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Optional | Auction ID for tracking |
| bids | array | Required | Array of bid slot objects (see below) |
| page | string | Optional | URL of the publisher page (improves targeting) |
| tmax | integer | Optional | Timeout in ms (default 500, max 1000) |
Bid Slot Object Fields
| Field | Type | Required | Description |
|---|---|---|---|
| bidId | string | Required | Unique ID for this bid slot (echoed back in response) |
| params.publisherId | integer | Required | Adverteks publisher user ID |
| sizes | array | Optional | Fallback sizes: [[300,250],[728,90]] |
| mediaTypes.banner.sizes | array | Optional | Preferred sizes (takes priority over sizes) |
| params.floorCpm | float | Optional | Minimum CPM floor (default 0.10) |
| params.siteId | string | Optional | Registered site ID for better analytics |
curl -X POST https://adverteks.com/api/hb/bid \
-H "Content-Type: application/json" \
-d '{
"id": "req-001",
"bids": [{
"bidId": "bid-slot-1",
"params": {"publisherId": 42, "floorCpm": 0.50},
"mediaTypes": {"banner": {"sizes": [[300,250],[728,90]]}},
"page": "https://mypublishersite.com/article"
}],
"tmax": 300
}'
{
"id": "req-001",
"bids": [{
"requestId": "bid-slot-1",
"cpm": 1.42,
"currency": "USD",
"width": 300,
"height": 250,
"ad": "<!-- creative HTML -->",
"ttl": 30,
"creativeId": "cr-4d9a2f",
"netRevenue": true,
"meta": {"advertiserDomains": [], "mediaType": "banner"},
"_adtk": {
"publisherId": 42,
"campaignId": 101,
"creativeId": "cr-4d9a2f",
"adFormat": "300x250"
}
}]
}
An empty bids: [] array means no fill for that slot. Prebid handles this as a no-bid automatically.
Called by the Prebid.js adapter via sendBeacon when the Adverteks bid wins the client-side auction and the ad renders. Triggers billing (advertiser wallet deduction) and publisher revenue credit (70% rev share).
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| publisherId | integer | Required | Publisher user ID (from bid response _adtk.publisherId) |
| campaignId | integer | Required | Campaign ID from bid response |
| cpm | float | Required | Winning CPM (clearing price) |
| creativeId | string | Optional | Creative ID for tracking |
| adFormat | string | Optional | e.g. "300x250" |
| pageUrl | string | Optional | Publisher page URL for impression logging |
curl -X POST https://adverteks.com/api/hb/win \
-H "Content-Type: application/json" \
-d '{
"publisherId": 42,
"campaignId": 101,
"cpm": 1.42,
"creativeId": "cr-4d9a2f",
"adFormat": "300x250",
"pageUrl": "https://mypublishersite.com/article"
}'
{"ok": true}
adverteksBidAdapter.js
The official Adverteks Prebid.js bid adapter is hosted at:
https://adverteks.com/sdk/adverteksBidAdapter.js
The adapter handles: bid request construction, timeout enforcement (tmax), win notice via navigator.sendBeacon, and GDPR/CCPA consent string forwarding.
Bidder Code
{ bidder: 'adverteks', params: { publisherId: 42 } }
Supported Media Types
| Media Type | Status | Notes |
|---|---|---|
| banner | ✅ Supported | 728×90, 300×250, 320×50, 160×600 |
| video | Roadmap | VAST 4.0 in development |
| native | Roadmap | Planned Q3 2026 |
DSP API
Manage advertising campaigns, creatives, audience targeting, and budgets. All endpoints require a valid JWT Bearer token.
{
"success": true,
"campaigns": [{
"id": 101,
"name": "Summer Sale 2026",
"status": "active",
"budget_total": 5000.00,
"budget_daily": 200.00,
"budget_spent": 842.30,
"bid_strategy": "cpm",
"bid_amount": 2.50,
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"targeting": {
"geo": ["US", "CA"],
"categories": ["IAB1"],
"device_types": ["desktop", "mobile"]
},
"impressions": 421540,
"clicks": 3082,
"ctr": 0.73
}]
}
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | required | Campaign display name (max 255 chars) |
| budget_total | float | required | Total campaign budget in USD |
| budget_daily | float | optional | Daily spend cap in USD |
| bid_strategy | string | required | cpm | cpc | cpa |
| bid_amount | float | required | Max bid in USD per event |
| start_date | string | optional | ISO 8601 date YYYY-MM-DD. Defaults to today. |
| end_date | string | optional | ISO 8601 date. Null = indefinite. |
| targeting | object | optional | Audience targeting rules |
Targeting Object
| Field | Type | Description |
|---|---|---|
| geo | string[] | ISO 3166-1 alpha-2 country codes e.g. ["US","GB"] |
| categories | string[] | IAB content categories e.g. ["IAB1","IAB12"] |
| device_types | string[] | desktop | mobile | tablet |
| ad_formats | string[] | 728x90 | 300x250 | 320x50 | 160x600 |
| geofence_ids | integer[] | IDs of geofence zones for hyper-local targeting |
{
"name": "Q2 Brand Awareness",
"budget_total": 10000,
"budget_daily": 500,
"bid_strategy": "cpm",
"bid_amount": 3.00,
"start_date": "2026-04-01",
"targeting": {
"geo": ["US"],
"device_types": ["desktop", "mobile"],
"ad_formats": ["300x250", "728x90"]
}
}
Modify an existing campaign. Only fields included in the request body are updated (partial update). Paused campaigns can be reactivated by setting "status": "active".
Updatable Fields
| Field | Type | Description |
|---|---|---|
| name | string | Campaign display name |
| status | string | active | paused |
| budget_daily | float | New daily budget cap in USD |
| budget_total | float | New lifetime budget cap in USD |
| bid_cpm | float | Updated max bid CPM |
| targeting | object | Replaces the entire targeting config (see Create Campaign) |
| start_date | string | ISO 8601 date |
| end_date | string | ISO 8601 date |
curl -X PUT https://adverteks.com/api/advertiser/campaigns/101 \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{"status": "paused"}'
Permanently deletes a campaign and all associated creatives. Historical impression and analytics data is retained. Returns 200 {"success":true}.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | required | Internal creative name |
| ad_format | string | required | 728x90 | 300x250 | 320x50 | 160x600 |
| type | string | required | image | html |
| image_url | string | optional | HTTPS URL to creative image (for image type) |
| html_content | string | optional | Raw HTML markup (for html type). Max 64KB. |
| click_url | string | required | Landing page URL (HTTPS) |
| third_party_tracking_url | string | optional | Impression tracking pixel URL |
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| campaign_id | integer | Filter to specific campaign |
| start_date | string | ISO 8601 date YYYY-MM-DD |
| end_date | string | ISO 8601 date |
| granularity | string | hour | day | week. Default: day |
{
"success": true,
"analytics": [{
"date": "2026-03-22",
"impressions": 84210,
"clicks": 612,
"ctr": 0.73,
"spend": 210.53,
"cpm": 2.50,
"cpc": 0.34,
"conversions": 14
}]
}
Advertiser Billing & Wallet
Manage your advertising budget. Deposit funds, view transaction history, and download receipts. All spend is pre-paid — campaigns pause automatically when the wallet hits $0.
{
"success": true,
"billing": {
"balance": 142.50,
"total_deposited": 500.00,
"total_spent": 357.50,
"currency": "USD",
"auto_pause_threshold": 0.00
}
}
Initiates a Stripe-powered deposit. Returns a checkout_url — redirect the user to complete payment. Balance is credited immediately on successful payment.
POST /api/auth/reauth. The re-auth token expires in 5 minutes.Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| amount_usd | float | Required | Deposit amount in USD (minimum $10.00) |
| success_url | string | Optional | Redirect URL after successful payment |
curl -X POST https://adverteks.com/api/advertiser/billing/deposit \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{"amount_usd": 100.00}'
{
"success": true,
"checkout_url": "https://checkout.stripe.com/pay/cs_live_...",
"session_id": "cs_live_...",
"amount_usd": 100.00
}
Returns a paginated list of deposits and spend deductions.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| page | integer | Page number (default 1) |
| limit | integer | Results per page (default 50, max 200) |
| type | string | Filter: deposit | spend |
{
"success": true,
"transactions": [
{"id": 5001, "type": "deposit", "amount": 100.00, "created_at": "2026-03-20T14:22:00Z"},
{"id": 5002, "type": "spend", "amount": -1.42, "campaign_id": 101, "created_at": "2026-03-21T09:15:00Z"}
],
"total": 85,
"page": 1
}
Returns a list of PDF receipts for all successful deposits. Each receipt includes a download_url valid for 24 hours.
SSP API
Register and manage publisher sites, generate ad tags, configure floor prices, and access revenue analytics. Requires JWT Bearer token.
{
"success": true,
"sites": [{
"id": 55,
"name": "Tech Blog",
"domain": "techblog.example.com",
"status": "approved",
"floor_cpm": 1.00,
"created_at": "2026-01-15T10:22:00Z"
}]
}
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | required | Human-readable site name |
| domain | string | required | Site domain without protocol e.g. example.com |
| category | string | optional | IAB content category e.g. IAB1 |
| floor_cpm | float | optional | Minimum CPM floor USD. Default: 0.50 |
| description | string | optional | Site description for quality review |
Ad Zone Management
Ad zones define the placements on your site where ads will serve. Each zone maps to a specific ad format and generates a unique zone key for the JS tag.
{
"success": true,
"zones": [
{
"id": 12,
"zone_key": "zk_a3f9b2c1",
"ad_format": "300x250",
"name": "Sidebar Rectangle",
"status": "active",
"floor_cpm": 0.50,
"created_at": "2026-01-10T08:00:00Z"
}
]
}
Returns the new zone with its generated zone_key. Use the zone key in the JS embed tag.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Required | Descriptive name (e.g. "Header Leaderboard") |
| ad_format | string | Required | 728x90 | 300x250 | 320x50 | 160x600 |
| floor_cpm | float | Optional | Minimum CPM floor (default 0.50). Bids below this are excluded. |
curl -X POST https://adverteks.com/api/publisher/sites/7/zones \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{"name":"Header Leaderboard","ad_format":"728x90","floor_cpm":0.75}'
{
"success": true,
"zone": {
"id": 13,
"zone_key": "zk_b8e1d4f2",
"ad_format": "728x90",
"name": "Header Leaderboard",
"status": "active",
"floor_cpm": 0.75
}
}
Returns embeddable script tags for all approved ad zones. Each zone has a unique zoneKey used to serve ads.
{
"success": true,
"ad_tags": [{
"zone_id": 12,
"zone_key": "zk_a3f9b2c1",
"site_id": 55,
"ad_format": "300x250",
"tag": "<script src=\"https://adverteks.com/ad.js?z=zk_a3f9b2c1\"></script>"
}]
}
<div id="ad-container"></div> <script src="https://adverteks.com/ad.js?z=zk_a3f9b2c1"></script>
Query Parameters
| Parameter | Description |
|---|---|
| site_id | Filter to specific site |
| start_date | ISO 8601 date YYYY-MM-DD |
| end_date | ISO 8601 date |
| granularity | day | week | month |
{
"success": true,
"analytics": [{
"date": "2026-03-22",
"impressions": 24810,
"fill_rate": 87.4,
"revenue": 24.81,
"ecpm": 1.00,
"clicks": 181,
"ctr": 0.73
}]
}
{
"success": true,
"earnings": {
"available_balance": 142.80,
"pending_balance": 58.22,
"lifetime_earnings": 3291.50,
"revenue_share": 70,
"minimum_withdrawal": 25.00,
"currency": "USD"
}
}
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| start_date | string | ISO 8601 date YYYY-MM-DD |
| end_date | string | ISO 8601 date |
| page | integer | Page number (default 1) |
{
"success": true,
"transactions": [
{"id": 8001, "type": "impression_revenue", "amount": 0.0142, "site_id": 7, "zone_key": "zk_a3f9b2c1", "created_at": "2026-03-21T09:15:00Z"},
{"id": 8050, "type": "withdrawal", "amount": -50.00, "status": "paid", "created_at": "2026-03-15T12:00:00Z"}
],
"total": 1240
}
Withdrawals & Payment Methods
Publishers can withdraw available earnings once the $25.00 minimum threshold is met. Add a bank account or PayPal to receive payouts.
{
"success": true,
"payment_methods": [
{"id": 3, "type": "bank_transfer", "label": "Chase ****4521", "is_default": true, "created_at": "2026-01-12T10:00:00Z"}
]
}
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| type | string | Required | bank_transfer | paypal |
| label | string | Required | Friendly name for this method |
| details | object | Required | Account details (see below) |
{"type":"bank_transfer","label":"My Bank","details":{"account_holder":"Jane Doe","account_number":"****4521","routing_number":"021000021","bank_name":"Chase"}}
{"type":"paypal","label":"My PayPal","details":{"paypal_email":"jane@example.com"}}
Initiates a withdrawal of your available earnings balance. Payouts processed within 5 business days.
POST /api/auth/reauth. The token expires in 5 minutes.Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| amount | float | Required | Amount to withdraw in USD (minimum $25.00) |
| payment_method_id | integer | Required | ID of the saved payment method to pay out to |
curl -X POST https://adverteks.com/api/publisher/earnings/withdraw \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{"amount": 50.00, "payment_method_id": 3}'
{
"success": true,
"withdrawal": {
"id": 501,
"amount": 50.00,
"status": "pending",
"payment_method": "Chase ****4521",
"estimated_arrival": "2026-04-08",
"created_at": "2026-04-03T03:42:00Z"
}
}
Publisher JS Tag Setup
Complete guide to embedding Adverteks ad units on your site. Go from zone key to live revenue in under 10 minutes.
Minimal Tag (Copy & Paste)
Place this snippet wherever you want an ad unit to appear. Replace YOUR_ZONE_KEY with the zone key from your Ad Tags dashboard.
<!-- Adverteks Ad Unit --> <div id="adtks-zone-YOUR_ZONE_KEY"></div> <script src="https://adverteks.com/ad.js?z=YOUR_ZONE_KEY" async></script>
async on the script tag. This prevents the ad loader from blocking your page render. The div container is populated after the script executes.Supported Ad Formats
Adverteks serves three standard IAB display formats. Specify the desired format when creating ad zones in your dashboard. The ad tag script renders the correct dimensions automatically.
| Format Name | Dimensions | Best Placement | Typical eCPM |
|---|---|---|---|
| Medium Rectangle | 300 × 250 | Sidebar, in-content, below article | $1.00–$3.50 |
| Leaderboard | 728 × 90 | Page header / footer, above fold | $0.80–$2.80 |
| Mobile Banner | 320 × 50 | Mobile sticky bottom, between content blocks | $0.50–$1.80 |
<!-- 300x250 Medium Rectangle --> <div id="adtks-zone-zk_a3f9b2c1" style="width:300px;height:250px;overflow:hidden;"></div> <script src="https://adverteks.com/ad.js?z=zk_a3f9b2c1" async></script>
<!-- 728x90 Leaderboard --> <div id="adtks-zone-zk_b8e1d4f2" style="width:728px;height:90px;overflow:hidden;"></div> <script src="https://adverteks.com/ad.js?z=zk_b8e1d4f2" async></script>
<!-- 320x50 Mobile Banner --> <div id="adtks-zone-zk_c5a7e3b9" style="width:320px;height:50px;overflow:hidden;"></div> <script src="https://adverteks.com/ad.js?z=zk_c5a7e3b9" async></script>
Advanced Configuration
Multiple Zones on One Page
Each zone is independent. Drop as many snippets as you need — one script tag per zone, each with its own container div. Scripts load in parallel; there is no shared loader to initialize.
<!-- Header leaderboard --> <div id="adtks-zone-zk_b8e1d4f2" style="width:728px;height:90px;"></div> <script src="https://adverteks.com/ad.js?z=zk_b8e1d4f2" async></script> <!-- Sidebar 300x250 --> <div id="adtks-zone-zk_a3f9b2c1" style="width:300px;height:250px;"></div> <script src="https://adverteks.com/ad.js?z=zk_a3f9b2c1" async></script> <!-- Mobile sticky (hidden on desktop via CSS) --> <div id="adtks-zone-zk_c5a7e3b9" style="width:320px;height:50px;"></div> <script src="https://adverteks.com/ad.js?z=zk_c5a7e3b9" async></script>
Lazy Loading (Intersection Observer)
For below-the-fold zones, defer loading until the container is about to enter the viewport. This improves page load performance and viewability scores (which increase eCPM).
<div id="adtks-zone-zk_a3f9b2c1" style="width:300px;height:250px;"></div>
<script>
(function() {
var container = document.getElementById('adtks-zone-zk_a3f9b2c1');
var observer = new IntersectionObserver(function(entries) {
if (entries[0].isIntersecting) {
var s = document.createElement('script');
s.src = 'https://adverteks.com/ad.js?z=zk_a3f9b2c1';
s.async = true;
document.body.appendChild(s);
observer.disconnect();
}
}, { rootMargin: '200px' });
observer.observe(container);
})();
</script>
Responsive Container (Fluid Width)
Wrap the ad container in a fluid div to handle varying page widths. The ad renders at the zone's declared size but the outer wrapper prevents layout overflow on small screens.
<div style="max-width:728px; width:100%; text-align:center; margin:0 auto;"> <div id="adtks-zone-zk_b8e1d4f2" style="width:728px;height:90px;display:inline-block;"></div> <script src="https://adverteks.com/ad.js?z=zk_b8e1d4f2" async></script> </div>
Retrieving Your Zone Key via API
If you manage many sites programmatically, fetch zone keys via the Ad Tags API instead of copying them from the dashboard:
curl -s https://adverteks.com/api/publisher/ad-tags \
-H "Authorization: Bearer YOUR_JWT_TOKEN" | jq '.ad_tags[] | {zone_key, ad_format}'
[
{ "zone_key": "zk_a3f9b2c1", "ad_format": "300x250" },
{ "zone_key": "zk_b8e1d4f2", "ad_format": "728x90" },
{ "zone_key": "zk_c5a7e3b9", "ad_format": "320x50" }
]
Content Security Policy (CSP)
If your site sends a Content-Security-Policy header, add Adverteks to the allowed origins for scripts and frames:
Content-Security-Policy: script-src 'self' https://adverteks.com; frame-src 'self' https://adverteks.com; img-src 'self' https://adverteks.com data:;
img-src * data: and frame-src * to avoid blocking rendered ads.Verifying Tag Installation
After embedding, verify the tag loaded correctly in your browser:
- Open DevTools → Network tab → filter by
ad.js - Confirm the script request returns 200
- Check the
adtks-zone-*div — it should contain an<iframe>or<ins>element after load - Impressions appear in your Publisher Dashboard → Analytics within ~5 minutes
Affiliate API
Earn commissions by referring publishers and advertisers to Adverteks. The affiliate program features multi-level tracking, real-time commission calculations, and flexible payout options.
One-time registration to join the affiliate program. Requires an existing Adverteks account (publisher or advertiser). Returns your affiliate profile with unique referral code.
curl -X POST https://adverteks.com/api/v1/affiliate/register \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{"agreed_to_terms": true}'
{
"success": true,
"affiliate": {
"id": 88,
"referral_code": "ADTK-abc123",
"referral_url": "https://adverteks.com/?ref=ADTK-abc123",
"status": "active",
"commission_rate": 0.10,
"created_at": "2026-04-03T03:42:00Z"
}
}
Returns your affiliate profile including referral code, commission rate, and payout status.
{
"success": true,
"affiliate": {
"id": 88,
"referral_code": "ADTK-abc123",
"referral_url": "https://adverteks.com/?ref=ADTK-abc123",
"status": "active",
"commission_rate": 0.10,
"tier": "standard"
}
}
Returns aggregate performance metrics: total referred users, active accounts, lifetime commissions, and current period earnings.
curl https://adverteks.com/api/v1/affiliate/dashboard \ -H "Authorization: Bearer YOUR_JWT"
{
"success": true,
"dashboard": {
"total_referrals": 14,
"active_referrals": 11,
"pending_referrals": 3,
"lifetime_commissions_usd": 284.50,
"current_period_commissions_usd": 42.10,
"available_balance_usd": 142.50,
"pending_balance_usd": 42.10,
"top_referral": {"email": "pub***@example.com", "revenue_generated_usd": 3200.00}
}
}
Returns a paginated list of individual commission events — one record per referred account billing event.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| status | string | pending | approved | paid |
| start_date | string | ISO 8601 date YYYY-MM-DD |
| end_date | string | ISO 8601 date |
| page | integer | Page number (default 1) |
| limit | integer | Results per page (default 50) |
{
"success": true,
"commissions": [
{
"id": 2001,
"referred_user": "pub***@example.com",
"event_type": "impression_revenue",
"referred_revenue_usd": 24.81,
"commission_usd": 2.48,
"commission_rate": 0.10,
"status": "approved",
"earned_at": "2026-03-21T00:00:00Z"
}
],
"total": 341,
"page": 1
}
Returns the tree of referred accounts with their current status and lifetime revenue generated.
{
"success": true,
"payouts": [
{"id": 301, "amount_usd": 100.00, "status": "paid", "method": "bank_transfer", "paid_at": "2026-03-10T00:00:00Z"},
{"id": 302, "amount_usd": 42.50, "status": "pending", "method": "paypal", "requested_at": "2026-04-01T00:00:00Z"}
]
}
Submit a payout request. Minimum $50.00. Processed within 10 business days.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| amount_usd | float | Required | Amount to withdraw (minimum $50.00) |
| method | string | Required | bank_transfer | paypal |
| payout_details | object | Required | Bank or PayPal details |
curl -X POST https://adverteks.com/api/v1/affiliate/payouts/request \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{
"amount_usd": 100.00,
"method": "paypal",
"payout_details": {"paypal_email": "you@example.com"}
}'
Marketing Tools
The GET /api/v1/affiliate/tools endpoint returns ready-made marketing assets: banner ad HTML, text links, and landing page copy variants for your referral URL.
{
"success": true,
"tools": {
"referral_url": "https://adverteks.com/?ref=ADTK-abc123",
"banners": [
{"size": "728x90", "html": "<a href='...'><img src='...'></a>"}
],
"text_links": [
{"label": "Monetize your traffic with Adverteks", "url": "https://adverteks.com/?ref=ADTK-abc123"}
]
}
}
Referral Stats Endpoints
| Endpoint | Method | Description |
|---|---|---|
| /api/referral/stats | GET | Summary stats: clicks, sign-ups, conversions, revenue generated |
| /api/referral/network | GET | Full referral tree with per-account revenue breakdown |
| /api/referral/commissions | GET | Alias for /api/v1/affiliate/commissions |
| /api/referral/leaderboard | GET | Public affiliate leaderboard (top 10 earners, anonymized) |
| /api/v1/affiliate/status | GET | Check affiliate registration status (no requireAffiliate needed) |
Ad Exchange
How the real-time auction engine works, clearing price calculation, and platform economics.
Auction Mechanics
Adverteks runs a second-price sealed-bid (Vickrey) auction on every ad request. The highest bidder wins but pays the second-highest bid price plus $0.01.
Ad Formats
| Format Code | Dimensions | IAB Classification | Common Placement |
|---|---|---|---|
| 728x90 | 728 x 90 px | Leaderboard | Page header, above fold |
| 300x250 | 300 x 250 px | Medium Rectangle | Sidebar, in-content |
| 320x50 | 320 x 50 px | Mobile Banner | Mobile top/bottom bar |
| 160x600 | 160 x 600 px | Wide Skyscraper | Right rail |
Linear Pacing
Campaigns use linear pacing to spread budget evenly over campaign lifetime. The system calculates an hourly spend target and scales bid participation accordingly.
Ad Serving Endpoint
Called automatically by the embedded ad tag script. Returns the winning creative HTML.
| Parameter | Type | Description |
|---|---|---|
| zoneKey | string | Zone identifier from ad tag |
| lat | float | Visitor latitude for geo-targeting |
| lng | float | Visitor longitude |
| page_url | string | URL-encoded page URL for contextual targeting |
Webhooks
Subscribe to real-time event notifications for wins, impressions, clicks, and conversions. Delivered via HTTP POST to your configured endpoint.
Event Types
| Event | Trigger | Key Payload Fields |
|---|---|---|
| bid.win | Bid won the auction | auction_id, clearing_price, creative_id |
| impression | Ad rendered in browser | impression_id, auction_id, timestamp |
| click | User clicked the ad | impression_id, auction_id, timestamp |
| conversion | Attributed post-click conversion | impression_id, revenue, timestamp |
| budget.depleted | Campaign budget exhausted | campaign_id, budget_type |
{
"event": "impression",
"timestamp": 1742656000000,
"data": {
"impression_id": "imp-9f3c2a1b",
"auction_id": "7f3d2a11-c4b8-4e9a-b2f1-a3c9e8d72f01",
"campaign_id": 101,
"creative_id": "cr-4d9a2f",
"ad_format": "300x250",
"clearing_price": 1.42
}
}
Verifying Webhook Signatures
All webhook deliveries include an X-Adverteks-Signature header — HMAC-SHA256 of the raw request body signed with your partner secret key.
const crypto = require('crypto');
function verifyWebhook(rawBody, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
Webhook CRUD API
Programmatically register, update, and manage webhook endpoints. Webhooks deliver real-time event payloads to your HTTP endpoint on auction wins, impressions, clicks, conversions, and budget events.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| url | string | Required | HTTPS endpoint to receive event payloads |
| events | array | Required | Event types to subscribe to (see Event Types table) |
| secret | string | Optional | HMAC signing secret. If omitted, one is auto-generated. |
| description | string | Optional | Friendly label for this webhook |
curl -X POST https://adverteks.com/api/v1/webhooks \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/adverteks",
"events": ["bid.win", "impression", "click", "budget.depleted"],
"description": "Production campaign monitoring"
}'
{
"success": true,
"webhook": {
"id": 9,
"url": "https://your-server.com/webhooks/adverteks",
"events": ["bid.win","impression","click","budget.depleted"],
"secret": "whsec_a8f2b3c1d4e5f6...",
"status": "active",
"description": "Production campaign monitoring",
"created_at": "2026-04-03T03:42:00Z"
}
}
{
"success": true,
"webhooks": [
{
"id": 9,
"url": "https://your-server.com/webhooks/adverteks",
"events": ["bid.win","impression"],
"status": "active",
"last_delivery_at": "2026-04-02T22:14:00Z",
"delivery_success_rate": 99.8
}
]
}
Update the URL, subscribed events, or disable a webhook. Partial updates — only fields you provide are changed.
curl -X PATCH https://adverteks.com/api/v1/webhooks/9 \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{"status": "disabled"}'
curl -X PATCH https://adverteks.com/api/v1/webhooks/9 \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{"events": ["bid.win","conversion"]}'
Permanently removes the webhook. No further events will be delivered to this endpoint.
curl -X DELETE https://adverteks.com/api/v1/webhooks/9 \ -H "Authorization: Bearer YOUR_JWT"
Delivery & Retry Policy
| Property | Value |
|---|---|
| Delivery timeout | 10 seconds per attempt |
| Expected response | Any 2xx HTTP status |
| Retry attempts | Up to 5 retries with exponential backoff (1s, 4s, 16s, 64s, 256s) |
| Payload delivery | At-least-once. Your handler should be idempotent. |
| Signature header | X-Adverteks-Signature — HMAC-SHA256 of raw body |
| Event ordering | Best-effort. High-volume events may arrive out of order. |
Supported Event Types
| Event | Trigger | Key Payload Fields |
|---|---|---|
| bid.win | Adverteks bid won the auction | auction_id, clearing_price, creative_id, campaign_id |
| impression | Ad rendered in browser | impression_id, auction_id, zone_key, timestamp |
| click | User clicked the ad | impression_id, auction_id, timestamp |
| conversion | Post-click conversion attributed | impression_id, revenue_usd, timestamp |
| budget.depleted | Campaign balance reached $0 | campaign_id, budget_type (daily | total) |
Receiver Example (Node.js/Express)
const crypto = require('crypto');
const express = require('express');
const app = express();
// Raw body needed for HMAC verification
app.use('/webhooks/adverteks', express.raw({ type: 'application/json' }));
app.post('/webhooks/adverteks', (req, res) => {
const sig = req.headers['x-adverteks-signature'];
const secret = process.env.ADVERTEKS_WEBHOOK_SECRET;
const expected = crypto
.createHmac('sha256', secret)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig))) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
console.log(`Received ${event.event}:`, event.data);
// Handle by type
if (event.event === 'bid.win') {
// Track win in your system
} else if (event.event === 'budget.depleted') {
// Trigger budget top-up alert
}
res.status(200).send('OK');
});
app.listen(3000);
Receiver Example (Python/Flask)
import hmac
import hashlib
import json
from flask import Flask, request, jsonify
app = Flask(__name__)
def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
"""Verify HMAC-SHA256 signature from X-Adverteks-Signature header"""
expected = hmac.new(
secret.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
@app.route('/webhooks/adverteks', methods=['POST'])
def handle_webhook():
# Get signature from header (format: sha256=...)
signature = request.headers.get('X-Adverteks-Signature', '')
if signature.startswith('sha256='):
signature = signature[7:] # Remove 'sha256=' prefix
secret = request.headers.get('X-Webhook-Secret') or 'your_secret_here'
raw_body = request.get_data()
# Verify signature if secret is configured
if signature and not verify_signature(raw_body, signature, secret):
return jsonify({'error': 'Invalid signature'}), 401
event = json.loads(raw_body)
event_type = event.get('event')
data = event.get('data', {})
print(f"Received {event_type}:", data)
# Handle by event type
if event_type == 'impression.served':
# Track impression - data contains impression.id, ad_unit_id, campaign_id
pass
elif event_type == 'click.tracked':
# Track click - data contains click.id, impression_id, url
pass
elif event_type == 'conversion.recorded':
# Track conversion - data contains conversion.id, value, currency
pass
elif event_type == 'campaign.budget_exhausted':
# Alert: campaign needs more budget
pass
elif event_type == 'payout.completed':
# Payment sent to publisher
pass
elif event_type == 'publisher.site_approved':
# Site is now live
pass
return jsonify({'status': 'ok'}), 200
if __name__ == '__main__':
app.run(port=3000, debug=False)
Receiver Example (PHP/Laravel)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Hash;
class WebhookController extends Controller
{
/**
* Handle incoming Adverteks webhook
*/
public function handleAdverteks(Request $request)
{
// Get signature from header (format: sha256=...)
$signature = $request->header('X-Adverteks-Signature', '');
if (str_starts_with($signature, 'sha256=')) {
$signature = substr($signature, 7);
}
// Get raw body for signature verification
$rawBody = $request->getContent();
$secret = config('services.adverteks.webhook_secret');
// Verify HMAC-SHA256 signature
if ($signature && $secret) {
$expected = hash_hmac('sha256', $rawBody, $secret);
if (!hash_equals($expected, $signature)) {
return response()->json(['error' => 'Invalid signature'], 401);
}
}
$event = json_decode($rawBody, true);
$eventType = $event['event'] ?? null;
$data = $event['data'] ?? [];
Log::info("Adverteks webhook: {$eventType}", $data);
// Handle by event type
match ($eventType) {
'impression.served' => $this->handleImpression($data),
'click.tracked' => $this->handleClick($data),
'conversion.recorded' => $this->handleConversion($data),
'campaign.budget_exhausted' => $this->handleBudgetExhausted($data),
'payout.completed' => $this->handlePayout($data),
'publisher.site_approved' => $this->handleSiteApproved($data),
default => null,
};
return response()->json(['status' => 'ok']);
}
private function handleImpression(array $data): void
{
// $data['impression']['id'], $data['impression']['campaign_id'], etc.
}
private function handleClick(array $data): void
{
// $data['click']['id'], $data['click']['url'], etc.
}
private function handleConversion(array $data): void
{
// $data['conversion']['value'], $data['conversion']['currency'], etc.
}
private function handleBudgetExhausted(array $data): void
{
// Notify advertiser to add funds
}
private function handlePayout(array $data): void
{
// Update publisher balance
}
private function handleSiteApproved(array $data): void
{
// Site is now live, start serving ads
}
}
Error Codes
Standard error response format and HTTP status codes returned by all API endpoints.
Error Response Format
{
"success": false,
"message": "Human-readable error description",
"code": "MACHINE_READABLE_CODE"
}
HTTP Status Codes
- 200OKRequest succeeded. Response body contains data.
- 204No ContentRTB: no eligible bid found. Empty body.
- 400Bad RequestMissing or invalid parameters. See message field for details.
- 401UnauthorizedMissing or expired authentication token. Re-authenticate.
- 403ForbiddenToken valid but insufficient permissions for this resource.
- 404Not FoundResource does not exist or belongs to another account.
- 429Too Many RequestsRate limit exceeded. See Retry-After header.
- 500Internal Server ErrorUnexpected server error. Contact support@adverteks.com.
Application Error Codes
| Code | HTTP | Description |
|---|---|---|
| INVALID_BID_REQUEST | 400 | OpenRTB BidRequest missing required fields or fails validation |
| BANNER_REQUIRED | 204 | Bid request has no banner impression object |
| BELOW_FLOOR | 204 | Highest bid was below the effective floor CPM |
| TOKEN_EXPIRED | 401 | JWT expired. Request new token via /api/auth/login |
| BUDGET_EXHAUSTED | 400 | Campaign budget depleted. Top up wallet or increase budget. |
| SITE_NOT_APPROVED | 403 | Site registration still pending review |
| CAMPAIGN_INACTIVE | 400 | Campaign is paused, ended, or not yet started |
| RATE_LIMIT_EXCEEDED | 429 | Too many requests in current window. Honor Retry-After. |
Partner Onboarding
Everything you need to connect as an external DSP or SSP — registration, sandbox access, and supply chain compliance.
Registration Process
External DSP/SSP integration is approval-gated. There is no self-serve API key creation — this ensures inventory quality and prevents fraudulent traffic from entering the exchange.
What to Include in Your Integration Request
| Field | Description |
|---|---|
| Company name | Legal entity name |
| Platform type | DSP (demand-side) or SSP (supply-side) |
| Daily bid volume | Expected QPS / daily impression volume |
| Geo focus | Primary countries and device types |
| Ad categories | IAB content categories you trade in |
| Technical contact | Name + email for integration support |
Sandbox Environment
The sandbox environment mirrors the production API with deterministic test responses. Use it to validate bid request formatting, HMAC signatures, and win notice delivery before going live.
| Property | Value |
|---|---|
| Sandbox base URL | https://adverteks.com (same host, sandbox activated per API key) |
| Sandbox bid endpoint | POST /api/rtb/bid — same path; sandbox keys always return a deterministic bid |
| Test API key prefix | adtks_test_ — sandbox keys are issued during onboarding |
| Clearing price | Always returns $1.00 CPM in sandbox |
| Win notices | Accepted and logged; no actual billing |
| Rate limits | 100 req/min (lower than production) |
curl -X POST https://adverteks.com/api/rtb/bid \
-H "Content-Type: application/json" \
-H "X-Api-Key: adtks_test_your_sandbox_key" \
-H "X-OpenRTB-Version: 2.5" \
-d '{
"id": "test-auction-001",
"imp": [{"id": "1", "banner": {"w": 300, "h": 250}, "bidfloor": 0.50}],
"tmax": 150
}'
A valid sandbox response looks identical to a production BidResponse. HTTP 200 with a seatbid payload confirms your request format is correct.
ads.txt & sellers.json
Adverteks participates in the IAB supply chain transparency framework. Publishers monetizing via Adverteks must add the following entry to their ads.txt file. DSPs verifying inventory can check Adverteks in sellers.json.
ads.txt Entry
Add to the root ads.txt of every domain monetized through Adverteks:
adverteks.com, pub-XXXXXXXXXXXXXXXX, DIRECT, f08c47fec0942fa0
pub-XXXXXXXXXXXXXXXX with your Publisher ID, visible in your publisher dashboard under Settings → Account.sellers.json
Adverteks publishes its sellers.json at:
https://adverteks.com/.well-known/sellers.json
DSPs should validate that impression supply chains reference Adverteks using seller_id values matching your Publisher ID. The file is updated daily.
app-ads.txt (Mobile / CTV)
For in-app inventory, add the same entry to your app-ads.txt file (hosted at your developer domain root):
adverteks.com, pub-XXXXXXXXXXXXXXXX, DIRECT, f08c47fec0942fa0
Code Examples
Ready-to-run examples for the most common integration workflows. Copy, replace credentials, and run.
cURL Examples
Bid Request (no HMAC)
curl -s -X POST https://adverteks.com/api/rtb/bid \
-H "Content-Type: application/json" \
-H "X-Api-Key: adtks_live_YOUR_API_KEY" \
-H "X-OpenRTB-Version: 2.5" \
-d '{
"id": "7f3d2a11-c4b8-4e9a-b2f1-a3c9e8d72f01",
"imp": [{
"id": "1",
"banner": { "w": 300, "h": 250, "pos": 1 },
"bidfloor": 0.50,
"bidfloorcur": "USD"
}],
"site": {
"page": "https://example.com/article",
"domain": "example.com",
"cat": ["IAB1"]
},
"device": {
"geo": { "lat": 40.7128, "lon": -74.0060, "country": "USA", "city": "New York" },
"ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"devicetype": 2
},
"user": { "id": "user-abc123" },
"tmax": 150
}'
Bid Request with HMAC Signature (bash function)
#!/usr/bin/env bash
API_KEY="adtks_live_YOUR_API_KEY"
HMAC_SECRET="your-hmac-secret"
ENDPOINT="https://adverteks.com/api/rtb/bid"
BODY='{
"id": "auction-12345",
"imp": [{"id": "1", "banner": {"w": 728, "h": 90}, "bidfloor": 1.00}],
"tmax": 150
}'
# Compute HMAC-SHA256 over the raw body
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$HMAC_SECRET" -hex | awk '{print "sha256="$2}')
curl -s -X POST "$ENDPOINT" \
-H "Content-Type: application/json" \
-H "X-Api-Key: $API_KEY" \
-H "X-OpenRTB-Version: 2.5" \
-H "X-Signature-SHA256: $SIG" \
-d "$BODY"
Win Notice
curl -s -X POST "https://adverteks.com/api/rtb/win?aid=auction-12345&price=1.42" \ -H "X-Api-Key: adtks_live_YOUR_API_KEY"
Node.js Full Example
A complete bid → win → event tracking flow using the built-in fetch API (Node 18+).
const crypto = require('crypto');
const CONFIG = {
apiKey: process.env.ADVERTEKS_API_KEY,
hmacSecret: process.env.ADVERTEKS_HMAC_SECRET,
host: 'adverteks.com',
};
// ── Build auth headers ──────────────────────────────────────────────────────
function authHeaders(bodyStr) {
const sig = crypto
.createHmac('sha256', CONFIG.hmacSecret)
.update(bodyStr, 'utf8')
.digest('hex');
return {
'Content-Type': 'application/json',
'X-Api-Key': CONFIG.apiKey,
'X-OpenRTB-Version': '2.5',
'X-Signature-SHA256': `sha256=${sig}`,
};
}
// ── Submit bid request ───────────────────────────────────────────────────────
async function bid(bidRequest) {
const body = JSON.stringify(bidRequest);
const res = await fetch(`https://${CONFIG.host}/api/rtb/bid`, {
method: 'POST',
headers: authHeaders(body),
body,
signal: AbortSignal.timeout(200),
});
if (res.status === 204) return null;
if (!res.ok) throw new Error(`Bid error ${res.status}: ${await res.text()}`);
return res.json();
}
// ── Send win notice ──────────────────────────────────────────────────────────
async function sendWin(auctionId, clearingPriceCpm) {
const res = await fetch(
`https://${CONFIG.host}/api/rtb/win?aid=${auctionId}&price=${clearingPriceCpm}`,
{ method: 'POST', headers: { 'X-Api-Key': CONFIG.apiKey } }
);
if (!res.ok) console.error('Win notice failed:', res.status);
}
// ── Track impression ─────────────────────────────────────────────────────────
async function trackImpression(auctionId) {
const body = JSON.stringify({ auction_id: auctionId, event_type: 'impression' });
await fetch(`https://${CONFIG.host}/api/rtb/event`, {
method: 'POST', headers: authHeaders(body), body,
});
}
// ── Example usage ────────────────────────────────────────────────────────────
(async () => {
const bidRequest = {
id: crypto.randomUUID(),
imp: [{ id: '1', banner: { w: 300, h: 250 }, bidfloor: 0.5 }],
site: { page: 'https://example.com/', domain: 'example.com' },
device: { geo: { lat: 37.77, lon: -122.41, country: 'USA' } },
user: { id: 'user-seg-xyz' },
tmax: 150,
};
const response = await bid(bidRequest);
if (!response) { console.log('No bid'); return; }
const bidItem = response.seatbid[0].bid[0];
const clearingCpm = bidItem.price;
console.log(`Won at $${clearingCpm} CPM | Creative: ${bidItem.crid}`);
// Fire win notice and impression in parallel
await Promise.all([
sendWin(bidRequest.id, clearingCpm),
trackImpression(bidRequest.id),
]);
console.log('Win + impression logged');
})();
Python Full Example
Requires Python 3.8+ and no external dependencies beyond the standard library.
import hmac
import hashlib
import json
import os
import uuid
import urllib.request
import urllib.error
from typing import Optional
API_KEY = os.environ['ADVERTEKS_API_KEY']
HMAC_SECRET = os.environ['ADVERTEKS_HMAC_SECRET']
BASE_URL = 'https://adverteks.com'
# ── Build auth headers ──────────────────────────────────────────────────────
def auth_headers(body_bytes: bytes) -> dict:
sig = hmac.new(HMAC_SECRET.encode(), body_bytes, hashlib.sha256).hexdigest()
return {
'Content-Type': 'application/json',
'X-Api-Key': API_KEY,
'X-OpenRTB-Version': '2.5',
'X-Signature-SHA256': f'sha256={sig}',
}
# ── Submit bid request ───────────────────────────────────────────────────────
def bid(bid_request: dict) -> Optional[dict]:
body = json.dumps(bid_request, separators=(',', ':')).encode()
req = urllib.request.Request(
f'{BASE_URL}/api/rtb/bid',
data=body, headers=auth_headers(body), method='POST'
)
try:
with urllib.request.urlopen(req, timeout=0.2) as r:
return json.loads(r.read()) if r.status == 200 else None
except urllib.error.HTTPError as e:
if e.code == 204: return None
raise
# ── Send win notice ──────────────────────────────────────────────────────────
def send_win(auction_id: str, clearing_price_cpm: float) -> None:
url = f'{BASE_URL}/api/rtb/win?aid={auction_id}&price={clearing_price_cpm}'
req = urllib.request.Request(url, method='POST',
headers={'X-Api-Key': API_KEY})
try:
urllib.request.urlopen(req, timeout=1)
except urllib.error.HTTPError as e:
print(f'Win notice error: {e.code}')
# ── Track event ──────────────────────────────────────────────────────────────
def track_event(auction_id: str, event_type: str) -> None:
body = json.dumps({'auction_id': auction_id, 'event_type': event_type}).encode()
req = urllib.request.Request(
f'{BASE_URL}/api/rtb/event',
data=body, headers=auth_headers(body), method='POST'
)
urllib.request.urlopen(req, timeout=1)
# ── Example usage ────────────────────────────────────────────────────────────
if __name__ == '__main__':
bid_request = {
'id': str(uuid.uuid4()),
'imp': [{'id': '1', 'banner': {'w': 300, 'h': 250}, 'bidfloor': 0.50}],
'site': {'page': 'https://example.com/', 'domain': 'example.com'},
'device': {'geo': {'lat': 37.77, 'lon': -122.41, 'country': 'USA'}},
'user': {'id': 'user-xyz'},
'tmax': 150,
}
response = bid(bid_request)
if not response:
print('No bid')
else:
bid_item = response['seatbid'][0]['bid'][0]
clearing_cpm = bid_item['price']
print(f'Won at ${clearing_cpm:.3f} CPM | Creative: {bid_item["crid"]}')
send_win(bid_request['id'], clearing_cpm)
track_event(bid_request['id'], 'impression')
print('Win + impression logged')