Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
272 changes: 272 additions & 0 deletions ads/concepts/templates.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
---
sidebar_position: 3
sidebar_label: Templates
---

# Templates

import RebrandingNotice from '../callouts/_rebranding_notice.md';

<RebrandingNotice />

A template is a reusable break preset for OptiView Ads. It stores a break payload once so you can schedule consistent breaks quickly, either manually from the dashboard and API or automatically through marker rules.

Templates are scoped to an organization. API calls identify the organization with the `X-Org-ID` header and authenticate with an API key and secret using HTTP Basic authentication.

## Dashboard path

In the OptiView Unified Dashboard, templates are available in two places:

| Path | Use it for |
| ------------------------------------------------------ | ----------------------------------------------------- |
| `/{organizationId}/ads/templates` | Manage every template in the organization. |
| `/{organizationId}/ads/channels/{channelId}/templates` | Manage the templates surfaced for a specific channel. |

Both lists expose **New**, **Edit**, and **Delete** actions, plus a **Schedule now** action that immediately schedules a break on the channel from the selected template.

## Template identity

Every template has a customer-facing `id`. The API stores it together with the organization ID, so the unique identity is:

```text
organizationId + templateId
```

Use stable template IDs that match your operational names, such as `midroll-30s` or `sponsor-lshape`. If you omit `id` on creation, the API generates one.

## What a template contains

A template holds the same payload as a break's `data`, so anything you can express on a break you can preset on a template:

- `variant` — one variant, or a list of variants with device `targeting`, using the same variant formats (`single`, `double`, `lshape_ad`, `lshape_content`, `overlay`) and typed assets as a break.
- `resumeOffset` and `controls` (skip offset, snapback) — optional playback behaviour.
- `duration` — optional on a template (it is required on a break). When set, it is copied onto breaks scheduled from the template.

The **Breaks** section is the canonical reference for variant formats, layouts, typed assets, and device targeting. This section cross-links there instead of repeating those details.

Templates can also record associations that make them easier to organize and surface:

| Field | Relationship |
| ------------ | ------------------------------------------------------------------------------------------ |
| `channelIds` | Channels the template is associated with (for example, in the per-channel dashboard list). |
| `eventIds` | **Events** the template is associated with. |

## Snapshot semantics

A template is a preset, not a live link. When a break is scheduled from a template:

1. The template's payload is **copied onto the new break** at creation.
2. The break records the source `templateId` as provenance.
3. There is **no synchronization afterwards**. Editing or deleting the template later does not change breaks that were already created from it — they keep their copied payload.

Templates are **hard-deleted**. Deleting a template removes it permanently; there is no soft-delete or archival state. Breaks previously created from the template are unaffected and still report their historical `templateId`, but that `templateId` no longer resolves to a template, and listing breaks by a deleted template returns a not-found error.

## Scheduling a break from a template

You can schedule a break from a template in three ways:

- **Dashboard** — use the **Schedule now** action on a template in either template list to create a break on the channel immediately.
- **API** — create a break on a channel and reference the template with `templateId` (see [Schedule a break from a template](#schedule-a-break-from-a-template) below).
- **Marker rules** — each marker rule targets a template through its `templateId`. When automatic detection matches a marker, the worker schedules a break from that template. See the **Marker Detection** section for how rules are configured and evaluated.

In every case the template payload is snapshotted onto the resulting break, as described in [Snapshot semantics](#snapshot-semantics).

## Configuration reference

| Field | Type | Default | Description |
| -------------- | -------------------- | --------- | ----------------------------------------------------------------------------------- |
| `id` | string | generated | Customer-facing template ID, unique within the organization. |
| `name` | string | none | Human-readable label shown in the dashboard. |
| `channelIds` | string[] | none | Channels the template is associated with. |
| `eventIds` | string[] | none | Events the template is associated with. |
| `duration` | integer | none | Optional break duration in seconds, copied onto breaks scheduled from the template. |
| `variant` | variant or variant[] | Required | Break variant(s). See the **Breaks** section for formats, assets, and targeting. |
| `resumeOffset` | integer | none | Optional resume offset applied to breaks scheduled from the template. |
| `controls` | object | none | Optional playback controls: `skipOffset` and `snapback`. |

## Create a template

Dashboard: **Ads → Templates → New**.

API:

```bash
curl -X POST 'https://ads.example.com/api/v1/templates' \
-u "$ADS_API_KEY:$ADS_API_SECRET" \
-H 'Content-Type: application/json' \
-H 'X-Org-ID: org_123' \
-d '{
"id": "midroll-30s",
"name": "Mid-roll 30s",
"channelIds": ["sports-main"],
"duration": 30,
"variant": {
"format": "single",
"assets": [
{
"type": "vast",
"mediaType": "video",
"uri": "https://ads.example.com/vast/midroll.xml"
}
]
}
}'
```

Example response:

```json
{
"id": "midroll-30s",
"name": "Mid-roll 30s",
"channelIds": ["sports-main"],
"duration": 30,
"variant": {
"format": "single",
"assets": [
{
"type": "vast",
"mediaType": "video",
"uri": "https://ads.example.com/vast/midroll.xml"
}
]
},
"createdAt": "2026-07-16T12:00:00.000Z"
}
```

## Get a template

```bash
curl 'https://ads.example.com/api/v1/templates/midroll-30s' \
-u "$ADS_API_KEY:$ADS_API_SECRET" \
-H 'X-Org-ID: org_123'
```

## Update a template

```bash
curl -X PATCH 'https://ads.example.com/api/v1/templates/midroll-30s' \
-u "$ADS_API_KEY:$ADS_API_SECRET" \
-H 'Content-Type: application/json' \
-H 'X-Org-ID: org_123' \
-d '{
"name": "Mid-roll 30s (VAST)",
"duration": 30
}'
```

Updating a template does not change breaks already scheduled from it — see [Snapshot semantics](#snapshot-semantics).

## List templates

```bash
curl 'https://ads.example.com/api/v1/templates?page=1&pageSize=20&sort=-createdAt' \
-u "$ADS_API_KEY:$ADS_API_SECRET" \
-H 'X-Org-ID: org_123'
```

List endpoints use the same pagination shape as the rest of the API. Templates can be sorted by `name`, `duration`, or `createdAt`.

| Query parameter | Default | Description |
| --------------- | ------------ | -------------------------------------------------------------------------- |
| `page` | `1` | Page number. |
| `pageSize` | `20` | Items per page. Maximum `100`. |
| `filter` | none | Optional RSQL filter expression. |
| `sort` | `-createdAt` | Comma-separated sort fields. Prefix a field with `-` for descending order. |

Templates maintain denormalized fields derived from their payload so you can filter without inspecting the full `variant`. The `filter` expression accepts these selectors:

| Filter selector | Matches on | Operators |
| --------------- | --------------------------------------- | ------------------------------------------ |
| `name` | Template name | `==`, `!=`, `=like=`, `=in=` |
| `duration` | Template duration | `==`, `!=`, `=gt=`, `=ge=`, `=lt=`, `=le=` |
| `format` | Variant formats present on the template | `==`, `!=`, `=like=`, `=in=` |
| `assetType` | Asset types present on the template | `==`, `!=`, `=like=`, `=in=` |
| `vendor` | Vendors present on the template | `==`, `!=`, `=like=`, `=in=` |

Examples:

```bash
# Overlay templates only
curl 'https://ads.example.com/api/v1/templates?filter=format==overlay' \
-u "$ADS_API_KEY:$ADS_API_SECRET" \
-H 'X-Org-ID: org_123'
```

```bash
# Short VAST templates (30s or less), sorted by duration
curl 'https://ads.example.com/api/v1/templates?filter=duration=le=30;assetType==vast&sort=duration' \
-u "$ADS_API_KEY:$ADS_API_SECRET" \
-H 'X-Org-ID: org_123'
```

```bash
# Templates that use a vendor asset (for example, Google Ad Manager pods)
curl 'https://ads.example.com/api/v1/templates?filter=vendor==gam' \
-u "$ADS_API_KEY:$ADS_API_SECRET" \
-H 'X-Org-ID: org_123'
```

Combine multiple conditions with `;`.

## Delete a template

```bash
curl -X DELETE 'https://ads.example.com/api/v1/templates/midroll-30s' \
-u "$ADS_API_KEY:$ADS_API_SECRET" \
-H 'X-Org-ID: org_123'
```

Delete multiple templates in one request:

```bash
curl -X DELETE 'https://ads.example.com/api/v1/templates' \
-u "$ADS_API_KEY:$ADS_API_SECRET" \
-H 'Content-Type: application/json' \
-H 'X-Org-ID: org_123' \
-d '{ "ids": ["midroll-30s", "sponsor-lshape"] }'
```

Deletes are permanent (hard delete). Existing breaks scheduled from the template are not affected — see [Snapshot semantics](#snapshot-semantics).

## Schedule a break from a template

Create a break on a channel and reference the template with `templateId`. The template payload is snapshotted onto the break at creation.

```bash
curl -X POST 'https://ads.example.com/api/v1/channels/sports-main/breaks' \
-u "$ADS_API_KEY:$ADS_API_SECRET" \
-H 'Content-Type: application/json' \
-H 'X-Org-ID: org_123' \
-d '{
"templateId": "midroll-30s",
"start": "2026-07-16T13:00:00.000Z"
}'
```

`templateId` is the only required field. You can override the snapshotted payload per break with optional fields — `start`, `duration`, `variant`, `assetParameters`, `eventId`, and `id`. Start semantics depend on the channel timebase; see the **Channels** and **Breaks** sections for scheduling and lifecycle details.

The created break records the source `templateId` alongside its own copied payload:

```json
{
"id": "b_9f2c",
"channelId": "sports-main",
"templateId": "midroll-30s",
"status": "PREPARING",
"start": "2026-07-16T13:00:00.000Z",
"duration": 30,
"variant": {
"format": "single",
"assets": [
{
"type": "vast",
"mediaType": "video",
"uri": "https://ads.example.com/vast/midroll.xml"
}
]
},
"createdAt": "2026-07-16T12:30:00.000Z"
}
```
2 changes: 1 addition & 1 deletion sidebarsAds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const sidebars: SidebarsConfig = {
customProps: {
icon: '📚',
},
items: ['concepts/channels', 'concepts/breaks'],
items: ['concepts/channels', 'concepts/breaks', 'concepts/templates'],
},
{
type: 'category',
Expand Down
Loading