From d6e2d79e63bf54cd937102f6fd25d22511e5e385 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 14:19:57 +0000 Subject: [PATCH] ADS-116 document ad templates Co-Authored-By: maarten.rimaux --- ads/concepts/templates.mdx | 272 +++++++++++++++++++++++++++++++++++++ sidebarsAds.ts | 2 +- 2 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 ads/concepts/templates.mdx diff --git a/ads/concepts/templates.mdx b/ads/concepts/templates.mdx new file mode 100644 index 000000000000..b1e2fea2538d --- /dev/null +++ b/ads/concepts/templates.mdx @@ -0,0 +1,272 @@ +--- +sidebar_position: 3 +sidebar_label: Templates +--- + +# Templates + +import RebrandingNotice from '../callouts/_rebranding_notice.md'; + + + +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" +} +``` diff --git a/sidebarsAds.ts b/sidebarsAds.ts index 5317c4cb7f47..2694763bc301 100644 --- a/sidebarsAds.ts +++ b/sidebarsAds.ts @@ -12,7 +12,7 @@ const sidebars: SidebarsConfig = { customProps: { icon: '📚', }, - items: ['concepts/channels', 'concepts/breaks'], + items: ['concepts/channels', 'concepts/breaks', 'concepts/templates'], }, { type: 'category',