Browse the help center

Linking, status, tracking codes and ad tags via API

API reference for linking banners to placements, serving checks, activation and bulk on/off, list filters, bulk labels, banner approval, third-party tracking codes and retrieving ad tags.

Reference network manager admin

Once the advertisers and campaigns, banners and sites, zones and placements exist, these calls tie them together and put them live: linking banners to placements, switching entities on and off, which fields need a permission, approval, list filters and labels, third-party tracking codes and the ad tag. Examples append $AUTH, the hash-authentication parameters (an X-Api-Key header works the same), and send parameters form-encoded unless noted — see the API overview for authentication and Entities via API for the corner cases every entity shares.

Who this is for

Network managers, publishers and advertisers who link, activate and tag entities from a script, and admins. Linking, activation, approval, labels and each ad-tag type are gated by their own role permissions, named in each section.

Linking banners and placements

Links can be managed from either side:

From the banner side:

MethodPathPurpose
GET/rest-api/banner/{bannerId}/placements.doPlacements linked to a banner
GET/rest-api/banners/{bannerId}/placements.doThe banner’s linked site placements as id / name (view access to the advertiser needed)
GET/rest-api/banner/{bannerId}/matchplacements.doCompatible placements not yet linked (filters: publisherCategories, labels), each with type, zoneId, siteId and, when it has a size, width / height
GET/rest-api/banner/{bannerId}/mismatched-placements.doPlacements of exactly the banner’s size, on sites you may link to, that it cannot be linked to because their kind differs (a mobile placement for a desktop banner) — the ones a “link it to every 300x250” request would otherwise skip silently. Same row shape as matchplacements; 404 for a missing or deleted banner, 403 without view access to its advertiser
PUT/rest-api/banners/{bannerId}/placements.doSet/add links from the banner side (ids array, append flag)
DELETE/rest-api/banners/{bannerId}/placements.doRemove links listed in removeIds

From the placement side:

MethodPathPurpose
GET/rest-api/placements/{placementId}/banners.doBanners linked to a placement (needs view access to its site; banners of a private advertiser you have no share on are left out)
PUT/rest-api/placements/{placementId}/banners.doSet/add links from the placement side (ids, append)
DELETE/rest-api/placements/{placementId}/banners.doRemove links listed in removeIds

And the question both sides end up asking — why a banner is not serving on a placement:

MethodPathPurpose
GET/rest-api/serving-check.doWhy a banner does not serve on a placement: bannerId, placementId, optional country (two letters). Answers blockers — any of the six levels deleted or switched off (and, when the ad server switched it off itself because a total impressions, clicks or conversions limit was reached or the end date passed, which one: raising the limit or moving the date does not switch it back on), a delivery limit that is full on any level but the zone, moderation that switched the banner off, a missing link or links switched off on either side, a kind or size mismatch, a video file off the site’s requirements, the banner’s or campaign’s run dates, a location rule naming a place the geo database no longer knows that keeps every visitor out (an exclude, or includes that are all such places) and, with country, a country rule that keeps that visitor out — warnings — what does not stop serving: an approval pending on a banner that is on, a site the network has not approved, stale location includes next to ones that still exist — and targeting, each level’s rules as text — the site, zone and placement rules only with the Manage Supply Pre-targeting permission and the advertiser, campaign and banner rules only with Manage Demand Targeting (either one enabled or read-only), as the console shows them; a hidden level whose country rule keeps the visitor out is still named as a blocker, without its rules. 404 for a missing banner or placement (a deleted one is answered as a blocker), 403 without view access to either side
curl -X PUT "https://<your-network-domain>/rest-api/banners/5001/placements.do?$AUTH" \
  -d "ids=4001" -d "ids=4002" \
  -d "append=true"

Warning: with append=false (the default), the ids you send replace the banner’s entire link set — any placement not listed is unlinked. Pass append=true to add links without touching existing ones. Unlinking needs the same reach as the DELETE call: if a link you would drop sits on a site your grant cannot manage links on, the call fails with placements_cannot_be_linked listing it and nothing changes.

Corner case: the two DELETE verbs take removeIds, not ids. Reusing the PUT parameter name is a 400 (Parameter missing: removeIds) on both sides, and nothing is unlinked.

An id of no placement, or of a deleted one, is skipped: the rest are linked and the answer lists the skipped ones in skipped as {id, reason} — no entity with this id or it is deleted. Every placement that is linked must be type-compatible with the banner, or the call fails validation; when no id is left to link, the call fails too. The placement-side call skips unknown and deleted banner ids the same way, in the same skipped list that already names the banners that do not fit the placement.

Ids your Link Placements to Banners grant does not reach are rejected rather than skipped: the call fails with 403 and {"success": false, "placements_cannot_be_linked": [4002]} and nothing is written. With the grant at Shared every id must sit on inventory shared with you; at All any placement in the network is accepted; at Linked / Shared linked only ids already linked to the banner are accepted, since those grants never create a link. The placement-side PUT /rest-api/placements/{placementId}/banners.do answers the same way with banners_cannot_be_linked, and additionally needs the right to update the placement’s site: without it the call is a 403 and nothing is written, whatever the link grant.

Activation, approval, status

  • Activation is the active boolean on each entity’s create/update endpoint — there is no separate activate endpoint. Deactivating an advertiser stops everything beneath it. active, the feature switches and several other fields take effect only with the permission the console asks for before it changes them. Without it the rest of the create or update is applied, the field is left as stored (on create: at its default), and it is listed in ignoredFields as not permitted (see Parameters that were not applied):
EntityFieldPermission it needs
Advertiser, campaign, banner, site, zone, placementactiveManage Advertisers’ Active Status, Manage Campaigns’ Active Status, Manage Banners’ Active Status, Manage Sites’ Active Status, Manage Zone’s Active Status, Manage Placement’s Active Status — one per entity type
AdvertiserenableTargetingManage Demand Targeting
Site, zone, placementenableTargetingManage Supply Pre-targeting
AnyoperationBetweenRuleTypesThe side’s targeting permission plus Manage Operation Between TargetingRule Types
AnyenablePriceAdjustingManage Price Adjusting
AnyactionLimitsEnabledManage Capping & Limitations plus the campaign or inventory per-action limit permission
AnyenableRulesManage Rules
AdvertiseradomainSet Advertiser Domain (OpenRTB adomain)
AdvertiserprivateFieldSet Private
AdvertiserconfirmationDelay, preliminaryConfirmationDays, lastConfirmedDateManage Completeness Delay for Advertisers. The date is yyyy-MM-dd and an empty value clears it; GET /rest-api/advertisers/{id}.do returns the three under the same permission
AdvertiseradsHostSet Ad Serving Domain (Campaigns)
AdvertiserselfServeCpmFloorAdjustmentSelf-serve CPM Floor Adjustment (0–10000, where 100 means no adjustment)
CampaignSee Campaign settings that need a permission
SiteSee the corner cases under Sites
PlacementcustomOpenRtbTagIdOpen RTB
PlacementvideoAdMinDuration, videoAdMaxDuration, videoAdSkipMin, videoPlaybackMethod, videoApiFrameworkVideo RTB Configuration
PlacementserverSideTrackersEnabledPlacement Server-Side Trackers
PlacementcontentReplacementEnabledPlacement Content Replacement
PlacementpiggybackStatusPiggyback Pixel Tracking
PlacementalwaysRedirectAlways Redirect
PlacementrotateIntervalAuto Refresh
PlacementallowVariableBannerSizesFlexible Placement Size
PlacementdisableAutoLinkingAuto-linking settings
PlacementenablePricingOverrideManage Pricing
PlacementservingDomainSet Ad-Serving Domain (Placement)
PlacementdefaultCodePlacement Default Code
Placementlabels, labelUpdateTypePlacement Labels
PlacementnativePreferences.*Size.*Native Placement Sizes
PlacementnativePreferences.requiredFieldsNative Placement Required Fields
PlacementnativePreferences.contextTypeNative Placement OpenRTB Context Type
PlacementnativePreferences.contextSubTypeNative Placement OpenRTB Context Sub Type
PlacementnativePreferences.placementTypeNative Placement OpenRTB Placement Type
PlacementenableLinkingAny Link Placements to Banners scope but none
BannerweightManage Banner Weight
Bannerlabels, labelUpdateTypeBanner Labels
BannerallowUseForTemplate, targetTemplateNameTemplates
BannerdspPartnerId, usePlacementSize, always2ndPrice, advertisingNetworkParameters[…], mimeTypesOpen RTB
BannerskipButtonShowAfterSecondsBanner Video Skip Button
BannerapplicationPreCheckPackagesApplication pre-check
BannerhardLinkageLink Placements to Banners
BannerthirdTrackingCode[…]Banner Third-Party Tracking Code
BanneruniversalAdIdValue, universalAdIdRegistry (a video creative’s VAST UniversalAdId)Banner ISCI / Ad-ID Code
BannerenableViewTrackingBanner View Tracking
BannerallowNewPlacementsAutoLinking, autolinkCategoriesAuto-linking settings (autoLinkLabels also needs Placement Labels)
BannerstatusBanners Approval — see Banner approval below

A read-only grant does not count: it shows the control in the console but does not let it be saved. This applies whether you authenticate with hash parameters or call from a logged-in session; a username sent without hash and timestamp authenticates nothing and lends the call none of that user’s permissions.

  • Bulk on/off switches up to 500 advertisers, campaigns or banners in one call, with the same rules as the console grids’ on/off toggle:
MethodPathPurpose
POST/rest-api/advertisers/status.doids (repeat the parameter) and active = true/false
POST/rest-api/campaigns/status.doSame for campaigns
POST/rest-api/banners/status.doSame for banners
curl -X POST "https://<your-network-domain>/rest-api/banners/status.do?$AUTH" \
  -d "ids=3001" -d "ids=3002" -d "ids=3999" -d "active=false"
# → {"success":true,"changed":[3001],"skipped":[{"id":3002,"reason":"unchanged"},{"id":3999,"reason":"not-found"}]}

Unlike the single update, a missing grant is not silent here: without Manage Advertisers’ / Campaigns’ / Banners’ Active Status, or when any id belongs to an advertiser outside your update share, the call returns 403 and changes nothing. Ids already in the requested state are skipped as unchanged, deleted or unknown ids as deleted / not-found, and a template creative whose template is inactive is skipped as inactive-template when switched on without Update properties and status, based on inactive template. A call where none of the ids exists returns 404; no ids or more than 500 return 400. Each switched entity raises the same activated / deactivated notification as a single update.

  • List filters narrow, and a list filter matches any of its values. placementTypes=VIDEO_PLACEMENT on banners.do returns the creatives built for video placements; types=VIDEO_PLACEMENT&active=true on placements/summary.do returns the switched-on video placements. A labels filter naming no label that exists returns an empty list rather than every entity, so a typo in a label name never looks like “everything carries it”.
  • filter[…] narrows the advertiser, campaign, banner, site, zone and placement lists by any on/off setting of the entity — filter[cpaOptimization]=true, filter[enableTargeting]=true, filter[alwaysRedirect]=false — and by a has<Relation> flag for every setting the entity keeps in rows of its own: hasLimit, hasPricing, hasFrequencyCapping, hasTrackingCode, hasPriceAdjustmentRules, hasLabels, hasBanners, hasZones and so on. A flag is true when the relation holds at least one row — a limit or pricing row exists only once it is switched on in the console. hasCapping, hasLimits and hasTargetingRules group the relations of their kind; note that hasTargetingRules (rules exist) and enableTargeting (rules are switched on) are different questions. Every key must match. The keys come from each entity’s data model, so the list differs per entity and grows with it: a key the list does not know is a 400 whose message lists every valid key for that list. On banners and placements the filter runs in the database, so offset / limit page the filtered result.
  • fields trims each entity to the named fields (id is always kept) — fields=id,name,active turns a 1,000-campaign list from megabytes into a few dozen kilobytes. A requested field that no returned row carries is named in the X-Ignored-Fields response header rather than failing the call.
# Campaigns with CPA optimisation on that also carry a frequency or click cap, 100 at a time
curl "https://<your-network-domain>/rest-api/campaigns.do?$AUTH&filter%5BcpaOptimization%5D=true&filter%5BhasCapping%5D=true&fields=id,name&offset=0&limit=100"
  • Only the documented fields are applied. Each create/update endpoint binds the parameters listed for it and ignores every other one — naming it in ignoredFields — so a nested path such as zone.name, size.adUnit.width, categories[0].name or limit.totalImpressionsLimit changes nothing. Related entities are named by id only — siteId, zoneId, advertiserId, categoryId, adUnitId, autolinkCategories — and are linked, never edited. Limits have their own endpoints (see Targeting, capping and limits).
  • Site approval is never taken from the request. A site created by a caller whose role holds the site-approval permission is approved as part of that call; everyone else’s new sites start at the network’s default status. An update never changes the approval status, so renaming a site a moderator rejected leaves it rejected.
  • Parents. A zone’s site comes from siteId, a new placement’s zone from zoneId. Sending an existing zone’s id with a different siteId moves the zone, which needs update rights on both the site it leaves and the site it joins; otherwise the call returns permission_denied and nothing changes. Sending an existing placement’s id with a different zoneId moves the placement to that zone the same way, on the same or another site; its banner links stay.
  • Banner approval (when your network moderates creatives):
MethodPathPurpose
POST/rest-api/banner/{bannerId}/approvalstatus.doSet status = NEW, PENDING, APPROVED, REJECTED
POST/rest-api/banners/sendToApprove.doSubmit banners for approval
POST/rest-api/banners/reaprove.doRe-approve banners (note the spelling — one p)

Those four are the whole status enum. Setting a status the banner already has is a no-op that returns a message. Moving to APPROVED or REJECTED notifies every user who has a share on the banner’s advertiser.

The call needs the Banners Approval permission (BANNERS_APPROVAL); without it the answer is a 403 naming that permission, whatever the banner and its current status.

The banner create and update calls also take a status, under the same rule as approvalstatus.do: changing it needs the Banners Approval permission. Without it the status is not changed and status is listed in ignoredFields, with ignoredFieldReasons naming the permission, while the rest of the create or update is saved — a new banner gets the status the network’s moderation gives it (NEW when your role’s creatives need approval, APPROVED otherwise), and an edited one keeps the status moderation leaves it. Sending the status the banner already has changes nothing and is not reported. approvalstatus.do itself still answers 403 without the permission.

  • Removing a banner’s media. DELETE /rest-api/banner/{bannerId}/video.do removes the uploaded video file (400 when the banner has none). The image is removed through the update instead: send deleteImage=true to /rest-api/banner/{bannerId}/update.do. A Local File banner cannot be left without an image, so it must upload the replacement in imageFile in the same call (400 otherwise); the old file is then deleted from storage. Naming the replacement in imageFileUrl does both in one step, without deleteImage. Both need update access to the banner’s advertiser.

Bulk labels

POST /rest-api/banners/labels.do, /rest-api/placements/labels.do and /rest-api/campaigns/labels.do apply one label change to up to 500 entities, the same action as the console grids’ Labels button. labelUpdateType picks the change: ADD (default) appends, OVERWRITE replaces the entity’s labels, REMOVE takes the named labels off, CLEAR removes every label and ignores labels.

# Every switched-on video placement of site 1001 gets the label "video-q4"
curl "https://<your-network-domain>/rest-api/placements/summary.do?$AUTH&siteId=1001&types=VIDEO_PLACEMENT&active=true"
curl -X POST "https://<your-network-domain>/rest-api/placements/labels.do?$AUTH" \
  -d "ids=4001" -d "ids=4002" -d "ids=4999" -d "labels=video-q4"
# → {"success":true,"changed":[4001],"skipped":[{"id":4002,"reason":"unchanged"},{"id":4999,"reason":"not-found"}]}

The rules follow bulk on/off: without the entity’s labels permission (Banner Labels, Placement Labels, Campaign Labels), or when any id is outside your update share, the call returns 403 and changes nothing. A label name that does not exist yet is created when you hold Create Labels; otherwise the call returns 400 naming it. Entities whose labels would not change are skipped as unchanged, deleted or unknown ids as deleted / not-found; a call where none of the ids exists returns 404, and no ids, more than 500, or no labels for ADD / OVERWRITE / REMOVE return 400.

Third-party tracking codes

A banner or a placement can carry HTML tracking code that fires when it serves, for every country (country=*) or for one. The two families have the same eight operations — under /rest-api/tracking-code/banner/ and /rest-api/tracking-code/placement/ — and take domainId, the banner or placement id, as server-side trackers do:

MethodPath (after /rest-api/tracking-code/banner/ or …/placement/)Purpose
GETlist.doThe entity’s codes: id, code, country (* is global) and countryStr (domainId)
POSTadd.doAdd or replace the code for that entity and country (domainId, country, code)
POSTadd/batch.doThe same code on many entities (domainIds, country, code); answers a map keyed by id, each {success}
POSTedit.doChange one code by id, moving it to another country if that differs; the global code is edited with country=* and id=0
POSTdelete.doRemove codes: countryTrackingCodeIds, and/or clearGlobalTrackingCode=true
POSTglobal-clear/batch.doClear the global code on many entities (domainIds); country codes stay
POSTenable-tracking-code.doSwitch the feature on with an empty set (id); on already, nothing changes and the codes are kept
POSTdisable-tracking-code.doSwitch it off (id). This deletes every code of the entity — there is no dormant state

An unknown country on add.do or edit.do is a 400 under errors.country. Switching the feature on or off needs Banner Third-Party Tracking Code or Placement Third-Party Tracking Code and update rights on the entity, otherwise a 403 naming the permission; an entity or code that does not exist is a 404. A banner’s thirdTrackingCode[…] on banner/create.do / update.do is the same setting from the other side.

Getting the ad tag

Once a placement exists, retrieve its serving tag by placement key, not by its numeric ID. The key is 32 lowercase hex characters, generated by the server when the placement is created, shown on the placement, and never rewritten. Moving the placement or its zone keeps it, so a published tag keeps working; do not try to derive it from the ids. GET /rest-api/placements/summary.do and the single read GET /rest-api/placements/{placementId}.do return it, as the field key; placements/all.do, the site tree and the zone placement lists do not carry it.

MethodPathPurpose
GET/rest-api/placement/{key}/code.do?t=AJAXInvocation code; t is required — AJAX, JS_MOUNT, IFRAME_SIMPLE, DIRECT_URL, API, EMAIL, VIDEO_PLAYER. tpId is an internal test-page id — leave it out
GET/rest-api/placement/{key}/vast-tag.do?v=3.0VAST tag URL for video placements (v = 2.0, 3.0, 4.0; default 3.0)
GET/rest-api/placement/{key}/vmap-tag.doVMAP tag
GET/rest-api/placements/{placementId}/invocation-code-types.doThe tag types your role may generate for this placement (placementType, types) — the values invocation-code.do takes; types is empty when the role holds none of the invocation-code permissions for that placement type
GET/rest-api/placements/{placementId}/invocation-code.do?type=AJAXThe tag by placement id, checking your view access to its site and the per-type permission
GET/rest-api/placements/{placementId}/invocation-code/export.do?type=AJAXThe same tag as a text-file attachment, as the console’s download button hands it out
GET/rest-api/placements/{placementId}/preview-link.doA shareable preview link (url, path) that renders the placement as a visitor sees it, needs no login and works for 30 days; optional codeType (default AJAX when your role may generate it). Your role needs the invocation-code permission of the tag it renders, as for the ad-tag card — 403 otherwise, or when it may generate no tag for the placement at all. servesOnlyWhileActive is false when the placement, its zone or its site is switched off — the preview then shows no ad

t is bound to an enum, so a value outside that list is a 400, not an empty code, and omitting it is 400 {"success":false,"message":"Parameter missing: t"}. Those seven are the whole list: IFRAME_SYNC, IFRAME_ASYNC, JS_SYNC, JS_ASYNC, JSP, PHP, API_JS_SYNC_CODE and LITE were removed, and a caller still sending one now fails outright — see Retired code types for what to migrate each to.

A key that names no placement (or one that is not active) is a 404 on code.do, vast-tag.do and vmap-tag.do — and on the deprecated placement-code/{key}.do — with success: false and the key in the message.

Note: the four key-based reads (code.do, vast-tag.do, vmap-tag.do and the deprecated placement-code/{key}.do) run no REST authentication and no role check — the key in the path is the only thing they look at, so treat it as a secret. placements/{placementId}/invocation-code.do is the variant that checks your access to the site and the permission for the tag type.

The names differ from the tab labels in the control panel: AJAX is Universal JS, JS_MOUNT is Mount JS, EMAIL is Mail.

JS_MOUNT is the one most integrations miss. It returns a bare anonymous function — (function(container, opts) { … })(container, opts) — with no surrounding <script> tags, for you to inline into your own script context.

Both container and opts are resolved from your scope at the call, so both must be declared there. container is the element the ad mounts into; declare it and leave it unassigned and the snippet falls back to the running script’s next sibling element. If neither resolves, it returns silently and nothing renders.

var container = document.getElementById('ad-slot-leaderboard');
var opts = { channel: 'homepage' };
// paste the JS_MOUNT snippet here

Warning: leaving container undeclared rather than unassigned throws a ReferenceError before the snippet body ever runs — the fallback never gets a chance.

opts overrides the placement’s baked-in defaults per call, for exactly five keys: channel, click, customParams, bundle and ifa. customParams merges key by key rather than replacing, so a parameter baked into the tag survives unless you override that key by name. It shares the Universal JS loader rather than running a parallel one, so mounting several placements on a page is safe. Use it for single-page apps and late injection — anywhere the ad slot is created by your own code rather than sitting in the HTML where a pasted AJAX tag would go.

There is also a deprecated GET /rest-api/placement-code/{key}.do, which returns only the Simple Iframe and Direct URL forms. Use placement/{key}/code.do instead.

See Invocation codes for what each format does.

Related pages

Please disable Adblock
Are you using adblock? Disable it and reload the page to proceed to the destination page.

A registration has already been submitted from this page. Please try again in 10 minutes.