---
title: "Network services and miscellaneous APIs"
description: "Categories and labels, templates, PMP deals, DMP data, shares, conversion actions, piggybacks, VAST events, dashboard widgets, search, user search, network settings, referral and finances — key endpoints per area."
type: "reference"
audience: [network-manager, admin]
keywords: [api, labels, categories, templates, pmp, deals, dmp, shares, actions, piggyback, server-side tracker, vast, dashboard, widgets, search, users, user search, network settings, currency, time zone, referral, finances]
---

Fetch the complete documentation index at: https://epom.com/ad-server/docs/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Network services and miscellaneous APIs

The remaining functional areas, one section each. Examples append
[`$AUTH`](https://epom.com/ad-server/docs/api.md#the-auth-shorthand), the hash-authentication parameters (an `X-Api-Key`
header works the same) — see the [API overview](https://epom.com/ad-server/docs/api.md) for authentication. Each section links
to its generated endpoint reference, which lists every field with a description and an example
request.

## Categories and labels

Labels (used to tag banners and placements, and referenced by default-label rules) — the
whole **Labels** tag, 8 operations:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/label/list.do` | List all labels |
| GET | `/rest-api/label/{labelId}.do` | Get one label |
| POST | `/rest-api/label/create.do` | Create — **JSON body**, not form params |
| POST | `/rest-api/label/{labelId}/update.do` | Update. Only what is sent changes. A missing value, a missing object type on a default label (a plain label needs none), an existing label's value, or a `defaultLabelPlacementTypes` id that `defaultPlacementTypes.do` does not offer is a `400` naming the field (create too) |
| DELETE | `/rest-api/label/{labelId}/delete.do` | Delete |
| GET | `/rest-api/label/defaultObjectTypes.do` | Valid object types for default labels |
| GET | `/rest-api/label/defaultPlacementTypes.do` | Valid placement types for default labels |

The create/update JSON body needs `value` (the label name) and `defaultLabelObjectType` —
**1 = Banner, 2 = Placement**; a default label adds `defaultLabel=true` and its
`defaultLabelPlacementTypes` (placement-type ids from `defaultPlacementTypes.do`). All fields, with descriptions and an example
request: [`POST /rest-api/label/create.do`](https://epom.com/ad-server/docs/api/labels.md#post-rest-apilabelcreatedo).

```bash
curl -X POST "https://<your-network-domain>/rest-api/label/create.do?$AUTH" \
  -H "Content-Type: application/json" \
  -d '{"value":"Sports","defaultLabelObjectType":1,"defaultLabel":false}'
```

> **Corner case:** label create/update is one of the few endpoints that takes a **JSON request
> body** — sending form parameters returns a media-type or validation error. Creating a label
> whose `value` already exists is rejected.

> **Corner case:** `GET /rest-api/labels.do` (plural) also exists and returns every label as
> `{id, value}` pairs, but it is **deprecated** — it is the eighth operation of the Labels tag.
> Use `/rest-api/label/list.do`.

Advertising and publishing **category** lookups are read-only, and live under the Banners tag:

```
GET /rest-api/categories/advertising.do
GET /rest-api/categories/publishing.do
```

The **Categories** tag (9 operations) holds the OpenRTB category cards and the custom field values:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/iab-categories.do` | The IAB content categories a site or zone can be given or can block, with each one's id and IAB code. Needs *Open RTB* |
| GET/POST | `/rest-api/sites/{siteId}/openrtb.do`, `/rest-api/zones/{zoneId}/openrtb.do` | Read / set the Open RTB card: `iabCategories` (sent in bid requests) and `blockedIabCategories` (ads the site or zone refuses), each by id or IAB code such as `IAB1_2`, comma-separated. Only the lists you send change and an empty list clears it. A site also reads back its OpenRTB publisher id. Needs *Open RTB* plus view (read) or update (set) rights; a placement's card is under [Placements](https://epom.com/ad-server/docs/api/entities-sites-zones-placements.md#placements) |
| GET/POST | `/rest-api/additional-fields/{entityType}/{entityId}.do` | The custom field values of an advertiser, campaign, banner, site, zone or placement (`entityType` is `ADVERTISER`, `CAMPAIGN`, `BANNER`, `SITE`, `ZONE` or `PLACEMENT`): every field the network defines, `null` where the entity has no value. The `POST` takes a JSON object mapping a field's id or name to its value — free text up to 255 characters, an empty string clears it, only the fields sent change, and a field that does not exist refuses the whole request. It answers the values after the save. The field definitions themselves are under `/rest-api/additional-entity-fields-configuration` (see [Users and account](#users-and-account)) |

## Templates

Creative templates (reusable creative markup with typed properties) — the whole **Templates**
tag, 17 operations:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/template/list.do` | Paginated list. Each row carries `canBeUpdated` / `canBeRemoved` / `canBeShared` flags derived from your access level |
| GET | `/rest-api/template/edit.do` | Get template by ID |
| POST | `/rest-api/template/edit.do` | Create or update template |
| POST | `/rest-api/template/delete.do` | Delete template (POST only; a `GET` gets 405) |
| GET | `/rest-api/template/export.do` | Export as XML |
| POST | `/rest-api/template/import.do` | Import from XML |
| POST | `/rest-api/template/import-as-new.do` | Import as a new template |
| GET | `/rest-api/template/{templateId}/properties.do` | Properties of a template |
| GET/POST/POST | `/rest-api/template/template-property/list.do`, `…/edit.do`, `…/delete.do` | Manage properties |
| POST | `/rest-api/template/template-property/order.do` | Reorder properties (`order` is 0 to the number of properties minus one; outside, a `400`) |
| GET/POST/POST | `/rest-api/template/template-file/list.do`, `…/edit.do`, `…/delete.do` | Manage attached files |
| GET | `/rest-api/template-catalog/list.do` | The public template library (`query`, `placementType`): each template's status for your network — `AVAILABLE`, `INSTALLED`, `UPDATE_AVAILABLE` or `NOT_SHARED` |
| POST | `/rest-api/template-catalog/install.do` | Install a library template as your own (`entryId`); `update=true` replaces an installed one with the newer build, changing every banner that uses it |

`template/list.do` is a grid-style list: it pages, sorts and searches with the grid parameters of
[Pagination and list conventions](https://epom.com/ad-server/docs/api.md#pagination-and-list-conventions). All fields, with
descriptions and an example request:
[`GET /rest-api/template/list.do`](https://epom.com/ad-server/docs/api/templates.md#get-rest-apitemplatelistdo).

When `template-property/edit.do` edits an existing property, `propertyId` must belong to
`templateId` — another template's property is a `404`. A call refused for lack of edit rights
on the template saves nothing.

> **Corner case:** the template reads — list, `edit.do` by id, `export.do`, the property and file
> lists — are `GET`, so keep link-prefetching tools and crawlers away from authenticated template
> URLs. Delete is `POST`-only.

## PMP deals

Private Marketplace deals attached to campaigns and carried in outgoing OpenRTB bid requests —
the whole **PMP Deals** tag, 6 operations:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/campaign/{campaignId}/pmp-deals.do` | List deals of a campaign |
| POST | `/rest-api/campaign/{campaignId}/pmp-deal.do` | Create a deal |
| POST | `/rest-api/campaign/pmp-deal/{id}.do` | Update a deal |
| POST | `/rest-api/campaign/pmp-deals/delete.do` | Delete deals |
| POST | `/rest-api/campaign/{campaignId}/pmp-deals/enable.do` | Switch the campaign's PMP deals on |
| POST | `/rest-api/campaign/{campaignId}/pmp-deals/disable.do` | Switch them off (deals are kept) |

Deals only reach bid requests while the campaign's PMP deals switch is on — deals created
through the API stay dormant until `enable.do` is called. The switch needs *RTB PMP Deals*
and update access to the campaign's advertiser.

All five create parameters are required: `dealId` (external deal string used in the bid
request), `buyerId` (buyer seat), `auctionType`, `country` (ISO alpha-2 code, or `*` for a
global deal), `bidFloor` (minimum price in the campaign's currency; bids below it are
rejected).

`auctionType` has three values: `FIRST_PRICE` (winner pays their bid), `SECOND_PRICE` (winner
pays the second-highest bid plus an increment), `BID_FLOOR` (fixed minimum price).

```bash
curl -X POST "https://<your-network-domain>/rest-api/campaign/2001/pmp-deal.do?$AUTH" \
  -d "dealId=deal-123" -d "buyerId=buyer-456" \
  -d "auctionType=FIRST_PRICE" -d "country=US" -d "bidFloor=2.50"
```

All fields, with descriptions and an example request:
[`POST /rest-api/campaign/{campaignId}/pmp-deal.do`](https://epom.com/ad-server/docs/api/pmp-deals.md#post-rest-apicampaigncampaignidpmp-dealdo).

## DMP data

Audience segment import/export per DMP integration — the whole **DMP** tag, 2 operations:

| Method | Path | Purpose |
|---|---|---|
| POST | `/rest-api/dmp/{dmpName}/data.do` | Upload segment data — **multipart** `file` field |
| GET | `/rest-api/dmp/{dmpName}/data/{dateTime}/{fileName}.do` | Download segment data |

`{dmpName}` is one of seven values — `FIRST_PARTY`, `DTSCOUT`, `AIDATA`, `LOTAME`, `SITEMATH`,
`MEDIAQUARK`, `JOTTIX` — and the converter also accepts the integer ID for backward
compatibility. Requires write permission for that specific DMP; without it the call is a
permission error.

`FIRST_PARTY` and `DTSCOUT` are FTP-fed: their **URL** in **Admin → Audience & analytics → DMP
settings** is an FTP host, and the scheduled import connects to it on port 21 with the **User**
and **Password** set next to it — `FIRST_PARTY` reads every `.csv` file in the host's root folder.
An upload to either of them only stores the file (it can be downloaded again through the `GET`
above): it does not change that host and is not what the import reads, so to feed `FIRST_PARTY`
put the `.csv` files on the FTP host. For the other five DMPs the upload stores the file and also
sets the DMP's import **URL** to the file's download link. See
[Upload a First-Party audience file (FTP)](https://epom.com/ad-server/docs/use-cases/retargeting-and-audiences.md#upload-a-first-party-audience-file-ftp).

```bash
# DMP is one of AIDATA, LOTAME, SITEMATH, MEDIAQUARK or JOTTIX; the file must be in the format
# that DMP's import reads
curl -X POST "https://<your-network-domain>/rest-api/dmp/$DMP/data.do?$AUTH" \
  -F "file=@./audience-file"
```

## Shares

Grant users access to advertisers and sites (the API equivalent of the Shares screens) — the
whole **Shares** tag, 6 operations:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/advertiserShares.do` | Advertiser shares for a user |
| POST | `/rest-api/advertiserShares/update.do` | Create/update a share: `advertiserId`, `shareType`, optional `userId` |
| DELETE | `/rest-api/advertiserShares/{userId}/{advertiserId}.do` | Remove a user's share on an advertiser |
| GET | `/rest-api/siteShares.do` | Site shares for a user |
| POST | `/rest-api/siteShares/update.do` | Create/update a site share |
| DELETE | `/rest-api/siteShares/{userId}/{siteId}.do` | Remove a user's share on a site |

`shareType` is `IS_OWNER`, `CAN_EDIT` or `CAN_VIEW`. The lists leave deleted advertisers and
sites out; the remove calls still work on them, so a share left on a deleted entity can be
cleaned up.

The response echoes `userId`, the entity ID and the resulting `shareType`.

> **Corner case:** removing a share follows the console's *Unshare* rule — the SHARE
> permission at *all* level removes any share; at *shared* level only one below your own
> share on the entity, or one of a user you own. Otherwise `403`; a user without a share on
> the entity is a `404`.

> **Corner case:** omitting `userId` creates the share **for the calling user** — handy
> for self-assignment, surprising if you meant someone else. When operating with a
> shared-level (not all-level) permission, you can grant at most **your own level** on
> that entity (an editor grants `CAN_EDIT` or `CAN_VIEW`, never `IS_OWNER` — not even to
> itself), and you cannot change a share above your own, so the owner cannot be demoted.
> The one exception to the second rule is a user you own. Anything else is a `403`.

See [Sharing and the permission model](https://epom.com/ad-server/docs/concepts/sharing-permission-model.md) for how
share types interact with role permissions.

## Conversion actions

Actions (goals) are account-level and referenced from campaigns — the whole **Actions** tag,
14 operations:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/actions.do` | All actions shared to the user |
| POST | `/rest-api/action/create.do` | Create (`name`, attribution windows, optional `campaignId` to get the campaign-specific `pixelKey` back; `key` is always the action's own) |
| GET | `/rest-api/action/id/{id}.do` / `/rest-api/action/{actionKey}.do` | Get by ID / by key |
| GET | `/rest-api/action/id/{id}/tracking-code.do` | The Conversion Tracking Code window: `postback` (S2S URLs) and, with `campaignId`, `pixel` (JS pixel, image pixel URL, piggyback variant); optional `host`. See [S2S and pixels](https://epom.com/ad-server/docs/guides/conversions/s2s-and-pixels.md#via-the-api) |
| POST | `/rest-api/action/id/{id}/update.do` / `/rest-api/action/{key}/update.do` | Update; answers the updated action as the GET returns it, `applyAttributionWindowToServerToServer` and `rejectDuplicateConversions` included |
| DELETE | `/rest-api/action/{key}/delete.do` | Delete (marks the action deleted, as the console does; its key and its id then answer `404`, and campaign pricing stops listing its price. Built-in actions answer `403`) |
| GET | `/rest-api/campaign/{campaignId}/actions.do` | Actions with keys for a campaign |

A create needs `name` — never blank, at most 64 characters. What decides how conversions are
counted:

- the two attribution windows, click-to-conversion and view-to-conversion — each an amount of
  0–255 (`clickToConversionTimeFrame`, `viewToConversionTimeFrame`) plus a unit `SECOND`…`YEAR`
  (the matching `…PeriodType`), as in the console;
- `applyAttributionWindowToServerToServer` — apply the windows to server-to-server postbacks too;
- `rejectDuplicateConversions` — off by default; on, a repeat of the same event on one click is
  thrown away;
- `defaultAttributionType` — the last-resort attribution for a conversion that arrives with none
  of its own: `UNSPECIFIED`, `POST_CLICK` or `POST_VIEW`. Any other `AttributionType` name
  (`POST_CLICK_EXPIRED`, `SYSTEM`…) is a `400` listing these three.

A value outside those bounds is a `400` naming the field, and nothing is saved. All fields, with
descriptions and an example request:
[`POST /rest-api/action/create.do`](https://epom.com/ad-server/docs/api/actions.md#post-rest-apiactioncreatedo).

Conversion tracking is switched on and off per campaign with two endpoints filed under the
Campaigns tag: `POST /rest-api/campaign/{campaignId}/enable-actions.do` and
`…/disable-actions.do`.

> **Corner case:** a deleted action's price rows are not erased — the console keeps them
> too — but `globalActionPricing` in `GET /rest-api/campaign/{campaignId}/pricing.do` lists
> only live actions, as the console's per-action price list does. Country-and-action price
> rows keep showing the deleted action by name, as the console's country grid does.

> **Note:** the `/rest-api/campaign/{campaignId}/action/...` create/get/update/delete
> family is **deprecated** — use the account-level `/rest-api/action/...` endpoints
> plus `campaignId` where needed.

## Piggybacks

Tracking pixels fired alongside conversions, attachable at campaign, placement and site level —
the whole **Piggybacks** tag, 18 operations:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/piggyback/campaign/get.do` | List campaign piggybacks |
| POST | `/rest-api/piggyback/campaign/save.do` | Create: `campaignId`, `type` (`URL`/`BEACON`), `codeUrl`, `actionId` or `allActions=true`, optional `siteId`/`placementId` scope, `sampling` (0–100). With `id`, edits that piggyback instead — it must be one of the campaign's, or the save is a `400` naming `id` (the site and placement saves take `id` the same way) |
| POST | `/rest-api/piggyback/campaign/update.do` | Update: `campaignId` and a JSON array of rows, each with the piggyback `id` and the fields to change (`codeUrl` text, `active` true/false, `sampling` 0–100, `deliveryAttribution`, `actionId`). A row of the wrong type or out of range is a `400` naming the field, and then no row is saved |
| DELETE | `/rest-api/piggyback/campaign/{id}.do` | Delete |
| POST | `/rest-api/piggyback/campaign/enable.do`, `…/disable.do` | Toggle |
| GET | `/rest-api/piggyback/placement/get.do` | List placement piggybacks |
| POST | `/rest-api/piggyback/placement.do` | Create/save a placement piggyback: `placementId` and `campaignId` (the campaign the placement belongs to) are required |
| POST | `/rest-api/piggyback/placement/{id}/update.do` | Change one placement piggyback — `codeUrl`, `active`, `sampling`, `deliveryAttribution`, `actionId` or `allActions=true`; a field not sent keeps its value and the type cannot change. Answers the piggyback as `piggyback` |
| POST | `/rest-api/piggyback/placement/{id}/delete.do` | Remove one placement piggyback |
| POST | `/rest-api/piggyback/placement/enable.do`, `…/disable.do` | Toggle |
| GET | `/rest-api/piggyback/site/get.do` | List site piggybacks |
| POST | `/rest-api/piggyback/site.do` | Create/save a site piggyback: `siteId` is required, `campaignId` optional |
| POST | `/rest-api/piggyback/site/{id}/update.do` | Change one site piggyback, as for a placement |
| POST | `/rest-api/piggyback/site/{id}/delete.do` | Remove one site piggyback |
| POST | `/rest-api/piggyback/site/enable.do`, `…/disable.do` | Toggle |

A save needs the owner's id — `campaignId`, `placementId` or `siteId` as in the table — the
`type` (`BEACON` for an HTML snippet, `URL` for a redirect) with its `codeUrl`, and either one
`actionId` or `allActions=true`. `deliveryAttribution` decides which conversions the pixel fires
for: `ALL`, `POST_CLICK_ONLY` or `POST_VIEW_ONLY`. All fields, with descriptions and an example
request: [`POST /rest-api/piggyback/campaign/save.do`](https://epom.com/ad-server/docs/api/piggybacks.md#post-rest-apipiggybackcampaignsavedo)
— the placement and site saves are listed next to it.

> **Corner case:** the three families delete differently: a campaign piggyback with
> `DELETE /rest-api/piggyback/campaign/{id}.do`, a placement or site piggyback with
> `POST …/{id}/delete.do`. The placement and site calls need update rights on the placement's
> site (on the site itself, for a site piggyback), besides *Piggyback Pixel Tracking*.

## Server-side trackers

Third-party tracker URLs fired server-side during ad serving, on banners and placements — the
whole **Server-Side Trackers** tag, 10 operations:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/server-side-tracker/banner/list.do` | List a banner's trackers |
| POST | `/rest-api/server-side-tracker/banner/add.do` | Add a tracker |
| POST | `/rest-api/server-side-tracker/banner/delete.do` | Delete one tracker |
| POST | `/rest-api/server-side-tracker/banner/enable.do`, `…/disable.do` | Turn server-side tracking on/off for the banner |
| GET/POST | `/rest-api/server-side-tracker/placement/list.do`, `…/add.do`, `…/delete.do`, `…/enable.do`, `…/disable.do` | The same five on placements |

`add.do` takes `domainId`, `url` (publisher macros supported) and `event` — one of
`IMPRESSION`, `CLICK` or `REQUEST`. `list.do` takes `domainId`. `delete.do`, `enable.do` and
`disable.do` all take `id`.

> **Corner case:** the parameter names do not mean what they look like. **`domainId` is the
> banner or placement ID**, not a domain. And `id` changes meaning per endpoint: on
> `delete.do` it is the **tracker record** ID, while on `enable.do` / `disable.do` it is the
> **banner or placement** ID.

> **Note:** a tracker only fires while server-side tracking is enabled on its banner or
> placement, so `add.do` alone does nothing until `enable.do` has been called once.

See [Server-side trackers](https://epom.com/ad-server/docs/guides/conversions/server-side-trackers.md) for the UI flow.

> **Corner case:** every piggyback call — campaign, placement and site alike: listing,
> saving, updating, deleting and switching an entity's piggybacks on or off — needs the
> *Piggyback Pixel Tracking* permission enabled, the one that shows the piggyback panel in
> the console. Without it, or with it disabled, the call is a `403` and nothing changes.
> The campaign `get.do` also needs view rights on the campaign, and answers `404` for a
> campaign that does not exist. `enable.do` / `disable.do` take the campaign, placement or
> site as `id`; leaving it out is a `400`.
>
> The placement and site `get.do` lists answer whether that entity's piggybacks are switched
> on or off, as the console grid does; `piggybacksEnabled` says which, and while it is
> `false` none of the listed rows fire. The campaign list, like the console's campaign grid,
> is empty while the campaign's piggybacks are off.

## VAST video events

Per-banner and per-placement video tracking configuration, plus the companions and video
files of a video banner — the whole **VAST** tag, 24 operations:

| Method | Path | Purpose |
|---|---|---|
| GET/POST | `/rest-api/banner/{id}/vast/events.do` | Read / update VAST tracking events |
| GET/PUT/DELETE | `/rest-api/banner/{id}/vast/progress-events.do` | Progress-marker events |
| GET/PUT/DELETE | `/rest-api/banner/{id}/vast/tracking-events.do` | Third-party tracking pixels |
| GET/POST, GET/PUT/DELETE | `/rest-api/placement/{id}/vast/…` | The same three families on placements |
| GET | `/rest-api/vpaid/framework/list.do` | Active VPAID frameworks (IDs for banner creation) |
| GET/POST | `/rest-api/banner/{bannerId}/vast/companions.do` | List a video banner's companion ads / add one without a file upload: `type` `STATIC` (image from `externalCreativeLink`, downloaded and stored), `IFRAME` (`externalCreativeLink` plus `width` and `height`), `HTML_STATIC` (`markup` plus `width` and `height`) or `HTML_TEMPLATE` (a Video Companion `templateId` plus `width` and `height`). Needs *VAST Companion Ads*; the add answers the banner's companions and the new one's id |
| DELETE | `/rest-api/banner/{bannerId}/vast/companions/{companionId}.do` | Delete one companion |
| GET/POST | `/rest-api/banner/{bannerId}/vast/media-files.do` | List / add the video files of an *Advanced Local Video(s)* banner: a multipart `file` or a public `url` the server downloads once, and `scaleTo` (`ORIGINAL`, `_1080P`, `_720P`, `_480P`, `_360P`, `_320P`, `_240P`) where the network compresses video creatives. The network's video size limit applies; the answer lists the banner's files and the ids of the new ones |
| POST | `/rest-api/banner/{bannerId}/vast/media-files/from-library.do` | Add a [media library](https://epom.com/ad-server/docs/guides/advertising/media-library.md) video by `mediaAssetId` (needs *Media Library* too). The file is referenced, not copied; a video the banner already has is not added again — `created` is empty and `alreadyAdded` names its row |
| DELETE | `/rest-api/banner/{bannerId}/vast/media-files/{mediaFileId}.do` | Remove one video file; an uploaded file is erased from storage, a library file stays in the library |

Note the method split: the `events.do` family updates with `POST`, while the two event-list
families add with `PUT` and clear with `DELETE`.

The `DELETE` calls take a JSON array of event ids; each must be an event of the banner or
placement in the path. An id of another entity's event is a `404` naming it, and nothing is
deleted.

A progress event's `time` is an offset `HH:MM:SS` (optionally `.mmm`) or a percentage from
`0%` to `100%`; anything else, `150%` included, is a `400`. Tracker URLs follow the network's
URL-validation switch, as every REST URL does (see the
[URL note](https://epom.com/ad-server/docs/api/entities-crud.md#two-create-or-update-styles)): with it off they need a scheme and a
host, and tracker macros such as `{clickid}`, `{{sub1}}`, `[timestamp]` and `%%CACHEBUSTER%%`
are accepted in them. A missing or deleted banner or placement is a `404`.


## Dashboard widgets

Programmatic management of the widgets on the account dashboard — the whole **Dashboard** tag,
6 operations:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/dashboard/widgets.do` | Your own dashboard: `widgets` — each with `id`, `title`, `displayTitle` (the title as shown in your language), `type`, column `x`, row `y`, and `value` (NOTICE text) or `data` (the report definition, the same fields create and update take as `data.*`). Sorted by column, then row. Runs no report: feed a widget's `data` to the [Analytics reports via API](https://epom.com/ad-server/docs/api/analytics-api.md) for its figures. Requires the Dashboard tab permission (`403` without) |
| POST | `/rest-api/dashboard/widget/create.do` | Create — `type` (`TABLE`, `LINE_CHART`, `PIE_CHART`, `BAR_CHART`, `NOTICE`), `title`, grid position `x` (0–3) / `y` (0–127), report configuration via `data.*` parameters (same model as the [Analytics reports via API](https://epom.com/ad-server/docs/api/analytics-api.md): `data.statisticType`, `data.range`, `data.groupBy`, `data.eqLong`, …) |
| POST | `/rest-api/dashboard/widget/update.do` | Update |
| POST | `/rest-api/dashboard/widget/delete.do` | Delete |
| GET/POST | `/rest-api/self-serv/dashboard/{login}/{hash}/{timestamp}.do` | Self-serve dashboard analytics feed |

Widget parameters:

| Parameter | Values | Notes |
|---|---|---|
| `type` | `TABLE`, `LINE_CHART`, `PIE_CHART`, `BAR_CHART`, `NOTICE` | **Required on create** — a missing type returns an `errors.type` message, not a 400 |
| `title` | string, max 64 chars | Required and must not be blank |
| `value` | string, max 1024 chars | The text shown, for `NOTICE` widgets |
| `x` | 0–3 | Grid column — but see the corner case |
| `y` | 0–127 | Grid row |
| `data.*` | Report configuration | The same model as the [Analytics reports via API](https://epom.com/ad-server/docs/api/analytics-api.md): `data.statisticType`, `data.range`, `data.groupBy`, `data.eqLong`, `data.splitColumnsBy`, … — 21 nested parameters in all |
| `id` | integer | Required on update; the widget to change |

All fields, with descriptions and an example request:
[`POST /rest-api/dashboard/widget/create.do`](https://epom.com/ad-server/docs/api/dashboard.md#post-rest-apidashboardwidgetcreatedo).

> **Corner case:** `NOTICE` widgets require a `value` — it is the text they display. Chart and
> table widgets **do not** keep the `value` you send: on save the server overwrites it with the
> JSON serialization of the `data.*` configuration, so the field is effectively output-only for
> those four types.

> **Corner case:** `x` is documented and validated as 0–3, then folded modulo 2 by the setter
> when the dashboard moved to a two-column layout. `x=2` lands in column 0 and `x=3` in
> column 1 — silently, with no error. Send 0 or 1.

> **Note:** `update.do` takes the same parameters as create, with two exceptions the server
> handles for you: the widget **type is taken from the existing record and cannot be changed**,
> and entity filters (`data.eqLong`) are preserved server-side, so you need not re-submit them.
> If `data` is present and `data.range` is not, the range defaults to `TODAY`.

> **Corner case:** create, update and delete need the same *Dashboard tab* permission as
> the list; a role without it gets `403 Your role has no Dashboard tab.` and nothing changes.

## Search and suggestions

The whole **Search** tag, 2 operations:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/suggest-items.do` | Autocomplete across sites, zones, placements, banners, campaigns, advertisers. `query` matches names; prefix with `#` for ID lookup (`#123`). Narrow with `entities`, `myItems`, `shareType`, `filterPath`. Banners under moderation (`NEW`, `PENDING`, `REJECTED`) are found too — the console's search box leaves them out — and every banner result carries `approvalStatus`. Each result also carries its parents' ids (`advertiserId` on a campaign, `advertiserId` and `campaignId` on a banner, `siteId` on a zone, `siteId` and `zoneId` on a placement); with `includeActive=true`, `active` too — the entity's on/off switch (`inactive` is not the switch: it means no traffic in the last two days) |
| POST | `/rest-api/search/campaigns.do` | Campaign search |

`entities` restricts `suggest-items.do` to `SITE`, `ZONE`, `PLACEMENT`, `BANNER`, `CAMPAIGN`
or `ADVERTISER`; left out, it searches every type you may see. All fields, with descriptions and
an example request: [`GET /rest-api/suggest-items.do`](https://epom.com/ad-server/docs/api/search.md#get-rest-apisuggest-itemsdo).

`POST /rest-api/search/campaigns.do` takes a **JSON body**, not form parameters (its fields:
[`POST /rest-api/search/campaigns.do`](https://epom.com/ad-server/docs/api/search.md#post-rest-apisearchcampaignsdo)). `name`
matches by "contains", and paging is `limit` with a **0-based `page`** rather than an offset. The
switches `showTargeting`, `showPricing` and `showLimits` add those sections to each campaign and
are honoured only with *Manage Demand Targeting*, *Manage Pricing* and *Manage Capping &
Limitations* respectively. The answer is `{data, total}`; a caller without the Campaigns SHARE
permission sees only the campaigns shared with them.

> **Corner case:** `query` is required — omitting it returns HTTP 400. The `entities` schema
> advertises the whole analytics dimension enum (the ids and `OPEN_RTB_PUBLISHER_ID` among
> them) because it reuses that Java type; the description of the parameter lists the six entity
> names above as the ones that are accepted.

## Users and account

The **Users** tag, 27 operations, of which these are the ones an integration usually needs:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/action-log/mine.do` | **Your own** action-log entries, newest first — what you did in the console, over the API or through the AI assistant, reads included. Each entry: `at` (ISO-8601), `via` (`UI`, `REST_API`, `LEGACY_REST`, `MCP`, `SYSTEM`), `action`, `pathIds`, `details` (values under a secret name — password, hash, API key, token — read `***`). `from` (ISO-8601 instant, default 24 hours ago), `start` (position, default 0), `limit` (1–1000, default 100); `more` says whether a full page came back. Never another user's entries, whatever your role — the network-wide log stays on the admin **Actions log** page |
| GET | `/rest-api/system-users/search.do` | Find users by name, one page at a time: `query` (substring of username, e-mail, first or last name), `roles` (comma-separated role ids or names, case-insensitive), `activeOnly`, `start`, `limit` (1–500, default 50). Answers `{total, start, limit, users:[{userId, username, email, firstName, lastName, roleId, role, status, created}]}` — never a password or API key. Use `userId` for [shares](#shares) |
| GET | `/rest-api/system-users.do` | Every visible user at once, unpaged (`roles` filter optional; a value that names no role is a `400` listing the roles whose users you can see) |
| POST | `/rest-api/system-users/create-and-share.do` | Create a user and, optionally, share advertisers and sites with them — the console's *Create user & share*. `login`, `email`, `role` (id or name, one your role may create users in, never an administrator role), optional `firstName`, `lastName`, `advertiserIds`, `siteIds`, `shareType` (default `CAN_VIEW`). No password in or out: the user is e-mailed a set-password link. A login or e-mail in use answers 400 under `errors`; a role you may not assign or a share you may not give answers 403; an entity you cannot see answers 404. Answers `{userId, username, email, roleId, role, active, shareType, advertiserIds, siteIds, invitationSentTo}` |
| GET | `/rest-api/aclrole/list.do` | Roles list |
| GET | `/rest-api/notification-settings.do` | Your notification settings, as the Preferences page shows them: every event the network lets users subscribe to and whether you are, the extra addresses that get a copy and `receiveNotificationsByEmail`. Needs view rights on campaigns or inventory; a role with *Skip All Notifications* is refused |
| POST | `/rest-api/notification-settings/subscriptions.do` | **Replace** the events you subscribe to: `templateIds` (comma-separated or repeated) lists every event to keep or add, all others are dropped, and an empty list unsubscribes from all. Only events the `GET` lists can be chosen |
| POST / DELETE | `/rest-api/notification-settings/recipients.do` | Add / remove one extra recipient: `email`. An address already on the list is not added twice |
| POST | `/rest-api/user/update.do` | Update user info |
| GET/POST | `/rest-api/user-preference/get.do`, `…/save.do` | Read / save preferences. `get.do` answers one `preference` object and never a password field; `save.do` takes a **JSON body** |
| POST | `/rest-api/user-preference/update-profile.do` | Change your own profile without touching credentials — a JSON body with any of the name, contact and display preferences ([fields](https://epom.com/ad-server/docs/api/users.md#post-rest-apiuser-preferenceupdate-profiledo)). Password, e-mail, API key and role are never changed here; any other property is listed back in `ignoredFields`. `locale` is accepted only when the network lets signed-in users change the language |
| POST | `/rest-api/user-preference/change-password.do` | Change password |
| GET | `/rest-api/user-preference/check-email.do` | Email uniqueness check — only for a role that may create users (`403` otherwise); a malformed address is a `400` |
| POST | `/rest-api/forgot.do`, `/rest-api/resetPasswordExec.do` | Password reset flow |
| POST | `/rest-api/register-user/{key}/{hash}/{timestamp}.do`, `/rest-api/user-sign-up/{key}/{hash}/{timestamp}.do` | Registration/sign-up (signed links) |
| GET | `/rest-api/blocked/entities.do` | Entities blocked for the account — without network-wide inventory view, only the rules on advertisers and sites shared with you (none when nothing is shared) |
| GET/POST | `/rest-api/users/{username}/scheduledEvents.do`, `…/{scheduledEventId}.do` | Scheduled report events — your own, or (admin) those of a user whose role you manage. Any other username, existing or not, answers the same 404 |
| GET/POST | `/rest-api/additional-entity-fields-configuration/list.do`, `…/edit.do`, `…/delete.do` | Custom entity fields |
| GET | `/rest-api/adunit/list.do` | Ad unit catalog (`/rest-api/ad-units.do` adds each unit's placement types) |
| GET | `/rest-api/referral/getBilling.do` | Referral billing records — see below |

> **Note:** scheduled events are listed on the collection path and updated on the item path.
> There is no POST on `scheduledEvents.do` and no GET on `scheduledEvents/{id}.do`.

Password reset and sign-up are the only endpoints here reachable without an existing session;
everything else follows the standard auth conventions.

> **Corner case:** both user lists show what the console's Users grid shows you: the users of
> every role your role may view. A `roles` value naming a role outside that set returns no users
> rather than an error; a value naming no role at all is refused by `search.do` with the list of
> roles you can see.

## Network settings

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/network/settings.do` | Read-only settings that shape your figures and requests: `currency` (every price, bid, budget and revenue is in `USD`), `reportingTimeZone` (`id`, `utcOffset` — the zone General reports and the dashboard bucket days and hours in; only the Advanced report takes its own `usersTimeZoneId`), `newEntities` (`active` — the on/off state an advertiser, campaign or banner gets when a create leaves `active` out; `siteApprovalStatus`; `piggybackActive`), `analyticsApi` (`dailyRequestLimit`, `requestsUsedToday`, `recordsPerRequestLimit`) and `creativeFileLimits` (`maxImageFileBytes`, `maxVideoFileBytes`). `siteApprovalStatus` is left out if you may not create sites, and `analyticsApi` if your role has no report type |

Any logged-in user may read these.

## Referral program

Two families of endpoints, one for the person who refers and one for the network administrator who pays out.

**Your own referral program** — what the account's **Referral program** tab shows. Needs the
*Manage Referral Program* permission:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/referral-program/list-registered.do` | The clients who signed up through your link: `emailMasked`, `registrationDate`, `status` (and its label `statusStr`). Filters `year`, `month` (repeatable) and `status` (`UNDER_REVIEW`, `APPROVED`, `ACTIVE`, `INACTIVE`) |
| GET | `/rest-api/referral-program/list.do` | Your revenue and payout status per referred client and month: `emailMasked`, `year`, `month`, `revenue`, `status` (and its label `statusStr`), `comments`. Filters `year`, `month` and `status` (`UNCONFIRMED`, `CONFIRMED`, `PAID`, `DECLINED`) |
| GET | `/rest-api/referral-program/total-earnings.do` | `totalEarnings` and `paidEarnings` for the same `year` / `month` / `status` filters. `DECLINED` payouts are left out of both sums unless you filter on `DECLINED` |

The two lists answer `{"data": [...], "total": N}` and take the grid paging parameters `start`,
`limit`, `sort` and `dir` (`ASC` / `DESC`). `sort` is `emailMasked`, `registrationDate` or
`statusStr` on `list-registered.do`, and `emailMasked`, `statusStr`, `revenue`, `year` or `month`
on `list.do`; by default `list-registered.do` is newest registration first and `list.do` newest
month first. Without the permission the two lists answer `200` with an empty page, so an empty
list does not prove you have no referrals; `total-earnings.do` answers `403`.

> **Warning:** these three endpoints are **not in the OpenAPI spec**, so they appear neither in
> the generated [per-tag reference](https://epom.com/ad-server/docs/api/endpoints.md) nor in the AI assistant's `api_search` /
> `api_describe` (and `api_read` / `api_write` only forward documented operations), and the
> **Referral Program** tag is empty. The endpoints are secured like every other REST
> call (see the [API overview](https://epom.com/ad-server/docs/api.md)); use `GET`.

**The billing ledger** behind the admin page, filed under the **Users** tag:

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/referral/getBilling.do` | Every referral billing record for the account — earnings, payment status and referral details. Unpaginated |

It is gated by the **Referral Program Billing** *admin-UI* permission on the caller's role (the
role editor's *Admin UI permissions*, the one behind **Admin → Referral program billing**) — a
different permission family from the usual account permissions. Without it the response is
HTTP **403** naming that permission. Approving referred clients and editing commission brackets
stay in the control panel.

## Network finances

Advertiser payments (the **Advertiser payments** grid of **Account → Billing** and the advertiser's Payments card):

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/advertiser/{advertiserId}/payments.do` | The advertiser's payments newest first — `year`, `month` (repeatable) narrow them, `start` / `limit` (1–1000) page them. Answers `{advertiserId, advertiserName, total, totalAmount, payments:[{paymentId, date, year, month, amount, comment}], balance}`; `balance` is the row (`startBalance`, `charges`, `payments`, `endOfMonthBalance`) of `balanceMonth` (`yyyy-MM`, default the current month) or `null` |
| POST | `/rest-api/advertiser/{advertiserId}/payments.do` | Book a payment: `amount` (> 0), `date` (`yyyy-MM-dd`, default today, 2010–2050), `comment` (≤ 200). Moves the balance rows from that month on by the amount. Refusals name the field under `errors` |
| DELETE | `/rest-api/advertiser/{advertiserId}/payments/{paymentId}.do` | Remove a payment and take it back out of the balances |

All three need the network billing management and advertiser-funds permissions (the list also campaign view); the list
also answers to *Show Advertisers' Funds* alone, the grant the Payments card is shown for. With a
shared rather than full campaign view, an advertiser not shared with you answers 404. There is no edit — remove and add
again, as in the console.

Publisher payouts (the **Publisher payments** grid of **Account → Billing** and the site's Payments card):

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/site/{siteId}/payouts.do` | The site's payouts newest first, with the same `year`, `month`, `start`, `limit` and `balanceMonth` parameters. Answers `{siteId, siteName, total, totalAmount, payouts:[{paymentId, date, year, month, amount, comment}], balance}`; `balance` is `{year, month, balance, paidOut, toBePaid}` for `balanceMonth` or `null` |
| POST | `/rest-api/site/{siteId}/payouts.do` | Book a payout: `amount` (> 0), `date` (`yyyy-MM-dd`, default today), `comment` (≤ 200). Moves the balance rows from that month on |
| DELETE | `/rest-api/site/{siteId}/payouts/{paymentId}.do` | Remove a payout and take it back out of the balances |

These need the network billing management and publisher-payments permissions (the list also inventory view); the list
also answers to *Show Publishers' Payouts* alone, the grant the site's Payments card is shown for. With a
shared rather than full inventory view, a site not shared with you answers 404.

> **Note:** invoices, balance recalculation and the network-wide balance grids are still managed only in the control
> panel (**Account → Billing**). The same applies to approving referral clients and editing the commission brackets.

## Mobile networks

**Mobile Networks** is a declared tag with no endpoints at all (**Referral Program** is empty in the spec too, though its
endpoints exist — see above): no mobile-network discovery or configuration endpoints exist. Mobile advertising is configured through the entities you
already have:

- in-app placements — `POST /rest-api/placements/update/app.do` and `…/update/mobile.do` (see
  [Entities CRUD](https://epom.com/ad-server/docs/api/entities-crud.md));
- mobile advertising-network banners — `advertisingNetworkParameters` on banner create/update;
- carrier targeting — the `mobile-carrier` dimension and
  `GET /rest-api/targeting/mobile-carrier/bycountry/values.do` (see
  [Targeting, capping and limits](https://epom.com/ad-server/docs/api/targeting-capping-limits.md));
- `MOBILE_NETWORK` is available as an analytics group-by dimension (see the
  [Analytics reports via API](https://epom.com/ad-server/docs/api/analytics-api.md#grouping)).

## Related

- [API overview](https://epom.com/ad-server/docs/api.md)
- [Entities CRUD](https://epom.com/ad-server/docs/api/entities-crud.md)
- [Targeting, capping and limits](https://epom.com/ad-server/docs/api/targeting-capping-limits.md)
- [Analytics reports via API](https://epom.com/ad-server/docs/api/analytics-api.md)
- [Generated endpoint reference by tag](https://epom.com/ad-server/docs/api/endpoints.md)
- [Shares (UI guide)](https://epom.com/ad-server/docs/guides/collaboration/shares.md)
- [Conversion actions (UI guide)](https://epom.com/ad-server/docs/guides/conversions/conversion-actions.md)
- [Piggybacks (UI guide)](https://epom.com/ad-server/docs/guides/conversions/piggybacks.md)
- [Server-side trackers (UI guide)](https://epom.com/ad-server/docs/guides/conversions/server-side-trackers.md)
- [Dashboards (UI guide)](https://epom.com/ad-server/docs/guides/analytics/dashboards.md)
- [PMP deals on a campaign](https://epom.com/ad-server/docs/guides/advertising/pmp-deals.md)