api_reference v1 stable

API Documentation

Everything in the dashboard is available over the API. Manage campaigns, creatives, and zones, pull statistics, receive conversions, and subscribe to events.

base url: https://api.d4rkw3b.network/v1 format: JSON timezone: UTC updated: 22 October 2026

01 Overview

The D4RKW3B API is a REST API over HTTPS. All requests and responses use JSON with UTF-8 encoding. Timestamps are ISO 8601 in UTC. Monetary values are decimal strings in US dollars (for example "12.50") to avoid floating-point rounding. Identifiers are opaque strings and should not be parsed.

The current version is v1, carried in the URL path. Backwards-compatible changes (new fields, new endpoints, new enum values) are made without a version change; clients should ignore unknown fields. Breaking changes will be released under v2 with at least 12 months of parallel support for v1.

TLS 1.2 or higher is required. HTTP requests are rejected, not redirected.

02 Authentication

Create API keys under Settings → API Keys in the dashboard. Each key has one of three scopes:

ScopeAccess
advertiserFull read and write on campaigns, creatives, targeting, and advertiser statistics; read on balance
publisherFull read and write on zones and tags; read on publisher statistics and payouts
readRead-only on everything the account can see; suitable for reporting integrations

Send the key as a bearer token in the Authorization header on every request.

// request header
Authorization: Bearer d4k_live_8f2a91c4e7b3d6f0a1c5e9b2d4f7a3c8

Keys are shown once at creation. Rotate keys from the dashboard; a rotated key remains valid for 24 hours so that deployments can be updated without downtime. Keys inherit the permissions of the user who created them and are revoked when that user is removed from the account. Never embed a key in client-side code or in a publisher tag.

03 Rate Limits

Limits apply per API key over a rolling 60-second window.

Endpoint groupLimit
Read endpoints (GET)600 requests per minute
Write endpoints (POST, PATCH, DELETE)120 requests per minute
Statistics endpoints60 requests per minute, maximum 31-day range per request
Creative uploads30 requests per minute, 20 MB per file

Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (Unix timestamp) headers. When a limit is exceeded the API returns 429 Too Many Requests with a Retry-After header in seconds. Clients should back off exponentially and never retry a 429 immediately. Higher limits are available for managed-service accounts on request.

04 Errors

Errors use standard HTTP status codes and a consistent body.

// error response
{
  "error": {
    "code": "validation_failed",
    "message": "targeting.geo must contain at least one country code",
    "field": "targeting.geo",
    "request_id": "req_01J9X4M2K7P3Q8R5"
  }
}
StatusCodeMeaning
400validation_failedA field is missing or invalid; field identifies it
401unauthenticatedMissing, malformed, revoked, or expired API key
403forbiddenThe key's scope does not permit this action, or the account is restricted
404not_foundThe resource does not exist or belongs to another account
409conflictThe action conflicts with current state, for example activating a campaign with no approved creatives
402insufficient_balanceThe advertiser balance cannot cover the requested action
422policy_violationThe creative or landing page was rejected at automated pre-screen; message explains why
429rate_limitedRate limit exceeded; honour Retry-After
500internal_errorUnexpected failure; retry with backoff and quote request_id to support if it persists
503maintenancePlanned maintenance in progress; see the status page

Include the request_id in any support request about a failed call.

05 Pagination

List endpoints return up to limit items (default 50, maximum 200) and a next_cursor when more results exist. Pass it back as cursor to fetch the next page. Cursors are valid for 10 minutes.

// paginated response
{
  "data": [ ... ],
  "next_cursor": "eyJpZCI6ImNtcF8wMUo5WDQifQ",
  "has_more": true
}

06 Campaigns

A campaign groups creatives, targeting, a pricing model, a bid, and budgets. Campaigns are created in draft status, move to review when activated, and serve when status is active. Scope: advertiser.

GET/campaigns

List campaigns. Filters: status (draft, review, active, paused, rejected, completed), vertical, format.

POST/campaigns

Create a campaign.

// request body
{
  "name": "Casino DE push Q4",
  "vertical": "igaming",
  "format": "push",
  "pricing_model": "cpc",
  "bid": "0.085",
  "daily_budget": "500.00",
  "total_budget": "15000.00",
  "landing_url": "https://example-casino.com/lp/de?click_id={click_id}&zone={zone_id}",
  "targeting": {
    "geo": ["DE", "AT"],
    "device": ["mobile"],
    "os": ["android"],
    "frequency_cap": { "impressions": 3, "per_hours": 24 },
    "schedule": { "timezone": "Europe/Berlin", "hours": [10, 11, 12, 18, 19, 20, 21, 22] }
  }
}
FieldTypeNotes
namestringRequired, 1 to 120 characters
verticalenumRequired. igaming, sportsbook, crypto, adult, sweeps, nutra, dating, forex, vpn, streaming, mainstream
formatenumRequired. display, pop, push, native, interstitial, video
pricing_modelenumRequired. cpm, cpc, or cpa (CPA requires an approved postback integration)
biddecimal stringRequired. Per 1,000 impressions for CPM, per click for CPC, per conversion for CPA
daily_budgetdecimal stringRequired, minimum "10.00"
total_budgetdecimal stringOptional; campaign completes when reached
landing_urlstringRequired. HTTPS. May contain tracking macros; see section 13
targetingobjectRequired; see section 8
start_at, end_atISO 8601Optional scheduling bounds
GET/campaigns/{campaign_id}

Retrieve a campaign, including its status, review object (reviewer notes and rejection reason if any), spend to date, and attached creative IDs.

PATCH/campaigns/{campaign_id}

Update any field from the create body. Changing landing_url or vertical on an active campaign returns it to review. Bid and budget changes apply within 60 seconds without re-review.

POST/campaigns/{campaign_id}/activate

Submit a draft for review, or resume a paused campaign. Requires at least one approved creative and sufficient balance for one day of the daily budget; otherwise returns 409 or 402.

POST/campaigns/{campaign_id}/pause

Stop delivery. Takes effect within 60 seconds. Spend already committed in open auctions may still be billed.

DELETE/campaigns/{campaign_id}

Archive a campaign. Archived campaigns stop serving, remain visible in statistics, and cannot be reactivated.

07 Creatives

Creatives belong to a campaign and are reviewed individually. A campaign serves only its approved creatives. Scope: advertiser.

POST/campaigns/{campaign_id}/creatives

Upload a creative as multipart/form-data. Fields depend on format.

FormatFieldsSpecifications
displayfileJPG, PNG, GIF, or HTML5 ZIP. Sizes 300x250, 728x90, 160x600, 320x50, 300x600, 336x280. Max 500 KB (2 MB for HTML5).
pushtitle, body, icon, imageTitle max 30 characters, body max 45. Icon 192x192 PNG. Image 360x240 JPG or PNG, optional.
nativetitle, description, image, brandTitle max 60, description max 120, brand max 25. Image 600x400 JPG or PNG.
popnonePop campaigns serve the landing URL directly; no creative upload needed.
interstitialfileJPG or PNG at 320x480, 480x320, 768x1024, or 1024x768. Max 800 KB.
videofile or vast_urlMP4 H.264, 16:9, 6 to 30 seconds, max 20 MB; or a VAST 4.x tag URL.

The response includes the creative id and status: "review". Automated pre-screen failures return 422 immediately with the reason.

GET/campaigns/{campaign_id}/creatives

List creatives with status (review, approved, rejected, archived), review notes, and per-creative CTR for the last 7 days.

DELETE/creatives/{creative_id}

Archive a creative. It stops serving immediately.

08 Targeting Object

All targeting fields are optional except geo. Omitted fields mean "all". Lists are inclusive; use exclude_ prefixed fields for exclusions.

FieldTypeValues
geoarrayISO 3166-1 alpha-2 country codes. Required. Restricted verticals are automatically limited to markets permitted for the advertiser's verified licences.
regionarrayISO 3166-2 subdivision codes, for example US-CA
cityarrayCity names as listed by GET /targeting/cities?geo=DE
devicearraydesktop, mobile, tablet
osarraywindows, macos, linux, android, ios, other
os_version_minstringMinimum major version, for example "13"
browserarraychrome, safari, firefox, edge, samsung, opera, other
connectionarraywifi, cellular
carrierarrayMobile carrier IDs from GET /targeting/carriers?geo=BR
languagearrayISO 639-1 browser language codes
zones, exclude_zonesarrayZone IDs to whitelist or blacklist. Zone-level performance is in statistics with group_by=zone.
publishers, exclude_publishersarrayPublisher IDs
frequency_capobject{ "impressions": n, "per_hours": h }. Default 3 per 24 hours. Pop and interstitial are additionally capped at 1 per session network-wide.
scheduleobjecttimezone (IANA name), hours (array of 0 to 23), days (array of mon to sun)
ip_ranges, exclude_ip_rangesarrayCIDR blocks, maximum 500 entries
adult_inventorybooleanWhether to serve on adult-flagged inventory. Forced true for adult campaigns and forced false for mainstream campaigns.

09 Zones

A zone is one ad placement on one publisher property. Zones are created under a verified property and are activated after compliance review and the 72-hour traffic audit. Scope: publisher.

GET/properties

List your verified properties (domains, apps, push lists) with verification status and vertical flags.

GET/zones

List zones. Filters: property_id, format, status (pending, audit, active, paused, rejected).

POST/zones
// request body
{
  "property_id": "prp_01J9X4HN2Q",
  "name": "Article sidebar 300x250",
  "format": "display",
  "size": "300x250",
  "pricing_preference": "auto",
  "accept_verticals": ["mainstream", "igaming", "crypto", "vpn"],
  "fallback_url": "https://yoursite.com/house-ad"
}
FieldTypeNotes
property_idstringRequired; must be verified
namestringRequired, for your reference
formatenumRequired. display, pop, push, native, interstitial, video, direct, smartlink
sizestringRequired for display
pricing_preferenceenumcpm, cpc, revshare, auto (default)
accept_verticalsarrayVerticals this zone will serve. adult can be included only on properties flagged adult by compliance.
fallback_urlstringOptional. Loaded when no ad fills, instead of a blank slot.
floor_cpmdecimal stringOptional minimum CPM. Setting a floor reduces fill.
GET/zones/{zone_id}/tag

Returns the ready-to-paste tag for the zone in html, plus the direct_url or smartlink_url for link formats.

PATCH/zones/{zone_id}

Update name, pricing preference, accepted verticals, fallback URL, or floor. Adding adult to accept_verticals triggers a property re-review.

POST/zones/{zone_id}/pause

Stop serving on the zone. Resume with /activate.

10 Statistics

Statistics are aggregated hourly and are final for a day at 04:00 UTC the following day, after invalid traffic review. Figures before that point are provisional and may decrease. Scope: any.

GET/stats
ParameterNotes
from, toRequired. Dates (YYYY-MM-DD) or ISO timestamps for hourly ranges. Maximum 31 days.
group_byComma-separated. date, hour, campaign, creative, zone, publisher, geo, region, device, os, browser, format, vertical, sub1 to sub5. Maximum 4 dimensions.
campaign_id, zone_id, geo, formatOptional filters, comma-separated
metricsOptional subset of: impressions, viewable_impressions, clicks, ctr, conversions, cr, spend, revenue, ecpm, ecpc, ecpa, ivt_filtered. Advertisers see spend; publishers see revenue.
formatResponse format: json (default) or csv
// example response (advertiser, group_by=date,geo)
{
  "data": [
    {
      "date": "2026-10-21", "geo": "DE",
      "impressions": 184203, "clicks": 4791, "ctr": 0.026,
      "conversions": 61, "cr": 0.0127,
      "spend": "407.24", "ecpa": "6.68",
      "ivt_filtered": 2117
    }
  ],
  "final": true
}

11 Balance and Payouts

GET/balance

Advertiser balance, pending deposits, today's spend, and the estimated hours of delivery remaining at the current spend rate. Scope: advertiser or read.

GET/transactions

Deposits, refunds, credits, and daily spend debits with timestamps and references. Supports from, to, and pagination.

GET/payouts

Publisher payout history: period, gross earnings, IVT deductions, net amount, method, destination (masked), status (scheduled, processing, sent, held), and transaction reference or on-chain hash once sent. Scope: publisher or read.

GET/payouts/upcoming

The current unpaid balance, the next scheduled payout date, and whether the minimum threshold has been reached.

12 S2S Postbacks

Server-to-server postbacks report conversions to D4RKW3B so that CPA campaigns are billed correctly, smartlink routing learns which offers convert, and conversion columns populate in statistics. The flow:

  1. Include {click_id} in your campaign's landing_url. D4RKW3B replaces it with a unique identifier on each click.
  2. Store the click identifier on your side (cookie, session, or your tracker's sub-ID field).
  3. When a conversion occurs, call the postback URL from your server with that identifier.
// postback url
https://pb.d4rkw3b.network/conv?click_id={click_id}&event={event}&payout={payout}&txid={transaction_id}
ParameterRequiredNotes
click_idYesThe value D4RKW3B inserted into your landing URL
eventNolead, registration, deposit, sale, install, subscribe, or a custom name up to 32 characters. Defaults to conversion.
payoutNoDecimal value of the conversion in USD, used for revenue reporting and smartlink optimisation
txidNoYour transaction identifier. Postbacks with a repeated click_id and txid are deduplicated.
statusNoapproved (default), pending, or rejected. Send a second postback to update a pending conversion.

The endpoint accepts GET and POST, responds with 200 OK and a body of {"status":"ok"}, and processes conversions within 60 seconds. Conversions are accepted up to 30 days after the click. Personal data in any parameter is stripped and logged as a policy warning on the account. Postbacks may optionally be signed by appending &sig= with an HMAC-SHA256 of the query string using your postback secret from Settings; signed postbacks are required for CPA campaigns above USD 5,000 per day.

12.1 Tracker presets

The dashboard provides one-click templates for Voluum, Bemob, RedTrack, Binom, Keitaro, and ClickFlare that populate both the landing URL macros and the tracker's postback URL. The equivalent manual configuration is a landing URL of the form https://your-tracker.com/path?d4_click={click_id}&zone={zone_id}&geo={geo} and a tracker postback URL of https://pb.d4rkw3b.network/conv?click_id={d4_click}&payout={payout}, substituting the tracker's own macro syntax for the right-hand side.

13 Tracking Macros

Macros can be placed in any campaign landing_url and are replaced at click time. Values are URL-encoded.

MacroValue
{click_id}Unique click identifier for postbacks
{campaign_id}Campaign ID
{creative_id}Creative ID
{zone_id}Publisher zone that served the ad. Use for zone-level optimisation and whitelists.
{publisher_id}Publisher ID
{geo}Country code
{region}Subdivision code
{city}City name
{device}desktop, mobile, or tablet
{os}Operating system
{os_version}Major OS version
{browser}Browser family
{language}Browser language
{carrier}Mobile carrier name, or empty on Wi-Fi
{connection}wifi or cellular
{format}Ad format
{bid}Winning bid for this impression or click, in USD
{timestamp}Unix timestamp of the click
{sub1} to {sub5}Publisher-supplied sub-IDs passed through from the tag or smartlink

14 Universal Tag

The universal tag loads once per page and renders every zone configured for the property. It is asynchronous, weighs under 12 KB compressed, and does not block page rendering.

// universal-tag.html
<!-- D4RKW3B universal tag: place once before </body> -->
<script async
  src="https://cdn.d4rkw3b.network/u.js"
  data-pub="PUB-7Q2K9M"
  data-zone="auto"
  data-sub1="homepage"></script>

<!-- Display placement: one per display zone -->
<ins class="d4-ad" data-zone="zn_01J9X5A8" style="display:inline-block;width:300px;height:250px"></ins>
AttributeNotes
data-pubRequired. Your publisher ID.
data-zoneauto renders every zone configured for the property. A specific zone ID restricts the tag to that zone.
data-formatsComma-separated list to enable only some formats on this page, for example display,native. Overrides property defaults.
data-pop-capPopunder frequency per user in hours. Default 24. Cannot be set below 12.
data-push-delaySeconds before the push subscription prompt may appear. Default 15. Cannot be set below 5. The prompt is shown once per 7 days per user.
data-sub1 to data-sub5Sub-IDs for your own reporting, available in statistics with group_by=sub1.
data-consenttcf (default: read IAB TCF signal if present), granted, or denied. Use granted or denied if you manage consent without a TCF-compatible CMP.
data-lazytrue defers display zones until they are within 200 px of the viewport. Improves viewability and page speed.

For display placements, add one <ins class="d4-ad"> element per zone where the ad should render. Pop, push, interstitial, and native widget zones need no placeholder. The tag sets only the identifiers listed in the Privacy Policy and honours Global Privacy Control.

A smartlink is a single URL that detects the visitor's geo, device, OS, browser, and language and routes to the best-paying eligible offer. Use it where you cannot place a tag: email, push lists, social bios, app traffic, or as a fallback.

// smartlink
https://link.d4rkw3b.network/PUB-7Q2K9M?zone=zn_01J9X5B2&sub1={your_subid}&vertical=igaming
ParameterNotes
zoneRequired. A zone of format smartlink or direct.
sub1 to sub5Optional sub-IDs for reporting and for passing your own click identifier
verticalOptional. Restrict routing to one vertical. Defaults to all verticals the zone accepts.
fallbackOptional URL-encoded URL to redirect to when no eligible offer exists for the visitor
geo, deviceOptional overrides when you already know the visitor's attributes (for example from an email list). Mismatches with detected values are logged and may be excluded.
ip, uaFor server-side redirects only: pass the end user's IP and user agent so routing and fraud scoring use the visitor's values rather than your server's. Requires the request to come from an IP registered in Settings.

Smartlinks pay on an RPM basis: revenue is attributed per click based on the conversions the routed offers generate, and shown in statistics with group_by=zone,sub1.

16 Webhooks

Register an HTTPS endpoint under Settings → Webhooks to receive events as they happen. Each delivery is a POST with a JSON body and is retried with exponential backoff for up to 24 hours until your endpoint returns a 2xx.

EventSent when
campaign.status_changedA campaign moves between draft, review, active, paused, rejected, or completed
creative.reviewedA creative is approved or rejected, with reviewer notes
campaign.budget_reachedDaily or total budget is exhausted
balance.lowAdvertiser balance falls below 24 hours of spend at the current rate
conversion.receivedA postback is accepted (optional; high volume)
zone.status_changedA zone moves between pending, audit, active, paused, or rejected
zone.quality_alertA zone's traffic quality score falls below threshold, with 48-hour remediation notice
payout.scheduledA payout is queued with its amount and date
payout.sentA payout is sent, with the reference or on-chain hash
compliance.actionAny enforcement action on the account, with reference number and appeal deadline
// webhook delivery
POST /your/endpoint
Content-Type: application/json
X-D4-Event: creative.reviewed
X-D4-Delivery: dlv_01J9X6C3R7
X-D4-Signature: sha256=4f1a0c7e9b2d8a6f3e5c1b9d7a2f4e6c8b0d2a4f6e8c0b2d4a6f8e0c2b4d6a8f

{
  "event": "creative.reviewed",
  "occurred_at": "2026-10-22T09:14:03Z",
  "data": {
    "creative_id": "crt_01J9X5D4",
    "campaign_id": "cmp_01J9X4M2",
    "status": "rejected",
    "reason": "Landing page bonus terms do not state wagering requirement (AUP 4.1)"
  }
}

Verify every delivery: compute HMAC-SHA256 of the raw request body using your webhook secret and compare it in constant time to the X-D4-Signature value. Reject deliveries whose occurred_at is more than 5 minutes old to prevent replay. The X-D4-Delivery ID is unique per attempt and can be used for idempotency.

17 OpenRTB Endpoint

Demand-side platforms and large advertisers can buy inventory programmatically over OpenRTB 2.6 at https://rtb.d4rkw3b.network/bid. Access is granted after an integration review; request it through your account manager or api@d4rkw3b.network.

18 Code Examples

Create and activate a campaign

// curl
curl -X POST https://api.d4rkw3b.network/v1/campaigns \
  -H "Authorization: Bearer $D4_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "VPN US desktop pop",
    "vertical": "vpn",
    "format": "pop",
    "pricing_model": "cpm",
    "bid": "1.40",
    "daily_budget": "200.00",
    "landing_url": "https://example-vpn.com/?cid={click_id}&z={zone_id}",
    "targeting": { "geo": ["US"], "device": ["desktop"] }
  }'

curl -X POST https://api.d4rkw3b.network/v1/campaigns/cmp_01J9X4M2/activate \
  -H "Authorization: Bearer $D4_API_KEY"

Pull yesterday's stats by zone

// python
import os, requests
from datetime import date, timedelta

yesterday = (date.today() - timedelta(days=1)).isoformat()
r = requests.get(
    "https://api.d4rkw3b.network/v1/stats",
    headers={"Authorization": f"Bearer {os.environ['D4_API_KEY']}"},
    params={"from": yesterday, "to": yesterday,
            "group_by": "zone", "metrics": "impressions,clicks,conversions,spend"},
    timeout=30,
)
r.raise_for_status()
for row in r.json()["data"]:
    print(row["zone"], row["clicks"], row["conversions"], row["spend"])

Verify a webhook signature

// node.js
const crypto = require('crypto');

function verify(rawBody, signatureHeader, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return expected.length === signatureHeader.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));
}

Send a conversion postback

// php
$params = http_build_query([
  'click_id' => $_SESSION['d4_click_id'],
  'event'    => 'deposit',
  'payout'   => '45.00',
  'txid'     => $depositId,
]);
$sig = hash_hmac('sha256', $params, $postbackSecret);
file_get_contents("https://pb.d4rkw3b.network/conv?{$params}&sig={$sig}");

19 Support

Integration questions: api@d4rkw3b.network. Include your account ID, the endpoint, the request_id from any error, and timestamps in UTC. Responses within one business day; managed-service accounts can reach their account manager on Telegram for same-hour help. Service health is published on the status page, and the unauthenticated endpoint GET /v1/status returns the same data as JSON for monitoring.