---
title: "Advertisers and campaigns via API"
description: "API endpoints, curl examples and corner cases for creating, reading, updating, copying, moving and deleting advertisers and campaigns."
type: "reference"
audience: [network-manager, admin]
keywords: [api, crud, advertiser, campaign, copy, move, priority, adsHost, autolinkCategories, ignoredFields, curl]
---

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.

# Advertisers and campaigns via API

The demand side of the account starts here: create the advertiser, then its campaigns, then [banners](https://epom.com/ad-server/docs/api/entities-banners.md) inside them. This page covers the advertiser and campaign endpoints, the fields that change how they behave, copy and move, and the corner cases that trip scripts. 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), and send parameters form-encoded unless noted — see the [API overview](https://epom.com/ad-server/docs/api.md) for authentication and [Entities via API](https://epom.com/ad-server/docs/api/entities-crud.md) for the corner cases every entity shares.

## Who this is for

Network managers and advertisers who create or maintain advertisers and campaigns from a script, and admins. Several campaign settings apply only when your role holds the matching permission — see the corner cases below.

## Advertisers

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/advertisers.do` | List all accessible advertisers, ordered by id (filters: `advertisingCategories`, `filter[…]`; `offset` / `limit`; `fields`). Returns a bare array, not an envelope |
| GET | `/rest-api/advertisers/{advertiserId}.do` | Get one advertiser |
| GET | `/rest-api/advertisers-tree.do` | Full advertiser → campaign → banner tree. On a large network read it in pages with `start` (entries to skip, 0 or more) and `limit` (1 or more; anything else is a `400`) — advertisers ordered by id, a page shorter than `limit` is the last |
| GET | `/rest-api/advertiser/{advertiserId}/campaigns.do` | Campaigns of one advertiser |
| POST *or* PUT | `/rest-api/advertisers/update.do` | Create (no `id`) or update (with `id`). Both verbs are mapped and behave identically |
| DELETE | `/rest-api/advertisers/{advertiserId}/delete.do` | Delete advertiser |

Create an advertiser:

```bash
curl -X POST "https://<your-network-domain>/rest-api/advertisers/update.do?$AUTH" \
  -d "name=Northwind Media" \
  -d "contactName=Dana Whitfield" \
  -d "contactEmail=dana@northwind.example" \
  -d "active=true"
# → {"success":true,"id":1001}
```

A create needs `name`; everything else is optional. Send `active` explicitly: left out, it
takes the network's default for new entities (`newEntities.active` in
`GET /rest-api/network/settings.do`). `enableLimits=true` creates the advertiser's limit record
when it has none and needs *Manage Capping & Limitations*; it is not a stored field and is never
listed in `ignoredFields`. Several advertiser fields apply only with a role permission — see
[Activation, approval, status](https://epom.com/ad-server/docs/api/entities-linking-status-tags.md#activation-approval-status).

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

> **Corner case:** validation failures on this endpoint come back as a **400** with a
> per-field map, one key per rejected field:
> `{"success":false,"errors":{"contactEmail":"Please provide a valid email address (with domain)","name":"Required"}}`.
> Read `errors` key by key — every failing field is listed, not only the first.

> **Corner case:** `adsHost` needs the *Set Ad Serving Domain (Campaigns)* permission. Without
> it the field is ignored — an existing advertiser keeps its domain and a new one gets your
> own user's ad-serving domain, as in the console. With it, the value must be one of the
> network's ad-serving domains (the list the console's picker offers, also returned by
> `GET /rest-api/adsHosts.do`) or blank for the system default; anything else fails with
> `errors.adsHost`. Sending back the domain the advertiser already has is always accepted.

## Campaigns

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/campaigns.do` | List all accessible campaigns, ordered by id (filters: `active`, `advertiserId`, `labels`, `filter[…]`; `offset` / `limit`; `fields`) |
| GET | `/rest-api/campaign/{campaignId}.do` | Get one campaign — every field `update.do` writes, under the same name (`autoTagLandingUrl`, `maxActionPriceOverride`, `campaignAliasForActionTracking`, `allowNewPlacementsAutolinking`, …); `creation_time` is the creation day at midnight |
| POST | `/rest-api/campaign/create.do` | Create (requires `advertiserId`) |
| POST | `/rest-api/campaign/{campaignId}/update.do` | Update |
| POST | `/rest-api/campaign/{campaignId}/delete.do` | Delete |
| POST | `/rest-api/campaign/{campaignId}/{operation}/{advertiserId}.do` | Copy or move to another advertiser (`operation` = `COPY` or `MOVE`) |
| POST | `/rest-api/campaigns/copy/bulk/{advertiserId}.do` | Bulk copy campaigns |
| GET | `/rest-api/campaigns/priorities.do` | List valid priority values |
| POST | `/rest-api/campaigns/labels.do` | Add, replace or remove labels on many campaigns — see [Bulk labels](https://epom.com/ad-server/docs/api/entities-linking-status-tags.md#bulk-labels) |

```bash
curl -X POST "https://<your-network-domain>/rest-api/campaign/create.do?$AUTH" \
  -d "advertiserId=1001" \
  -d "name=Brand Awareness Q3" \
  -d "priority=STANDARD_MEDIUM" \
  -d "weight=50" \
  -d "active=true"
```

A copy answers with the new ids in `created` and, in `copies`, each copy's `id`, `name` and
whether it starts `active`. Pass `name` to name the copy — with `copyCount` above 1 the later
copies become `<name> 2`, `<name> 3`… — or leave it out to keep the source's name (with `_copy`
appended when the target advertiser already has a campaign of that name). A campaign copy
starts switched **off** unless `preserveActive=true`.

Every copy operation — campaign (`copyCount`), banner (`copyCount`, also per campaign in the
bulk form), bulk campaign copy (`numberOfCopies`), `copy-placement` and zone copy (`count`) —
makes **1 to 20** copies per call; anything else is a 400 naming the parameter and the limit,
and nothing is copied. If a banner copy fails after some copies were saved, the answer is a 500
naming the copy that failed, with `created` listing the copies that do exist (per campaign in the
bulk form, next to `failed`). The bulk campaign copy takes a JSON array of
`{companyId, companyName, banners: [{itemId, link, active}]}` (`item_id` is accepted too);
`banners` is required — send `[]` to copy a campaign without its banners — and a campaign whose
copy fails is listed in `failedCampaignIds` with `success: false`. The bulk banner copy/move
(`/rest-api/banner/{bannerId}/{operation}/bulk.do`) needs `campaignIds`, refuses an unknown
or deleted campaign before copying anything, takes exactly one campaign for `MOVE`, and
lists a campaign whose copy failed in `failed`.

`priority` takes one of six values — `GET /rest-api/campaigns/priorities.do` returns
exactly this list:

| Value | Meaning |
|---|---|
| `PREMIUM` | Highest band; served ahead of everything below it |
| `STANDARD_HIGH` | Upper standard band |
| `STANDARD_MEDIUM` | Middle standard band |
| `STANDARD_LOW` | Lower standard band |
| `NON_GUARANTEED` | Served only when no higher band fills |
| `HOUSE_ADS` | Lowest band — your own filler inventory |

> **Note:** the `status` array and `hasTraffic` in campaign reads describe recent traffic, not the
> on/off switch — `active` is the switch. `status-not-active` means switched off **or** no traffic
> in the last ~6 hours, so `active=true` with `status-not-active` is normal for an idle or
> newly created campaign; `status-finished` means the campaign's limits have ended it (end date
> passed, total or action limit reached). Traffic data is refreshed hourly.

Only `advertiserId` is required. Beyond `priority`, the settings that change how a campaign
delivers are its optimization mode — pick **one** of `ctrOptimization`, `ecpmOptimization` and
`cpaOptimization` (the last with `cpaOptimizationActions`) — `enableActions` to track
conversions, and the auto-linking pair `allowNewPlacementsAutolinking` + `autolinkCategories`
(mind the spelling, below). `labelUpdateType` decides what the `labels` you send do: `ADD`,
`OVERWRITE`, `REMOVE` or `CLEAR`.

All fields, with descriptions and an example request:
[`POST /rest-api/campaign/create.do`](https://epom.com/ad-server/docs/api/campaigns.md#post-rest-apicampaigncreatedo) and
[`POST /rest-api/campaign/{campaignId}/update.do`](https://epom.com/ad-server/docs/api/campaigns.md#post-rest-apicampaigncampaignidupdatedo).

> **Corner case:** out-of-range input is a `400` naming the field, not a silent clamp or a
> `500`. `weight` is `0`–`32767`; `exchangeRate` is `0.001`–`999.999`; `maxActionPriceOverride`
> is `0`–`9999999.9999`; `name` is never blank — a blank one is a `400` — and at most 512
> characters; `targetTemplateName` is at most 50 characters; `cpaOptimizationActions` must name
> actions that exist.

> **Corner case:** `name` is optional on create. Leave it out and the campaign is created and
> named `Campaign <id>` after the id it receives. A `name` that is sent but blank is still a `400`.

> **Warning:** the auto-link category filter is **`autolinkCategories`** — a lowercase `l`,
> repeated publisher-category IDs, on campaigns and on banners alike. The camelCase
> `autoLinkCategories` is only how a campaign reads them **back**; sent as a parameter it
> binds nothing, the call still succeeds and the name comes back in `ignoredFields`, so a
> script that spells it that way auto-links against no categories at all.

> **Note:** `onlyOneBannerPerPage` and `onlyThisCampaignOnPage` are two different
> settings, not two spellings of one — the first caps a campaign to one creative per page
> impression, the second reserves the page for that campaign. Send both if you mean both.

> **Note:** the names you **send** and the names you **read back** differ on this entity.
> `GET /rest-api/campaign/{campaignId}.do` returns auto-linking twice — as
> `allowNewPlacementsAutolinking`, the name you write, and as the older
> `newPlacementsAutoLinking` — but reads the categories back as `autoLinkCategories` while
> the parameter you write is `autolinkCategories`. Don't feed a campaign's own JSON straight
> back into `update.do`: the renamed keys are not read there.

Copy and move take options the endpoint table can't show: `copyCount` (how many copies),
`keepBannersLinked`, `dontCopyBanners`, `pauseBanners` and `preserveActive`. Only `keepBannersLinked`
applies to `MOVE`: it re-assigns the same campaign, with its id and its banners, to the target
advertiser, and the banners lose their placement links unless `keepBannersLinked=true`. The
others, and `name`, are for `COPY`. A target advertiser that is deleted is a `400`.

> **Warning:** `{operation}` is bound to an enum and is **case-sensitive** — it must be
> `COPY` or `MOVE` in capitals. Lowercase `copy` is rejected before the handler runs:
> `400 {"success":false,"message":"Invalid value 'copy' for parameter 'operation'. Expected type: Operation"}`.
> The same applies to the [banner copy/move paths](https://epom.com/ad-server/docs/api/entities-banners.md#banners-creatives).

> **Corner case:** if you omit `active` on create, the campaign inherits the network's
> **Default activity status** preference, which ships as *active*. On a network whose
> administrator has turned that preference off, the same script creates inactive campaigns. Pass `active`
> explicitly rather than relying on it — and note that the flag is dropped for callers
> without the *Manage Campaigns' Active Status* permission, after which the network default
> applies anyway.

### Campaign settings that need a permission

Campaign settings the console shows only with a role permission are applied only with that
permission enabled. Without it the setting is left as stored (on create: at its default), the
rest of the call is saved, and the parameter is listed in `ignoredFields` as `not permitted` —
whether or not it would have changed the value, so a client that echoes the whole object back
keeps working.

| Field | Permission |
|---|---|
| `weight` | *Manage Campaign Weight* |
| `priority` | *Manage Priority* |
| `ctrOptimization` | *Set "CTR Optimization"* |
| `cpaOptimization`, `cpaOptimizationActions` | *Set "CPA Optimization"* |
| `ecpmOptimization` | *Set "eCPM Optimization"* |
| `exchangeRate`, `allowImpressionAndClicksPricingUrlOverriding` | *Event Tracking Price Overriding* |
| `selfServeCampaignType` | *Manage Self-Serve Campaign Type* |
| `onlyOneBannerPerPage` | *Set "Only one banner from this campaign per page"* |
| `onlyThisCampaignOnPage`, `showBannersOfOneCampaignAtTheSamePageAlias` | *Set "Only this campaign on page"* and *Set "Only this campaign on page" Alias* |
| `campaignAliasForActionTracking` | *Set Campaign Alias For Action Tracking* |
| `allowNewPlacementsAutolinking`, `autolinkCategories` | *Auto-linking settings* |
| `allowUseForTemplate`, `targetTemplateName` | *Templates* |
| `labels`, `labelUpdateType` | *Campaign Labels* |
| `enableActions`, `allowActionPricingUrlOverriding`, `maxActionPriceOverride` | *Manage Action Tracking* |

## Related

- [Entities via API (overview)](https://epom.com/ad-server/docs/api/entities-crud.md)
- [Banners (creatives) via API](https://epom.com/ad-server/docs/api/entities-banners.md)
- [Sites, zones and placements via API](https://epom.com/ad-server/docs/api/entities-sites-zones-placements.md)
- [Linking, status, tracking codes and ad tags via API](https://epom.com/ad-server/docs/api/entities-linking-status-tags.md)
- [API overview](https://epom.com/ad-server/docs/api.md)
- [Targeting, capping and limits](https://epom.com/ad-server/docs/api/targeting-capping-limits.md)
- [Network services and miscellaneous APIs](https://epom.com/ad-server/docs/api/network-and-misc.md)