---
title: "Banners (creatives) via API"
description: "API endpoints, curl examples and corner cases for banners: every placementType and bannerType, uploading or linking the creative file, files by URL and bulk landing-URL rewrites."
type: "reference"
audience: [network-manager, admin]
keywords: [api, crud, banner, creative, bannerType, placementType, upload, multipart, files by url, imageFileUrl, html5ZipUrl, vast, native, landing url, 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.

# Banners (creatives) via API

Banners — creatives — live inside a [campaign](https://epom.com/ad-server/docs/api/entities-advertisers-campaigns.md#campaigns). This page covers the banner endpoints, the `placementType` and `bannerType` values that decide what a banner is, which parameters carry each kind of creative, how to upload the creative file or hand it over by URL, and how to rewrite landing URLs in bulk. 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 update creatives from a script, and admins. Each banner type is gated by its own role permission, and several banner settings apply only with theirs — see the corner cases below.

## Banners (creatives)

| Method | Path | Purpose |
|---|---|---|
| GET | `/rest-api/banners.do` | Paginated list (`offset`/`limit`, filters: `campaignId`, `bannerName` (part of the name, case-insensitive), `approvalStatuses`, `labels`, `active`, `advertisingCategories`, `templateIds`, `placementTypes`, `bannerTypes`, `filter[…]`; `fields`) |
| GET | `/rest-api/banners/urls.do` | Landing URL of each banner (`bannerIds`, optional `advertisingCategories`) as `id` / `type` / `url` — see [Add a macro to every landing URL](https://epom.com/ad-server/docs/guides/advertising/banners-bulk-operations.md#add-a-macro-or-parameter-to-all-landing-urls-of-an-advertiser-each-banner-keeps-its-own-url) |
| POST | `/rest-api/banners/urls.do` | Set landing URLs banner by banner: JSON body `[{"id":…,"url":"…"}]`; answers `updated` and `failures` |
| GET | `/rest-api/banner/{bannerId}.do` | Get one banner |
| GET | `/rest-api/campaign/{campaignId}/banners.do` | Banners of one campaign |
| GET | `/rest-api/campaign/banners/batch.do` | Banners for multiple campaigns |
| POST | `/rest-api/banner/create.do` | Create — `campaignId`, `bannerType` and `placementType` are required |
| POST | `/rest-api/banner/{bannerId}/update.do` | Update |
| DELETE | `/rest-api/banner/{bannerId}/delete.do` | Delete |
| POST | `/rest-api/banner/{bannerId}/{operation}/{campaignId}.do` | Copy or move to another campaign (`COPY` / `MOVE`, plus `copyCount`, `keepBannersLinked`; `COPY` takes an optional `name`, see the [campaign copy note](https://epom.com/ad-server/docs/api/entities-advertisers-campaigns.md#campaigns)) |
| POST | `/rest-api/banner/{bannerId}/{operation}/bulk.do` | Bulk copy/move to `campaignIds` |

Around them:

| Method | Path | Purpose |
|---|---|---|
| POST | `/rest-api/banners/labels.do` | Add, replace or remove labels on many banners — see [Bulk labels](https://epom.com/ad-server/docs/api/entities-linking-status-tags.md#bulk-labels) |
| GET | `/rest-api/banner/{bannerId}/video-compliance.do` | For an uploaded video banner: the facts read from its file (size, duration, bitrate, codecs, loudness…) and, with the site video-requirements permission, whether it meets each linked site's spec — see [Video banners](https://epom.com/ad-server/docs/guides/advertising/banner-video.md) |
| GET | `/rest-api/ad-units.do` | Every ad unit with its size and the placement types it applies to (`placementType` filters). With `placementType`, `width` and `height` it answers the one unit a placement of that type and size is made in — the unit of exactly that size, else the type's custom unit, else none |
| GET | `/rest-api/banner/adunit/values.do`, `/rest-api/banners/{bannerType}/adunit/values.do` | Valid ad-unit sizes |
| GET/POST | `/rest-api/banners/urls.do` | Read or batch-rewrite landing URLs — see below |
| POST | `/rest-api/banner/{bannerId}/custom/parameters.do` | Replace the banner's custom key/value parameters (JSON body) |
| GET | `/rest-api/banner/dspPartners.do` | DSP partners available for `OPENRTB_DSP` creatives |

Create an externally-hosted image banner for standard web placements:

```bash
curl -X POST "https://<your-network-domain>/rest-api/banner/create.do?$AUTH" \
  -d "campaignId=2001" \
  -d "placementType=SITE_PLACEMENT" \
  -d "bannerType=EXTERNAL_FILE" \
  -d "name=Northwind Leaderboard 728x90" \
  -d "imageBannerLink=https://cdn.northwind.example/leaderboard.png" \
  -d "adUnitId=3" \
  -d "url=https://www.northwind.example/landing" \
  -d "target=_BLANK" \
  -d "allowNewPlacementsAutoLinking=true" \
  -d "linkToPlacements=true"
```

`linkToPlacements=true` links the banner to every placement its auto-linking rules match —
the banner's own when `allowNewPlacementsAutoLinking` is on (narrowed by `autolinkCategories`
/ `autoLinkLabels`), otherwise its campaign's. With auto-linking off on both, or without the
*Link Placements to Banners* or *Auto-Linking Settings* permission, the rest of the save goes
through, nothing is linked and `linkToPlacements` is listed in `ignoredFields` with the reason.

The size comes from `adUnitId` (ids from `GET /rest-api/ad-units.do`). Without it, as
above, `adUnitWidth` + `adUnitHeight` pick the ad unit of exactly that size for the
`placementType`, or its *Custom* unit sized to them when no unit matches. The same holds on
`POST /rest-api/banner/{bannerId}/update.do`; an update that sends none of the three keeps the
stored size, and a banner stored with a width and height but no ad unit gets the unit of that
size on its next update instead of failing with `adUnitId: Required`.

All fields, with descriptions and an example request:
[`POST /rest-api/banner/create.do`](https://epom.com/ad-server/docs/api/banners.md#post-rest-apibannercreatedo) and
[`POST /rest-api/banner/{bannerId}/update.do`](https://epom.com/ad-server/docs/api/banners.md#post-rest-apibannerbanneridupdatedo).

### `placementType` — all eight values

| Value | Control-panel name |
|---|---|
| `SITE_PLACEMENT` | Site Placement |
| `NON_STANDARD_SITE_PLACEMENT` | Non-standard Placement |
| `MOBILE_SITE_PLACEMENT` | Mobile Site Placement |
| `VIDEO_PLACEMENT` | Video Placement |
| `APPLICATION_PLACEMENT` | Application Placement |
| `EMAIL_PLACEMENT` | Email Placement |
| `CLICK_THROUGH_PLACEMENT` | Click-through Placement |
| `NATIVE_PLACEMENT` | Native Placement (the label is white-label configurable) |

That is the complete enum; there is no ninth value.

### `bannerType` — all twelve values

| Value | Control-panel name | Notes |
|---|---|---|
| `LOCAL_FILE` | Local File | Uploaded image/HTML5 — see *Uploading the creative file* below |
| `EXTERNAL_FILE` | External File | Creative hosted on your own CDN (`imageBannerLink`) |
| `CODE` | HTML Code | Raw third-party tag (`code`) |
| `TEMPLATE` | Template | Requires `templateId` |
| `OPENRTB_DSP` | OpenRTB | Requires `dspPartnerId` |
| `LOCAL_NATIVE` | Local Native | Native asset set, images uploaded |
| `EXTERNAL_NATIVE` | External Native | Native asset set, images by URL |
| `LOCAL_VIDEO` | Local Video | Video placements (and e-mail) |
| `EXTERNAL_VIDEO` | External Video | Video placements (and e-mail) |
| `ADVANCED_LOCAL_VIDEOS` | Advanced Local Video(s) (Beta) | Video placements |
| `VAST_2_0_TAG_URL` | Third Party VAST/VPAID Tag URL | Video placements |
| `VPAID_FRAMEWORK` | VPAID Framework | Requires `vpaidFrameworkId` |

That is the complete enum. Each type is also gated by its own role permission, so a type
your role cannot use is rejected even though the API accepts the name.

> **Corner case:** the API enum names differ from the labels in the control panel — an
> "Image banner" you upload in the UI is `LOCAL_FILE`; one hosted on your CDN is
> `EXTERNAL_FILE`.

> **Corner case:** a banner's `weight` is 1–32767, its `name` is never blank and at most 512
> characters, and `targetTemplateName` at most 50; outside those an update is a `400` naming
> the field. `custom/parameters.do` applies to native banners (`EXTERNAL_NATIVE`,
> `LOCAL_NATIVE`) only — on any other type it is a `400` rather than parameters nothing reads.

> **Corner case:** `thirdTrackingCode[*]=<code>` sets the banner's third-party tracking code
> for every country and `thirdTrackingCode[US]=<code>` for one; an empty value removes it. The
> key is `*` or two letters, in any case — a country key is stored upper-case, `GB` as `UK`, as
> the tracking-code endpoints store it, so `thirdTrackingCode[us]` and `thirdTrackingCode[US]`
> are the same setting. Two letters is the whole check — unlike `tracking-code/banner/add.do`, the
> key is not looked up in the country list. Any other key (`thirdTrackingCode[usa]`,
> `thirdTrackingCode[1]`) is not applied and is listed in `ignoredFields` as
> `thirdTrackingCode[<key>]` with the reason; the rest of the create or update is saved. The code needs the *Banner Third-Party Tracking Code*
> permission, as the console card and `tracking-code/banner/add.do` do; without it every sent
> key is listed in `ignoredFields` as `not permitted`. External-video banners do not carry the
> code.

### Uploading the creative file

`create.do` and `update.do` also accept the creative **file itself**, as a multipart
request — so `LOCAL_*` types can be created over the API, not only in the control panel:

| Multipart field | Used by |
|---|---|
| `imageFile` | `LOCAL_FILE` image and HTML5 creatives |
| `videoFile` | `LOCAL_VIDEO` and `ADVANCED_LOCAL_VIDEOS` |
| `nativeIconFile` | `LOCAL_NATIVE` icon asset |
| `nativeImageFile` | `LOCAL_NATIVE` main image asset |
| `nativeVideoFile` | `LOCAL_NATIVE` video asset |

```bash
curl -X POST "https://<your-network-domain>/rest-api/banner/create.do?$AUTH" \
  -F "campaignId=2001" -F "placementType=SITE_PLACEMENT" \
  -F "bannerType=LOCAL_FILE" -F "name=Northwind Leaderboard 728x90" \
  -F "adUnitId=3" -F "url=https://www.northwind.example/landing" \
  -F "imageFile=@leaderboard-728x90.png"
```

> **Note:** the generated reference lists these five fields as the endpoint's
> `multipart/form-data` request body, not among its query parameters. Send them as
> multipart parts, as in the example; every other parameter can travel in the same multipart
> request or in the query string.

> **Corner case:** `bannerType` and `placementType` are not marked required in the spec,
> because of one exception, but a create without them is refused —
> `400 {"success":false,"errors":{"error":"bannerType is required parameter"}}`. The exception is a creative built from a self-serve prototype, which supplies both
> through `selfServeCampaignType`.

> **Corner case:** size comes from `adUnitId` first. Without it, `adUnitWidth` + `adUnitHeight`
> pick the unit of exactly that size (or the type's *Custom* unit). When the unit is a
> **Custom** one — chosen by id or by size — both are required and set the banner's size:
> `400 adUnitWidth and adUnitHeight are required for Custom Ad Unit`. An `adUnitId` that is not an
> ad unit, or not one offered for the banner's placement type, is a `400` naming it.

### Creating each creative type without a file upload

Every type below is created with plain form parameters — no multipart. The types the console
builds from an uploaded file take the file **by URL** instead: the server downloads it once and
stores it exactly as the upload would have been stored (see [Files by URL](#files-by-url)). The
`EXTERNAL_*` twins are different: they keep pointing at your hosted file at serve time.

| Creative | `bannerType` | `placementType` | Parameters that carry it |
|---|---|---|---|
| Image by URL | `EXTERNAL_FILE` | `SITE_PLACEMENT`, `MOBILE_SITE_PLACEMENT`, `APPLICATION_PLACEMENT`… | `imageBannerLink` (the image, hot-linked at serve time), `url` (the click), `adUnitId` or `adUnitWidth` + `adUnitHeight` |
| HTML / JavaScript | `CODE` | display types | `code`; `adUnitId` (or width + height) on site and video placements |
| VAST / VPAID tag | `VAST_2_0_TAG_URL` | `VIDEO_PLACEMENT` | `vastTagUrl` (older clients send the same value as `url`, which still works). No ad unit needed: video placements take the tag whatever its size; `adUnitWidth` + `adUnitHeight` are stored when you give them |
| Hosted video | `EXTERNAL_VIDEO` | `VIDEO_PLACEMENT` | `videoFileLink`, `url` |
| Template (rich media) | `TEMPLATE` | the template's placement type | `templateId`, then one parameter per template property, named by its key — e.g. `$$LANDING_URL$$=https://…`. List templates with `GET /rest-api/template/list.do` and a template's keys, types and required flags with `GET /rest-api/template/{id}/properties.do`. Text, URL, number, select and boolean properties need nothing else |
| HTML5 package | `TEMPLATE` | the template's placement type | `templateId` plus `html5ZipUrl` — the URL of the creative's ZIP archive, for a template with an HTML5 ZIP property (`html5ZipUrl[<property key>]` when it has several) |
| Template file (image, video) | `TEMPLATE` | the template's placement type | `templateId` plus `fileUrl` — the URL of the file for the template's FILE property (`fileUrl[<property key>]` when it has several); the file's type must be one the property allows |
| Stored image | `LOCAL_FILE` | display types | `imageFileUrl` (downloaded and stored as the banner's own file — the multipart-free `imageFile`), `url` (the click), `adUnitId` or `adUnitWidth` + `adUnitHeight` |
| Stored video | `LOCAL_VIDEO` | `VIDEO_PLACEMENT` | `videoFileUrl` (MP4 or FLV, up to the network's video size limit — the multipart-free `videoFile`), `url` |
| Native by URL | `EXTERNAL_NATIVE` | `NATIVE_PLACEMENT` | `iconUrl` / `imageUrl` / `videoUrl` (hot-linked), `title`, `description`, `callToAction`, `clickUrl` |
| Stored native | `LOCAL_NATIVE` | `NATIVE_PLACEMENT` | `nativeIconFileUrl` / `nativeImageFileUrl` / `nativeVideoFileUrl` (downloaded and stored — the multipart-free `nativeIconFile` / `nativeImageFile` / `nativeVideoFile`), `title`, `description`, `callToAction`, `clickUrl`; `iconWidth`/`iconHeight`, `imageWidth`/`imageHeight`, `videoWidth`/`videoHeight` when you may set sizes |
| DSP | `OPENRTB_DSP` | any | `dspPartnerId` (from `GET /rest-api/banner/dspPartners.do`) |

```bash
# VAST tag
curl -X POST "https://<your-network-domain>/rest-api/banner/create.do?$AUTH" \
  -d "campaignId=2001" -d "placementType=VIDEO_PLACEMENT" -d "bannerType=VAST_2_0_TAG_URL" \
  -d "name=Summer Sale pre-roll" \
  --data-urlencode "vastTagUrl=https://vast.example.net/vast?id=123"

# HTML5 creative from a hosted ZIP
curl -X POST "https://<your-network-domain>/rest-api/banner/create.do?$AUTH" \
  -d "campaignId=2001" -d "placementType=SITE_PLACEMENT" -d "bannerType=TEMPLATE" \
  -d "templateId=224" -d "name=Summer Sale HTML5 300x250" \
  --data-urlencode "html5ZipUrl=https://cdn.example.com/creatives/summer-sale-300x250.zip"

# Image stored on the ad server (not hot-linked)
curl -X POST "https://<your-network-domain>/rest-api/banner/create.do?$AUTH" \
  -d "campaignId=2001" -d "placementType=SITE_PLACEMENT" -d "bannerType=LOCAL_FILE" \
  -d "adUnitWidth=300" -d "adUnitHeight=250" -d "name=Summer Sale 300x250" \
  --data-urlencode "url=https://northwind.example.com/summer" \
  --data-urlencode "imageFileUrl=https://cdn.example.com/creatives/summer-sale-300x250.png"

# Native with a stored icon and main image
curl -X POST "https://<your-network-domain>/rest-api/banner/create.do?$AUTH" \
  -d "campaignId=2001" -d "placementType=NATIVE_PLACEMENT" -d "bannerType=LOCAL_NATIVE" \
  -d "name=Northwind app install" -d "title=Northwind Notes" -d "callToAction=Install" \
  --data-urlencode "clickUrl=https://northwind.example.com/app" \
  --data-urlencode "nativeIconFileUrl=https://cdn.example.com/creatives/app-icon-128.png" \
  --data-urlencode "nativeImageFileUrl=https://cdn.example.com/creatives/hero-1200x627.jpg"
```

> **Corner case:** an `EXTERNAL_VIDEO` banner's `videoFileLink` is read when the banner is saved:
> the host must answer with a video content type, and the video's facts — the ones the banner's
> *Video info* shows — are taken from the file. An `update.do` that keeps the link of a banner that already
> is an External Video, with those facts stored, does not read it again, so an unrelated update
> does not depend on the video's host being up. A new link, a change of banner type, a banner
> with no stored facts or `refreshHostedFiles=true` reads the link again, and a link that cannot
> be read is refused with *Cannot get video by link*.

#### Files by URL

| Parameter | Banner type | Stands in for the upload | Must be |
|---|---|---|---|
| `imageFileUrl` | `LOCAL_FILE` | `imageFile` | an image (GIF, JPEG, PNG, SVG) within the network's image size limit for the ad unit |
| `videoFileUrl` | `LOCAL_VIDEO` | `videoFile` | a video (MP4, FLV) within the network's video size limit (20 MB by default) |
| `nativeIconFileUrl` / `nativeImageFileUrl` | `LOCAL_NATIVE` | `nativeIconFile` / `nativeImageFile` | GIF, JPEG, PNG or SVG; an animated GIF must match the icon/image size |
| `nativeVideoFileUrl` | `LOCAL_NATIVE` | `nativeVideoFile` | MP4, at least `videoWidth` × `videoHeight` in the same orientation |
| `html5ZipUrl`, `html5ZipUrl[<key>]` | `TEMPLATE` | the HTML5 ZIP property's upload | a ZIP of at most 10 MB that unpacks within the [archive limits](https://epom.com/ad-server/docs/guides/advertising/html5-zip-creatives.md#archive-limits) |
| `fileUrl`, `fileUrl[<key>]` | `TEMPLATE` | the FILE property's upload | a content type the property allows |

Each file is downloaded once, when you create or update the banner, and then kept exactly as
the uploaded file would be — the same type, size and dimension checks, the same SVG sanitising,
the same storage and CDN — so the URL does not need to stay up afterwards. The type is read from
the file's own bytes, not from the server's `Content-Type` (the URL's file name only settles bytes
that could be several things), and the stored file gets
the extension its content really has (an image named `banner.png` that is a JPEG is stored as
`banner.jpg`). The download is guarded: only `http` and `https`, only hosts that resolve to
public internet addresses (private, loopback, link-local and similar ranges are refused,
redirects included), a 10-second connect/stall timeout, 30 seconds in all and at most 3
redirects. The size cap is per kind: a video may be as large as the network's video size limit
and never more than 100 MB; a template `fileUrl` file the larger of 10 MB and that limit (100 MB
at most); an HTML5 ZIP 10 MB; an image the console's size limit for the ad unit.

On `POST /rest-api/banner/{bannerId}/update.do` the same parameters replace the stored file.
`imageFileUrl` replaces the image without `deleteImage` (the console's delete-then-upload in one
step); the old file is removed after the save.

A refused file is a `400` whose `errors` names the parameter you sent — e.g.
`{"success":false,"errors":{"imageFileUrl":"https://… is not an image: its content is text/html."}}`.
The reasons: not an `http`/`https` URL, not a public host, larger than the limit, an HTTP error,
unreachable or too slow, not the kind of file the parameter takes, a URL on a banner type it does
not apply to (`imageFileUrl applies to LOCAL_FILE banners only.`), the URL together with an upload
of the same file, or a template property the template does not have. A check the upload path
itself makes (an image over the size limit, a GIF of the wrong size) is reported under the URL
parameter too. A template file of a type the property does not allow is reported under the
property's key, as for an upload.

A placement's native adapter template takes its FILE properties the same way:
`fileUrl` / `fileUrl[<property key>]` next to `nativeAdapterTemplateId` on
`POST /rest-api/placements/update/*.do`.

> **Corner case:** a VAST banner created in the console stores no size at all. Over the API it
> now does the same unless you pass a size — earlier API-created VAST banners report
> `width`/`height` 0.

> **Corner case:** native banners carry their assets and click in fields of their own (the
> *Native* rows of the table above) instead of `imageBannerLink` and `url`. The
> `iconWidth`/`iconHeight`, `imageWidth`/`imageHeight` and `videoWidth`/`videoHeight` pairs are
> silently discarded for roles without the *Native Banner Sizes* permission.

### Rewriting landing URLs in bulk

`GET /rest-api/banners/urls.do` returns the landing URL of every banner you can reach,
filterable by `bannerIds` and `advertisingCategories`. The POST on the same path takes a
**JSON body** — an array of `{id, url}` objects — and validates each URL before saving:

```bash
curl -X POST "https://<your-network-domain>/rest-api/banners/urls.do?$AUTH" \
  -H "Content-Type: application/json" \
  -d '[{"id":5001,"url":"https://www.northwind.example/landing?cid=$$CAMPAIGN_ID$$"}]'
```

> **Warning:** this is the one endpoint on this page that takes JSON rather than form
> parameters. Sending it form-encoded produces
> `400 {"success":false,"message":"Request body is missing or not readable"}`. The
> response reports per-banner errors, so a partial success is normal — read it, don't
> assume every id in your array was written.

> **Corner case:** `enableViewTracking` needs *Banner View Tracking*;
> `allowNewPlacementsAutoLinking` and `autolinkCategories` need *Auto-linking settings*, and
> `autoLinkLabels` needs it plus *Placement Labels*. Without the permission the setting is left
> as stored, the rest of the create or update is saved, and the parameter is listed in
> `ignoredFields` as `not permitted`.

> **Corner case:** a parameter that does not suit the banner's type is not stored and comes back
> in `ignoredFields` with the reason *does not apply to a `<bannerType>` banner on a `<placementType>`*:
> the DSP settings (`dspPartnerId`, `usePlacementSize`, `always2ndPrice`,
> `advertisingNetworkParameters[…]`) on anything but `OPENRTB_DSP`, `vastTagUrl` and the
> `vast40Wrapper*` flags on anything but `VAST_2_0_TAG_URL`, `imageBannerLink` on anything but
> `EXTERNAL_FILE`, `customParameters` on a non-native banner, `clickUrl` on a banner that is neither native nor on a
> native placement, `title` on a type that has none, `returnAsIframe` off a video placement, `thirdTrackingCode[…]` on `EXTERNAL_VIDEO`
> and `directFileDownload` off an Android application banner. The rest of the save goes through.

## Related

- [Entities via API (overview)](https://epom.com/ad-server/docs/api/entities-crud.md)
- [Advertisers and campaigns via API](https://epom.com/ad-server/docs/api/entities-advertisers-campaigns.md)
- [Linking, status, tracking codes and ad tags via API](https://epom.com/ad-server/docs/api/entities-linking-status-tags.md)
- [Sites, zones and placements via API](https://epom.com/ad-server/docs/api/entities-sites-zones-placements.md)
- [API overview](https://epom.com/ad-server/docs/api.md)
- [Banner types](https://epom.com/ad-server/docs/reference/banner-types.md)
- [Placement types](https://epom.com/ad-server/docs/reference/placement-types.md)
- [Bulk banner operations](https://epom.com/ad-server/docs/guides/advertising/banners-bulk-operations.md)
- [Serve an HTML5 creative from a ZIP bundle](https://epom.com/ad-server/docs/guides/advertising/html5-zip-creatives.md)
- [Video banners](https://epom.com/ad-server/docs/guides/advertising/banner-video.md)