Browse the help center

REST API overview

Base URL, the three authentication methods with a worked hash example, where your API key lives, what happens after repeated failed credentials, response shapes, pagination, URL conventions, error codes and where to find the interactive API docs.

Reference network manager admin

Nearly everything you can do in the control panel — managing advertisers, campaigns, creatives, sites, placements, targeting, capping and reporting — is also available over a REST API. This page covers the conventions shared by all endpoints. The other pages in this section walk through each functional area with curl examples and link every call to its full entry in the generated reference.

Base URL

The API is served from the same domain as your control panel:

https://<your-network-domain>/rest-api/...

Every endpoint path starts with /rest-api/ and ends in .do, with no exceptions. Some paths answer more than one HTTP method; the per-tag reference lists every path and method and gives the current totals. If your network runs under a white-label domain, use that domain; API access, permissions and data scope are identical.

Authentication

Three methods are supported. Pick one per request; you don’t combine them.

MethodBest forHow it works
Hash (username + timestamp + hash)Server-to-server integrationsSigned request: an MD5 signature built from your password and a timestamp
API key (X-Api-Key header)Scripts and integrationsOne header on any REST call that needs a signed-in user
Session cookieBrowser-based tools, quick testsLog in to the control panel, reuse the session cookie

Add three query parameters to any request:

ParameterValue
usernameYour control-panel login
timestampCurrent Unix time in milliseconds
hashMD5( MD5(password) + timestamp ) — hex digest, either letter case

Worked example with password MySecret42 and timestamp 1751712000000:

  1. MD5("MySecret42") → 307ec992a5c1e4622ae2f7c909a0992f
  2. Concatenate with the timestamp → 307ec992a5c1e4622ae2f7c909a0992f1751712000000
  3. MD5 of that string → 9ece291919268a203f248e81a969253f — this is your hash
TS=$(($(date +%s) * 1000))                                    # milliseconds!
PWD_MD5=$(printf '%s' 'MySecret42' | md5 -q)                  # Linux: md5sum | cut -d' ' -f1
HASH=$(printf '%s%s' "$PWD_MD5" "$TS" | md5 -q)               # Linux: md5sum | cut -d' ' -f1

curl "https://<your-network-domain>/rest-api/advertisers.do?username=john.doe&timestamp=$TS&hash=$HASH"

Warning: the timestamp must be in milliseconds, and the server accepts it only within ±5 minutes of its own clock. A timestamp in seconds, or a machine with a skewed clock, produces Request is obsolete. A wrong password or a wrong concatenation order produces Data fingerprint mismatch., and an unknown username produces No matching credentials found. — all three arrive as HTTP 401.

Corner case: the signature is checked before the clock. A request whose hash is wrong reports the fingerprint mismatch even if the timestamp is also stale, so fix the hash first and re-test before blaming clock drift.

Because the timestamp is part of the signature, a long-running script must recompute timestamp and hash per request, not once at start-up.

Three endpoint families take the same three values as path segments rather than query parameters — the formula is identical:

/rest-api/analytics/{format}/{login}/{hash}/{timestamp}.do
/rest-api/analytics/reports-layout-settings/{login}/{hash}/{timestamp}.do
/rest-api/self-serv/dashboard/{login}/{hash}/{timestamp}.do

See Analytics reports via API.

Note: because hash and timestamp are signature values rather than business parameters, the generated reference and Swagger UI omit them from query-parameter lists. They still have to be sent. They are listed where they are path segments, as above. username and apiKey are ordinary parameters and are shown normally.

The $AUTH shorthand

The curl examples on the other API pages abbreviate the three signature parameters as $AUTH and append it to the URL. Build it from the TS and HASH above, fresh for each request:

AUTH="username=john.doe&timestamp=$TS&hash=$HASH"

curl "https://<your-network-domain>/rest-api/sites.do?$AUTH"

To authenticate with an API key instead, set the key once and send it as a header in place of $AUTH — every example works the same either way:

APIKEY="<your API key>"

curl -H "X-Api-Key: $APIKEY" "https://<your-network-domain>/rest-api/sites.do"

API key

Send your key in the X-Api-Key header (or as Authorization: Bearer <key>) on any REST call that needs a signed-in user. The key is a 32-character value tied to your user account, generated on your Preferences page; the call runs with exactly your permissions. Your role needs the API Key Access permission, and no stock role has it — on a new network your network administrator switches it on for the roles that should use the API. Without it the key is refused with 401 and API key access is not enabled for this account; the key of a deactivated account is refused with Account is not active. The analytics report (/rest-api/analytics/{format}) and the MCP endpoint (/mcp) refuse it with 403 instead.

curl -H "X-Api-Key: $APIKEY" "https://<your-network-domain>/rest-api/sites.do"

A request that carries more than one key has them tried in order — X-Api-Key, then Authorization: Bearer — and the first that belongs to an account allowed to use API keys wins, so a proxy that adds its own Bearer header does not hide your X-Api-Key.

On general REST calls the key works only in a header: in the query string it would end up in proxy logs and browser history, so a query-string apiKey is not read there — the call is authenticated by hash or session, or answers 401. Send the key as X-Api-Key on the analytics report too:

curl -H "X-Api-Key: $APIKEY" "https://<your-network-domain>/rest-api/analytics/JSON.do?range=YESTERDAY"

As a fallback for a client that cannot set a header, that one endpoint (/rest-api/analytics/{format}.do, GET and POST) also accepts the key as an apiKey query parameter; a header wins when both are sent.

Unlike a signed hash, which expires after five minutes, a key is valid until you generate a new one — treat it like a password and rotate it if it leaks.

Where your key lives. It is your own, not the network’s, and you mint it yourself: Account → Preferences → Change personal information → API key. Click Generate next to the field: the server mints a fresh 32-character hex value, saves it at once and shows it in the field — there is nothing to submit afterwards. The AI assistant (MCP) card on the same page shows the same key and has its own Generate API key button while you have none; see Connect an AI assistant (MCP).

What you see on the Change personal information cardWhy
The API key field with a Generate buttonAPI Key Access is enabled and Manage Preferences is enabled
The field, read-only, with no buttonAPI Key Access is read-only; or Manage Preferences is read-only, and then the card is titled Personal information
No API key field at allYour role has no API Key Access, or Manage Preferences is off and the whole card is hidden — ask your network administrator

Warning: Generate replaces the key permanently the moment you click it — there is no confirmation, no grace period and no second key slot. Every integration using the old key stops authenticating at that moment. Roll it only when you are ready to update the callers.

Corner case: a wrong, revoked or unknown API key is refused with 401 on both doors, but the body differs. On a general REST call it is {"success": false, "errors": {"error": "Not logged in"}}. On the analytics endpoint it carries rest_error (No matching credentials found.) next to errors.user (invalid user) — the analytics endpoints use their own body shape for authentication failures, not errors.error.

Failed credentials and the lockout

Repeated refused credentials — a wrong hash, an unknown login, a wrong API key — temporarily block further attempts from the caller’s address. While it is blocked, every request that presents a credential is refused with 401 and Too many failed attempts, even one with a valid key or hash. Wait a few minutes and try again; if it persists, ask your network manager. A console session that is already signed in keeps working.

For browser-based access, log in to the control panel and the session cookie (APPSESSIONID) authenticates subsequent API calls from the same browser.

For programmatic session creation there is a two-step token flow:

  1. POST /rest-api/auth/token.do with username and password. Returns {"success": true, "authToken": "...", "role": "..."}.
  2. GET /rest-api/auth/{authToken}/login.do — establishes the session.

Corner case: step 2 redirects to /index.do by default, even on failure. Add json=true to get {"success": …, "redirectUrl": …} back instead, or a callback parameter for JSONP. Without one of those, a script that follows redirects cannot tell a good token from a bad one.

There is also POST /rest-api/auth/forgot.do to trigger a password-reset email. It succeeds silently for an address that has no account, on purpose — that response tells you nothing about whether the address exists.

Signing a user in from another website: navigate, do not fetch. Step 2 has three answer modes. The default answers with a redirect to the control panel; json=true answers JSON and callback=<fn> answers JSONP. Only the default mode works when the call comes from a page on another site: open the URL as a top-level navigation (window.location, a link, or a form target="_top"), and the session cookie is set while the browser loads it. Called from another site through <script>, fetch or XHR — which is what the JSONP and json=true modes are for — the response still reports success: true, but the browser discards the session cookie (SameSite=Lax), so following redirectUrl lands on the login page and the token is already spent. Use those two modes only from pages served by the control panel’s own domain.

Corner case: the token is valid for one minute and is invalidated after a single use — the server evicts it from the cache as it reads it. The token endpoint requires HTTPS unless the server was explicitly configured to allow HTTP; over plain HTTP it answers 403 with {"success": false, "error": "Secure channel required"}. Every refusal — unknown username, wrong password, deactivated account, an address outside the user’s IP whitelist — answers 401 with the same Username or password is incorrect, so check each of those when a known-good password is refused. After repeated failures the answer is the lockout message instead (also 401), whatever the password; wait a few minutes.

Writes over a session need the CSRF token. A POST, PUT or DELETE authenticated only by the session cookie must also send the session’s CSRF token in the X-CSRF-TOKEN header (or a _csrf parameter); without it the call is refused with 403 and nothing is changed. The control panel and Swagger UI add the token for you. A script that logs in through the token flow and then writes with a cookie jar should switch to hash or API-key authentication, which need no token. Reads (GET) are unaffected.

Note: cross-origin calls get no access to the session cookie: browser code on another site can call the API, but only with hash or API-key authentication. The session cookie is sent as SameSite=Lax, and the session id changes at login.

Your first call

A good first call lists the sites your account can see: GET /rest-api/sites.do (an advertiser account starts with advertisers.do, which answers in the same bare-array form). Every role can sign a request with hash authentication; no permission is needed for it. The API key route needs API Key Access on your role, which no stock role holds — on a publisher or advertiser account, ask your network administrator to switch it on for your role before you look for a key (see API key).

curl -H "X-Api-Key: $APIKEY" "https://<your-network-domain>/rest-api/sites.do"

The answer is a bare array — there is no success key — with one object per site you can view, ordered by id. Deleted sites are left out, and an account that may view no inventory gets 403:

[
  {"id": 5001, "name": "Sports Daily", "enableTargeting": false},
  {"id": 5002, "name": "Northwind Recipes", "enableTargeting": true}
]

enableTargeting is the site’s pre-targeting switch. Add basicInfo=true to get a basicInfo object on every row (or basicInfoIds=5001,5002 for only those sites):

[
  {
    "id": 5001,
    "name": "Sports Daily",
    "enableTargeting": false,
    "basicInfo": {
      "isActive": true,
      "hasTraffic": true,
      "created": {"timestamp": 1751712000000, "formatted": "05/07/2025"},
      "url": "https://sportsdaily.example",
      "email": "ads@sportsdaily.example",
      "monthlyVisitors": "-",
      "monthlyImpressions": "-"
    }
  }
]

hasTraffic says whether the site has served recently. created, url, email and description appear only when the site has a value; monthlyVisitors and monthlyImpressions are the ranges picked on the site, or -. isPrivate and categoryIds (comma-separated) appear only for a role that may see the Private flag and inventory categories. To trim rows, pass fields=name (the id is always kept), and page with offset and limit — see Pagination and list conventions.

Response format

There is no single envelope. Which shape you get depends on the endpoint family, so read the shape before you write the client.

ShapeLooks likeWho returns it
Bare array[{…}, {…}]Most entity list and tree endpoints — advertisers.do, campaigns.do, sites.do, banners.do, placements/all.do, advertisers-tree.do, sites-tree.do
Bare object{"name": "…", "id": 4, …}Most single-entity reads — advertisers/{id}.do, zones/{id}.do
Grid page{"data": […], "total": 12, "overflowed": false}Grid-backed lists, e.g. template/list.do
Status envelope{"success": true, "id": 1001}Create, update, delete and action endpoints
Error envelope{"success": false, …}Every failure — see Error codes

Warning: success exists only on the last two shapes. A client that does if (!response.success) fail() treats every successful GET /rest-api/advertisers.do as a failure, because a bare array has no success key. Branch on the HTTP status first, then on success where the body is an object that has one.

On the status envelope:

  • success — false on every failure. A failure is also answered with the 4xx status that describes it (see Error codes), so you can rely on either the status or the flag; the body keeps the same keys it always had.
  • msg — human-readable message, usually only on errors.
  • errors — map of field name → validation message on validation failures. A failure whose reason is only in msg (or in an error code) repeats it as errors.error, so one reader handles every refusal.
  • Create endpoints typically add an id field with the new entity’s ID.
  • Empty collections are serialized, not dropped: an empty grid page is {"data": [], "total": 0, "overflowed": false} and an empty list endpoint is [].
  • overflowed on a grid page means the result was truncated by a server-side ceiling rather than by your limit.

Parameters that were not applied

The create and update calls — advertisers, campaigns, banners, sites, zones and placements, limits and pricing writes, saved reports, templates, and the site/placement piggyback and own-profile updates — set only the fields they are made for and that your role may change. A parameter outside that set does not fail the call — the rest of the update is still applied — but it is named back so a success is never mistaken for “everything I sent was saved”:

{
  "success": true,
  "ignoredFields": ["active", "contactNmae"],
  "ignoredFieldReasons": {
    "active": "not permitted",
    "contactNmae": "not a field of this operation"
  }
}
  • not permitted — a real field of the call that needs a permission your role lacks (the stored value is kept);
  • not a field of this operation — a misspelt name, a field managed by another endpoint, or one the call never changes;
  • a sentence naming the cause, where the call itself could not apply the value and says why — the permission a changed limit cap or a banner status needs (Your role lacks the TOTAL_CLICKS_LIMIT permission.), a thirdTrackingCode[…] key that is no country, a browserVersion the browser cannot be targeted by, a linkToPlacements with no auto-linking rules or no linking permission. The field is not applied and the rest of the call is saved.

Both keys are absent when everything was applied. Authentication parameters and parameters the call reads itself (ids, categoryId, labels, …) are never listed.

Pagination and list conventions

Three parameter styles exist, depending on the endpoint family:

StyleParametersUsed by
Entity listsoffset (0-based), limit, fields (comma-separated; id is always kept), filter[…] (on/off settings and has… relation flags)/rest-api/advertisers.do, campaigns.do, sites.do, banners.do, placements/summary.do. Advertisers, campaigns and sites come ordered by id, and without limit they return every row. /rest-api/sites/{siteId}/zones.do takes fields and filter only
Treesstart (0-based), limit (omit it for every entry)/rest-api/advertisers-tree.do, /rest-api/sites-tree.do; entries are advertisers or sites, ordered by id, each with everything beneath it. A page shorter than limit is the last one
Grid stylestart (0-based offset), limit, plus sort, dir (ASC/DESC), multisort (JSON array of {property, direction}), query (name search), activeOnly, onlyData, onlyTotalGrid-backed lists, e.g. /rest-api/template/list.do

Analytics reports page with offset and limit too, but their limit defaults differently — see Analytics reports via API. A requested fields name that no returned row carries is listed in the X-Ignored-Fields response header, and an unknown filter key is a 400 that lists the valid keys. /rest-api/placements/all.do is the one list that is not paged and takes no parameters: it returns every accessible placement. The per-endpoint rules (bounds on limit, the filter keys of each list) are in Entities: create, read, update, delete.

URL and parameter conventions

  • Kebab-case paths are the convention for new endpoints (/frequency-capping, /no-click-capping, /price-adjustment-rules), and most paths already use it. A few older paths still carry a camelCase segment — /advertiserShares.do, /siteShares.do, /floorCPMs.do, /banners/sendToApprove.do, /sites/{siteId}/changeAdServingDomain.do, /adsHosts.do, /invocationCodeHosts.do, /banner/dspPartners.do and the rest. They work; expect new features in kebab-case.
  • One path is snake_case: /rest-api/placements/update/click_through.do. Every neighbouring placement endpoint is kebab-case (update/non-standard.do), so this one is easy to guess wrong. Copy it exactly.
  • Parameters are form/query parameters, not JSON bodies, for nearly all endpoints. Send POSTs as application/x-www-form-urlencoded. The exceptions (JSON or multipart bodies) are called out on the pages that document them.
  • Enum parameters are per-parameter, not uniform. Most take the enum name (priority=PREMIUM, bannerType=EXTERNAL_FILE), several also accept the legacy numeric ID, and a few take the numeric ID only. The generated per-tag reference prints the accepted values for each parameter — when it shows a list of names, names are what that endpoint takes.
  • Dates are yyyy-MM-dd on most endpoints; the limits endpoints use yyyy-MM-dd-HH-mm. Each page states the format it needs.
  • Repeatable array parameters are passed by repeating the name: countryCode=US&countryCode=DE.

Calls that change data do not answer GET. Endpoints that delete, toggle, recalculate or reload — for example /rest-api/rules/{entity}/{entityId}/enable.do, …/remove.do and /rest-api/template/delete.do — accept POST only; a GET gets 405 Method Not Allowed.

Which method a delete takes. Deletes are split between DELETE and POST, and the wrong one gets 405. The main families:

MethodDelete endpoints
DELETEAdvertiser (/advertisers/{id}/delete.do) and banner (/banner/{id}/delete.do); targeting rules (/{entity}/{id}/targeting/{targetId}/delete.do, /{entity}/{id}/targetings.do) and preset domain, app-package and IP-range lists; capping by kind (/{campaign|banner}/{id}/frequency-capping.do and the other kinds); entity limits (/{entity}/{id}/limits.do); country prices (…/pricing/{countryCode}.do); price adjustment rules; conversion actions; labels; shares; campaign piggybacks; VAST companions, files and events; saved reports; advertiser payments and publisher payouts
POSTCampaign, site, zone and placement (…/{id}/delete.do); rule groups (/rule/{ruleId}/delete.do) and detaching them (/rules/{entity}/{id}/remove.do); cappings by id (/capping/delete.do); per-action limits; pricing models (…/pricing/{paymentModel}/remove.do); bid floors; templates with their files and properties; placement and site piggybacks; server-side trackers; tracking codes; PMP deals; media library files; dashboard widgets; site CPM thresholds

The per-tag reference gives the method of every endpoint.

Where the full field list lives. The task pages in this section name the fields a call needs and the ones that change its behaviour. Every field of an operation — with its type, description, accepted values and an example request — is in the generated reference, and each task page links to the exact entry, e.g. POST /rest-api/sites/update.do.

Error codes

HTTP statusMeaningBody
200Request processedEnvelope with success: true. A batch that applied some of its items and refused others also answers 200: success: false, the saved ids in updated and every refused one in failures
400Validation error, malformed parameter, missing required parameter, a value the database refuseserrors map and/or msg. A JSON body names the unknown field (with the accepted ones) or the field whose value is invalid (with accepted values for an enum). A value the database refuses — out of range, too long, a duplicate — is A value in the request is out of range or too long for its field. or The request conflicts with stored data…, without the SQL
401Authentication failed: bad hash, expired timestamp, unknown or unauthorised API key, no credential at all, a locked address, wrong password on auth/tokenerrors.error on general REST calls and on auth/token (error): Data fingerprint mismatch., Request is obsolete., No matching credentials found., Not logged in, API key access is not enabled for this account, Account is not active, Too many failed attempts, Username or password is incorrect. The analytics report endpoints put the text under rest_error instead
403Authenticated but not permitted (missing role permission or share)errors.error (and msg with permissionDenied: true where the endpoint always sent it); the missing grant is named — Your role lacks the OPEN_RTB permission. or You have no UPDATE permission on Campaign 2001. — so you know what to ask your network admin for
404Entity or endpoint not found, including a delete or update of something that does not exist. A deleted entity outside your shares answers exactly as an id that never existed — it is not a 403errors.error and/or msg naming the missing entity and id, e.g. Placement 4001 not found.
405Wrong HTTP verb for that path{"success": false, "message": "This method is not allowed for the requested URL."}
409The write clashes with an existing record (e.g. a PMP deal with the same deal ID, buyer and country), or a creative’s file is missing on the server — nothing was writtenconflict: true or bannersFileMissingOnFS: true, with the reason in msg / message (for a missing file, upload it again). Switching targeting on or off never checks files, so it is not refused this way
415Unsupported media type (wrong Content-Type on body endpoints)message, e.g. Content-Type 'text/plain' is not supported. Expected: application/json
429The caller’s daily analytics request limit is reachederrors["Too Many Requests"]: Daily requests limit reached.
500Internal errorGeneric Internal server error (as message, as errors.error on endpoints that answer that shape, or as msg on the analytics report endpoints) — details are logged server-side, never returned
503A service the answer depends on did not respond (e.g. the geo service behind region, city and carrier lists)errors.error; retry later rather than reading an empty list as “none”

Note: failures carry the HTTP status above, never a 200 with success: false. The body still explains the failure, so a client that treats any 4xx as a transport error should read the body of a 4xx before discarding it.

Warning: the error text is not always under the same key. Framework-level failures (missing parameter, wrong verb, unreadable body, unsupported media type, no handler, internal error) use message. Application-level failures use an errors object keyed by field name — with error as the field name when the failure isn’t attributable to one field. A handful of endpoints use a flat msg instead. Read all three before deciding a response carried no explanation.

Corner case: a URL that does not end in .do never reaches the API at all — the container answers it, and the 404 comes back in a different shape: {"success": false, "status": 404, "msg": "Not Found"}. If you see a status key, your path is malformed, not your parameters.

Analytics has two ceilings of its own, both set per network: Daily requests per user limit (default 100) and Records per request limit (default 10,000). Exceeding the first answers 429; asking for more rows than the second answers 400 with an errors.limit message naming the ceiling. A report refused for an earlier reason — permission, bad parameters, or the record-count ceiling — never counts against the daily quota; see Analytics reports via API for how the day is counted.

Interactive documentation

  • Swagger UI: https://<your-network-domain>/swagger-ui.html
  • Raw OpenAPI spec (JSON): https://<your-network-domain>/v3/api-docs

Swagger UI: the Authorize button, the tag filter, and endpoint groups that expand into their operations

Both require an authenticated session — open them in a browser where you are logged in to the control panel; anonymous requests get 401. The spec is the authoritative parameter reference; the pages in this section summarize the parts you’ll use most. Groups are sorted alphabetically and each one renders already expanded, so use the Filter by tag box to get to one.

Note: Swagger UI itself is loaded from a public CDN (unpkg.com). On a network that blocks outbound CDN traffic the page renders blank while /v3/api-docs keeps working — fetch the raw spec and open it in your own viewer.

Per-tag endpoint reference

For the exhaustive endpoint-by-endpoint reference — every path, parameter, request body and response per OpenAPI tag — see the generated API endpoint reference by tag. One page per tag (Advertisers, Campaigns, Banners, Targeting Rules, …), regenerated from the spec, so it always matches what Swagger UI shows. Use the hand-written pages below for task-oriented walkthroughs with curl examples, and the per-tag pages when you need the full parameter table of a specific endpoint.

Note: the spec declares two further groups — Mobile Networks and Referral Program — that carry no operations. The referral reads under /rest-api/referral-program/ exist and are covered in Network services and miscellaneous APIs, but they are not in the spec, so Swagger UI, the per-tag reference and the AI assistant’s api_search / api_read tools do not list them.

API quotas: how many requests can I make per day?

Only analytics reports are metered. Creating, editing, switching on/off, linking and changing limits, targeting or pricing through the API are not counted against any quota.

QuotaDefaultApplies toWhen exceeded
Daily requests per user limit100 reports per user per day/rest-api/analytics/... report calls, counted per API user429 with Daily requests limit reached. until the server’s next calendar day
Records per request limit10,000 rowsOne report call; also the row count you get when limit is left outA limit above it is a 400; page with offset instead

How to check where you stand: GET /rest-api/network/settings.do returns analyticsApi.dailyRequestLimit, analyticsApi.requestsUsedToday (your own count) and analyticsApi.recordsPerRequestLimit. Only a report that actually runs is counted — a call refused with 400, 401 or 403 costs nothing.

When the count resets. At midnight of the ad server’s own clock — the time zone the server runs in, which is neither your network’s reporting time zone nor yours. requestsUsedToday falls back to 0 at that moment, which shows you when it happens; Epom support can tell you the server time zone.

Raising the quota. Both values (Daily requests per user limit, Records per request limit) are network-wide settings; ask Epom support or your account manager to raise them.

Staying under it. Ask for one report grouped by the dimension you need (groupBy=PLACEMENT&groupRange=DAY) instead of one call per entity, pull yesterday once a day instead of polling, and use a separate API user per integration — the count is per user. See Automate reports.

Statistics by my own parameter (creator id, sub-id) through the API

Reports can only group by what the ad request carried, so the value has to be in the tag first — see Ad request parameters. Two ways, depending on how many labels you need:

You pass in the tagGroup the report byReport type
ch=<value> (data-channel) — one label per requestgroupBy=CHANNEL (filter: eqStr[CHANNEL]=<value>)General (default) and Advanced
cp.<name>=<value> (data-cp-<name>) — any number of named parametersstatisticType=HADOOP&groupBy=CUSTOM_PARAMETER&actionCustomParameterFragment=<name> — rows per value of that one parameterAdvanced only
# Yesterday's impressions per creator, per country, from the Advanced report
curl -G "https://<your-network-domain>/rest-api/analytics/JSON.do" -H "X-Api-Key: $APIKEY" \
  --data-urlencode "statisticType=HADOOP" \
  --data-urlencode "range=YESTERDAY" --data-urlencode "groupBy=CUSTOM_PARAMETER" \
  --data-urlencode "groupBy=COUNTRY" --data-urlencode "actionCustomParameterFragment=creator_id"

A grouping that comes back empty almost always means the requests did not carry the parameter (a VAST URL or a passback that drops it, a different tag version on the page) — check one live request URL before suspecting the report. Full parameter list: Analytics reports via API.

Usage expectations

  • Reference data (targeting values, categories, ad units) changes rarely — fetch it once and cache it rather than per request.
  • The one-time login token expires in 60 seconds; request it immediately before use.

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.