From fb7158b3ffc4291672208295858ea6256618e38b Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Wed, 8 Oct 2025 13:58:42 -0400 Subject: [PATCH 1/4] feat: add brand card and promoted products schemas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements standardized brand information manifest and flexible product selection to support both SMB and enterprise advertising workflows. ## Brand Card Schema - Minimal entry: just URL for SMB use cases - Explicit asset array with tags for discovery - Product catalog integration (Google Merchant Center format) - Supports logos, colors, fonts, tone, disclaimers - Cacheable via standard HTTP headers ## Promoted Products Schema - Multiple selection methods (combinable): - Direct SKU references - Tag-based filtering - Category selection - Natural language queries - Inline offerings for non-commerce campaigns ## Integration - Updated build_creative with brand_card, promoted_products, asset_filters - Updated create_media_buy with brand_card, promoted_products - Comprehensive documentation and examples ## Design Principles - Low friction: URL-only minimum enables AI inference - Asset tagging: "Give me holiday variants of my brand assets" - Product-level context: Optional message field for product-specific details - Non-commerce support: Brand awareness, events, services without SKUs Addresses feedback from Streamr, Connected Stories, and enterprise needs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- docs/creative-protocol/getting-started.md | 38 ++ .../task-reference/build_creative.md | 41 +- .../task-reference/create_media_buy.md | 1 + docs/reference/brand-card.md | 364 ++++++++++++++++++ static/schemas/v1/core/brand-card.json | 354 +++++++++++++++++ static/schemas/v1/core/promoted-products.json | 158 ++++++++ static/schemas/v1/index.json | 8 + .../v1/media-buy/build-creative-request.json | 39 +- .../media-buy/create-media-buy-request.json | 8 + 9 files changed, 1008 insertions(+), 3 deletions(-) create mode 100644 docs/reference/brand-card.md create mode 100644 static/schemas/v1/core/brand-card.json create mode 100644 static/schemas/v1/core/promoted-products.json diff --git a/docs/creative-protocol/getting-started.md b/docs/creative-protocol/getting-started.md index 7b2a912548..b0e862c08b 100644 --- a/docs/creative-protocol/getting-started.md +++ b/docs/creative-protocol/getting-started.md @@ -76,6 +76,41 @@ Use the `context_id` to make improvements: ## Common Patterns +### Using Brand Cards + +Provide brand context for better creative generation: + +```json +{ + "message": "Create a display ad for our coffee shop promotion", + "format_id": "display_300x250", + "brand_card": { + "url": "https://mycoffeeshop.com", + "name": "Brew & Co", + "colors": { + "primary": "#6F4E37", + "secondary": "#C4A35A" + }, + "tone": "warm and inviting" + }, + "output_mode": "manifest" +} +``` + +**Minimal Brand Card**: Start with just a URL for low-friction creative generation: + +```json +{ + "message": "Create a coffee shop ad", + "format_id": "display_native", + "brand_card": { + "url": "https://mycoffeeshop.com" + } +} +``` + +See [Brand Card Reference](../reference/brand-card) for comprehensive examples. + ### Using Your Own Assets Provide existing assets to incorporate into the creative: @@ -84,6 +119,9 @@ Provide existing assets to incorporate into the creative: { "message": "Create a display ad featuring our signature latte", "format_id": "display_300x250", + "brand_card": { + "url": "https://mycoffeeshop.com" + }, "assets": [ { "asset_id": "brand_logo", diff --git a/docs/creative-protocol/task-reference/build_creative.md b/docs/creative-protocol/task-reference/build_creative.md index 2819e11354..5706e77cb3 100644 --- a/docs/creative-protocol/task-reference/build_creative.md +++ b/docs/creative-protocol/task-reference/build_creative.md @@ -41,6 +41,7 @@ Creative agents need to understand format requirements to generate appropriate c | `format_source` | string | No | Source URL for format lookup (sales agent URL). If null/omitted, assumes standard AdCP format | | `format_id` | string | Yes | Format identifier to look up from the format source | | `context_id` | string | No | Session context from previous message for continuity | +| `brand_card` | BrandCard | No | Brand information manifest for creative generation context. See [Brand Card](../../reference/brand-card) for details. Replaces legacy `brand_guidelines`. | | `assets` | array | No | References to asset libraries and specific assets | | `output_mode` | string | No | `"manifest"` for creative manifest or `"code"` for executable (default: `"manifest"`) | | `preview_options` | object | No | Options for generating preview | @@ -174,14 +175,50 @@ Creative agents need to understand format requirements to generate appropriate c ## Examples -### Example 1: Building a Native Ad (Manifest Mode) +### Example 1: Building a Native Ad with Brand Card (Manifest Mode) -#### Initial Request +#### Initial Request with Brand Card +```json +{ + "message": "Create a native ad for Yahoo promoting Purina Pro Plan. Focus on the veterinarian recommendation and that real salmon is the #1 ingredient.", + "format_id": "display_native", + "output_mode": "manifest", + "brand_card": { + "url": "https://purina.com", + "name": "Purina Pro Plan", + "logos": [ + { + "url": "https://cdn.purina.com/logos/proplan-square.png", + "tags": ["square", "dark"], + "width": 512, + "height": 512 + } + ], + "colors": { + "primary": "#E31837", + "secondary": "#003DA5", + "background": "#FFFFFF" + }, + "tone": "informative and trustworthy" + }, + "assets": [ + { + "library_id": "purina_assets", + "tags": ["product_shots", "salmon_formula"] + } + ] +} +``` + +#### Simple Request (Minimal Brand Card) ```json { "message": "Create a native ad for Yahoo promoting Purina Pro Plan. Focus on the veterinarian recommendation and that real salmon is the #1 ingredient. Use an informative and trustworthy tone with 'Learn More' as the CTA.", "format_id": "display_native", "output_mode": "manifest", + "brand_card": { + "url": "https://purina.com" + }, "assets": [ { "library_id": "purina_assets", diff --git a/docs/media-buy/task-reference/create_media_buy.md b/docs/media-buy/task-reference/create_media_buy.md index 110c6f360a..a833dd75d2 100644 --- a/docs/media-buy/task-reference/create_media_buy.md +++ b/docs/media-buy/task-reference/create_media_buy.md @@ -22,6 +22,7 @@ Create a media buy from selected packages. This task handles the complete workfl | `buyer_ref` | string | Yes | Buyer's reference identifier for this media buy | | `packages` | Package[] | Yes | Array of package configurations (see Package Object below) | | `promoted_offering` | string | Yes | Description of advertiser and what is being promoted | +| `brand_card` | BrandCard | No | Optional brand information manifest for creative generation and campaign context. Can be cached and reused across multiple requests. See [Brand Card](../../reference/brand-card) for details. | | `po_number` | string | No | Purchase order number for tracking | | `start_time` | string | Yes | Campaign start date/time in ISO 8601 format (UTC unless timezone specified) | | `end_time` | string | Yes | Campaign end date/time in ISO 8601 format (UTC unless timezone specified) | diff --git a/docs/reference/brand-card.md b/docs/reference/brand-card.md new file mode 100644 index 0000000000..610653ec98 --- /dev/null +++ b/docs/reference/brand-card.md @@ -0,0 +1,364 @@ +--- +title: Brand Card +description: Standardized brand information manifest for creative generation and media buying +keywords: [brand card, brand manifest, creative generation, brand guidelines] +--- + +# Brand Card + +The **Brand Card** is a standardized manifest format for sharing brand information across AdCP workflows. It enables low-friction creative generation by providing brand context that can be easily cached and reused across multiple requests. + +## Overview + +Brand cards solve a key problem identified in creative agent workflows: how to efficiently provide brand context without requiring complex authorization flows or repeated data entry. The format supports both simple use cases (just a URL) and enterprise scenarios (comprehensive brand assets and guidelines). + +### Key Benefits + +- **Minimal Friction**: Start with just a URL, expand as needed +- **Cacheable**: Same brand card can be reused across requests +- **Standardized**: Consistent format across all AdCP implementations +- **Flexible**: Supports SMB to enterprise use cases +- **AI-Optimized**: Structured for easy ingestion by creative agents + +## Use Cases + +### SMB / Ad Hoc Creative Generation + +For small businesses or one-off campaigns, a minimal brand card provides enough context: + +```json +{ + "url": "https://bobsfunburgers.com" +} +``` + +Creative agents can infer brand information from the URL, pulling logos, colors, and style from the website. + +### Enterprise / Established Brand + +For established brands with defined guidelines, the brand card provides comprehensive context: + +```json +{ + "url": "https://acmecorp.com", + "name": "ACME Corporation", + "logos": [ + { + "url": "https://cdn.acmecorp.com/logo-square-dark.png", + "tags": ["dark", "square"], + "width": 512, + "height": 512 + }, + { + "url": "https://cdn.acmecorp.com/logo-horizontal-light.png", + "tags": ["light", "horizontal"], + "width": 1200, + "height": 400 + } + ], + "colors": { + "primary": "#FF6B35", + "secondary": "#004E89", + "accent": "#F7931E", + "background": "#FFFFFF", + "text": "#1A1A1A" + }, + "fonts": { + "primary": "Helvetica Neue", + "secondary": "Georgia" + }, + "tone": "professional and trustworthy", + "tagline": "Innovation You Can Trust", + "product_feed": "https://acmecorp.com/products.rss", + "industry": "technology", + "target_audience": "business decision-makers aged 35-55" +} +``` + +### Multi-SKU Retailer + +Large retailers can provide product feeds and asset libraries: + +```json +{ + "url": "https://bigretail.com", + "name": "BigRetail", + "product_feed": "https://bigretail.com/catalog.json", + "asset_library": { + "images": "https://assets.bigretail.com/api/images", + "videos": "https://assets.bigretail.com/api/videos" + }, + "disclaimers": [ + { + "text": "Prices and availability subject to change", + "context": "pricing", + "required": true + } + ] +} +``` + +## Brand Card Schema + +**Schema URL**: [/schemas/v1/core/brand-card.json](/schemas/v1/core/brand-card.json) + +### Required Fields + +| Field | Type | Description | +|-------|------|-------------| +| `url` | string (uri) | Primary brand URL for context and asset discovery | + +### Optional Fields + +| Field | Type | Description | +|-------|------|-------------| +| `name` | string | Brand or business name | +| `logos` | Logo[] | Brand logo assets with semantic tags | +| `colors` | Colors | Brand color palette (hex format) | +| `fonts` | Fonts | Brand typography guidelines | +| `tone` | string | Brand voice and messaging tone | +| `tagline` | string | Brand tagline or slogan | +| `product_feed` | string (uri) | URL to product catalog feed | +| `asset_library` | AssetLibrary | References to brand asset libraries | +| `disclaimers` | Disclaimer[] | Legal disclaimers for creatives | +| `industry` | string | Industry or vertical | +| `target_audience` | string | Primary target audience description | +| `contact` | Contact | Brand contact information | +| `metadata` | Metadata | Version and update tracking | + +### Logo Object + +```typescript +{ + url: string; // URL to logo asset + tags?: string[]; // Semantic tags (e.g., "dark", "light", "square", "horizontal") + width?: number; // Logo width in pixels + height?: number; // Logo height in pixels +} +``` + +**Common Tags**: `"dark"`, `"light"`, `"square"`, `"horizontal"`, `"vertical"`, `"icon"`, `"wordmark"`, `"lockup"` + +### Colors Object + +```typescript +{ + primary?: string; // Primary brand color (#RRGGBB) + secondary?: string; // Secondary brand color (#RRGGBB) + accent?: string; // Accent color (#RRGGBB) + background?: string; // Background color (#RRGGBB) + text?: string; // Text color (#RRGGBB) +} +``` + +### Fonts Object + +```typescript +{ + primary?: string; // Primary font family name + secondary?: string; // Secondary font family name + font_urls?: string[]; // URLs to web font files +} +``` + +### Disclaimer Object + +```typescript +{ + text: string; // Disclaimer text + context?: string; // When this applies (e.g., "financial_products", "health_claims") + required?: boolean; // Whether this must appear (default: true) +} +``` + +### Asset Library Object + +```typescript +{ + images?: string; // URL to image asset library or API + videos?: string; // URL to video asset library or API + templates?: string; // URL to creative templates library +} +``` + +## Integration with AdCP Tasks + +### create_media_buy + +Include brand card in media buy creation to provide context for creative generation: + +```json +{ + "buyer_ref": "campaign_2024_q1", + "promoted_offering": "ACME Pro Widget", + "brand_card": { + "url": "https://acmecorp.com", + "name": "ACME Corporation", + "tone": "professional and innovative" + }, + "packages": [...], + "budget": {...} +} +``` + +### build_creative + +Use brand card to inform creative generation: + +```json +{ + "message": "Create a native ad highlighting our new product launch", + "format_id": "display_native", + "brand_card": { + "url": "https://acmecorp.com", + "logos": [ + { + "url": "https://cdn.acmecorp.com/logo-square.png", + "tags": ["square", "dark"] + } + ], + "colors": { + "primary": "#FF6B35", + "secondary": "#004E89" + }, + "tone": "professional and trustworthy" + } +} +``` + +## Best Practices + +### 1. Start Simple, Expand as Needed + +Begin with just a URL. Add more fields only when the URL-based inference isn't sufficient: + +```json +// ✅ Good starting point +{ + "url": "https://mybrand.com" +} + +// ✅ Add details when needed +{ + "url": "https://mybrand.com", + "logos": [...], + "colors": {...} +} +``` + +### 2. Use Semantic Tags for Logos + +Tags help creative agents select appropriate logo variants: + +```json +{ + "logos": [ + {"url": "...", "tags": ["dark", "square"]}, // For light backgrounds + {"url": "...", "tags": ["light", "square"]}, // For dark backgrounds + {"url": "...", "tags": ["dark", "horizontal"]}, // Wide layouts + {"url": "...", "tags": ["icon"]} // Small placements + ] +} +``` + +### 3. Cache and Reuse Brand Cards + +Brand cards are designed to be cached: + +```javascript +// Cache brand card once +const brandCard = { + url: "https://acmecorp.com", + colors: {...}, + logos: [...] +}; + +// Reuse across requests +await createMediaBuy({ brand_card: brandCard, ... }); +await buildCreative({ brand_card: brandCard, ... }); +await buildCreative({ brand_card: brandCard, ... }); // Same card, different creative +``` + +### 4. Product Feeds for Multi-SKU + +Large retailers should provide product feeds: + +```json +{ + "url": "https://retailer.com", + "product_feed": "https://retailer.com/products.json" +} +``` + +**Supported Feed Formats**: RSS, JSON Feed, Product CSV + +### 5. Asset Libraries for Enterprise + +Enterprise brands with large asset libraries should provide API endpoints: + +```json +{ + "asset_library": { + "images": "https://assets.brand.com/api/images", + "videos": "https://assets.brand.com/api/videos" + } +} +``` + +## Evolution and Versioning + +Brand cards are versioned using the `metadata.version` field: + +```json +{ + "url": "https://brand.com", + "metadata": { + "version": "2.1", + "updated_date": "2024-03-15T10:00:00Z" + } +} +``` + +Version updates: +- **Patch** (2.0.1): Fix typos, update contact info +- **Minor** (2.1.0): Add new assets, update colors +- **Major** (3.0.0): Complete rebrand, new identity + +## Migration from brand_guidelines + +For implementations using the legacy `brand_guidelines` field in `build_creative`: + +**Before (Legacy)**: +```json +{ + "brand_guidelines": { + "colors": ["#FF6B35", "#004E89"], + "fonts": ["Helvetica Neue"], + "tone": "professional" + } +} +``` + +**After (Brand Card)**: +```json +{ + "brand_card": { + "url": "https://brand.com", + "colors": { + "primary": "#FF6B35", + "secondary": "#004E89" + }, + "fonts": { + "primary": "Helvetica Neue" + }, + "tone": "professional" + } +} +``` + +## Related Documentation + +- **[create_media_buy](../media-buy/task-reference/create_media_buy)** - Media buy creation with brand context +- **[build_creative](../creative-protocol/task-reference/build_creative)** - AI-powered creative generation +- **[Creative Lifecycle](../media-buy/creatives/)** - Managing creative assets +- **[Data Models](./data-models)** - Core AdCP data structures diff --git a/static/schemas/v1/core/brand-card.json b/static/schemas/v1/core/brand-card.json new file mode 100644 index 0000000000..6349785343 --- /dev/null +++ b/static/schemas/v1/core/brand-card.json @@ -0,0 +1,354 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/v1/core/brand-card.json", + "title": "Brand Card", + "description": "Standardized brand information manifest for creative generation and media buying. Enables low-friction creative workflows by providing brand context that can be easily cached and shared across requests.", + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." + }, + "name": { + "type": "string", + "description": "Brand or business name" + }, + "logos": { + "type": "array", + "description": "Brand logo assets with semantic tags for different use cases", + "items": { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "URL to the logo asset" + }, + "tags": { + "type": "array", + "description": "Semantic tags describing the logo variant (e.g., 'dark', 'light', 'square', 'horizontal', 'icon')", + "items": { + "type": "string" + } + }, + "width": { + "type": "integer", + "description": "Logo width in pixels" + }, + "height": { + "type": "integer", + "description": "Logo height in pixels" + } + }, + "required": ["url"] + } + }, + "colors": { + "type": "object", + "description": "Brand color palette", + "properties": { + "primary": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$", + "description": "Primary brand color (hex format)" + }, + "secondary": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$", + "description": "Secondary brand color (hex format)" + }, + "accent": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$", + "description": "Accent color (hex format)" + }, + "background": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$", + "description": "Background color (hex format)" + }, + "text": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$", + "description": "Text color (hex format)" + } + } + }, + "fonts": { + "type": "object", + "description": "Brand typography guidelines", + "properties": { + "primary": { + "type": "string", + "description": "Primary font family name" + }, + "secondary": { + "type": "string", + "description": "Secondary font family name" + }, + "font_urls": { + "type": "array", + "description": "URLs to web font files if using custom fonts", + "items": { + "type": "string", + "format": "uri" + } + } + } + }, + "tone": { + "type": "string", + "description": "Brand voice and messaging tone (e.g., 'professional', 'casual', 'humorous', 'trustworthy', 'innovative')" + }, + "tagline": { + "type": "string", + "description": "Brand tagline or slogan" + }, + "assets": { + "type": "array", + "description": "Brand asset library with explicit assets and tags. Assets are referenced inline with URLs pointing to CDN-hosted files.", + "items": { + "type": "object", + "properties": { + "asset_id": { + "type": "string", + "description": "Unique identifier for this asset" + }, + "asset_type": { + "type": "string", + "enum": ["image", "video", "audio", "text"], + "description": "Type of asset" + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL to CDN-hosted asset file" + }, + "tags": { + "type": "array", + "description": "Tags for asset discovery (e.g., 'holiday', 'lifestyle', 'product_shot')", + "items": { + "type": "string" + } + }, + "name": { + "type": "string", + "description": "Human-readable asset name" + }, + "description": { + "type": "string", + "description": "Asset description or usage notes" + }, + "width": { + "type": "integer", + "description": "Image/video width in pixels" + }, + "height": { + "type": "integer", + "description": "Image/video height in pixels" + }, + "duration_seconds": { + "type": "number", + "description": "Video/audio duration in seconds" + }, + "file_size_bytes": { + "type": "integer", + "description": "File size in bytes" + }, + "format": { + "type": "string", + "description": "File format (e.g., 'jpg', 'mp4', 'mp3')" + }, + "metadata": { + "type": "object", + "description": "Additional asset-specific metadata", + "additionalProperties": true + } + }, + "required": ["asset_id", "asset_type", "url"], + "additionalProperties": false + } + }, + "product_catalog": { + "type": "object", + "description": "Product catalog information for e-commerce advertisers. Enables SKU-level creative generation and product selection.", + "properties": { + "feed_url": { + "type": "string", + "format": "uri", + "description": "URL to product catalog feed" + }, + "feed_format": { + "type": "string", + "enum": ["google_merchant_center", "facebook_catalog", "custom"], + "default": "google_merchant_center", + "description": "Format of the product feed" + }, + "categories": { + "type": "array", + "description": "Product categories available in the catalog (for filtering)", + "items": { + "type": "string" + } + }, + "last_updated": { + "type": "string", + "format": "date-time", + "description": "When the product catalog was last updated" + }, + "update_frequency": { + "type": "string", + "enum": ["realtime", "hourly", "daily", "weekly"], + "description": "How frequently the product catalog is updated" + } + }, + "required": ["feed_url"], + "additionalProperties": false + }, + "disclaimers": { + "type": "array", + "description": "Legal disclaimers or required text that must appear in creatives", + "items": { + "type": "object", + "properties": { + "text": { + "type": "string", + "description": "Disclaimer text" + }, + "context": { + "type": "string", + "description": "When this disclaimer applies (e.g., 'financial_products', 'health_claims', 'all')" + }, + "required": { + "type": "boolean", + "description": "Whether this disclaimer must appear", + "default": true + } + }, + "required": ["text"] + } + }, + "industry": { + "type": "string", + "description": "Industry or vertical (e.g., 'retail', 'automotive', 'finance', 'healthcare')" + }, + "target_audience": { + "type": "string", + "description": "Primary target audience description" + }, + "contact": { + "type": "object", + "description": "Brand contact information", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Contact email" + }, + "phone": { + "type": "string", + "description": "Contact phone number" + } + } + }, + "metadata": { + "type": "object", + "description": "Additional brand metadata", + "properties": { + "created_date": { + "type": "string", + "format": "date-time", + "description": "When this brand card was created" + }, + "updated_date": { + "type": "string", + "format": "date-time", + "description": "When this brand card was last updated" + }, + "version": { + "type": "string", + "description": "Brand card version number" + } + } + } + }, + "required": ["url"], + "additionalProperties": false, + "examples": [ + { + "url": "https://bobsfunburgers.com", + "name": "Bob's Fun Burgers" + }, + { + "url": "https://acmecorp.com", + "name": "ACME Corporation", + "logos": [ + { + "url": "https://cdn.acmecorp.com/logo-square-dark.png", + "tags": ["dark", "square"], + "width": 512, + "height": 512 + }, + { + "url": "https://cdn.acmecorp.com/logo-horizontal-light.png", + "tags": ["light", "horizontal"], + "width": 1200, + "height": 400 + } + ], + "colors": { + "primary": "#FF6B35", + "secondary": "#004E89", + "accent": "#F7931E", + "background": "#FFFFFF", + "text": "#1A1A1A" + }, + "fonts": { + "primary": "Helvetica Neue", + "secondary": "Georgia" + }, + "tone": "professional and trustworthy", + "tagline": "Innovation You Can Trust", + "assets": [ + { + "asset_id": "hero_winter_2024", + "asset_type": "image", + "url": "https://cdn.acmecorp.com/hero-winter-2024.jpg", + "tags": ["hero", "winter", "holiday", "lifestyle"], + "name": "Winter Campaign Hero", + "width": 1920, + "height": 1080, + "format": "jpg" + }, + { + "asset_id": "product_video_30s", + "asset_type": "video", + "url": "https://cdn.acmecorp.com/product-demo-30s.mp4", + "tags": ["product", "demo", "30s"], + "name": "Product Demo 30 Second", + "width": 1920, + "height": 1080, + "duration_seconds": 30, + "format": "mp4" + } + ], + "product_catalog": { + "feed_url": "https://acmecorp.com/products.xml", + "feed_format": "google_merchant_center", + "categories": ["electronics/computers", "electronics/accessories"], + "last_updated": "2024-03-15T10:00:00Z", + "update_frequency": "hourly" + }, + "disclaimers": [ + { + "text": "Results may vary. Consult a professional before use.", + "context": "health_claims", + "required": true + } + ], + "industry": "technology", + "target_audience": "business decision-makers aged 35-55" + } + ] +} diff --git a/static/schemas/v1/core/promoted-products.json b/static/schemas/v1/core/promoted-products.json new file mode 100644 index 0000000000..ee790fa989 --- /dev/null +++ b/static/schemas/v1/core/promoted-products.json @@ -0,0 +1,158 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/v1/core/promoted-products.json", + "title": "Promoted Products", + "description": "Specification of products or offerings being promoted in a campaign. Supports multiple selection methods that can be combined: direct SKUs, tag-based filtering, category selection, natural language queries, and inline offering definitions for non-commerce campaigns.", + "type": "object", + "properties": { + "skus": { + "type": "array", + "description": "Direct product SKU references from the brand's product catalog", + "items": { + "type": "string" + } + }, + "tags": { + "type": "array", + "description": "Select products by tags from the product catalog (e.g., 'organic', 'sauces', 'holiday')", + "items": { + "type": "string" + } + }, + "category": { + "type": "string", + "description": "Select products from a specific category in the product catalog (e.g., 'beverages/soft-drinks', 'food/sauces')" + }, + "query": { + "type": "string", + "description": "Natural language query to select products (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" + }, + "offerings": { + "type": "array", + "description": "Inline offering definitions for non-commerce campaigns or campaigns without a product catalog. Use when promoting services, events, brand awareness, or other non-SKU offerings.", + "items": { + "type": "object", + "properties": { + "offering_id": { + "type": "string", + "description": "Unique identifier for this offering" + }, + "name": { + "type": "string", + "description": "Name of the offering being promoted" + }, + "description": { + "type": "string", + "description": "Description of what is being promoted" + }, + "message": { + "type": "string", + "description": "Product-specific message or context for creative generation. Provides additional context beyond the overall campaign message." + }, + "link": { + "type": "string", + "format": "uri", + "description": "Landing page or destination URL for this offering" + }, + "assets": { + "type": "array", + "description": "Campaign-specific assets for this offering (in addition to brand card assets)", + "items": { + "type": "object", + "properties": { + "asset_id": { + "type": "string" + }, + "asset_type": { + "type": "string", + "enum": ["image", "video", "audio", "text"] + }, + "url": { + "type": "string", + "format": "uri" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "width": { + "type": "integer" + }, + "height": { + "type": "integer" + }, + "duration_seconds": { + "type": "number" + }, + "format": { + "type": "string" + } + }, + "required": ["asset_id", "asset_type", "url"] + } + }, + "metadata": { + "type": "object", + "description": "Additional offering-specific metadata", + "additionalProperties": true + } + }, + "required": ["name", "description"], + "additionalProperties": false + } + } + }, + "additionalProperties": false, + "examples": [ + { + "skus": ["SKU-12345", "SKU-67890"], + "description": "Direct SKU selection for specific products" + }, + { + "tags": ["organic", "sauces"], + "category": "food/condiments", + "description": "Combine tags and category for refined selection" + }, + { + "query": "all Kraft Heinz pasta sauces under $5", + "description": "Natural language product selection" + }, + { + "offerings": [ + { + "offering_id": "q1_brand_awareness", + "name": "Q1 Brand Awareness Campaign", + "description": "Promote our new sustainability initiative and brand values", + "message": "Focus on environmental impact and corporate responsibility", + "link": "https://brand.com/sustainability", + "assets": [ + { + "asset_id": "sustainability_hero", + "asset_type": "image", + "url": "https://cdn.brand.com/sustainability-hero.jpg", + "tags": ["campaign", "sustainability"], + "width": 1920, + "height": 1080, + "format": "jpg" + } + ] + } + ], + "description": "Non-commerce campaign with inline offering" + }, + { + "skus": ["SKU-123"], + "offerings": [ + { + "offering_id": "holiday_promo", + "name": "Holiday Bundle Promotion", + "description": "Buy 2 get 1 free holiday special", + "message": "Limited time offer - perfect for gift giving" + } + ], + "description": "Combine catalog SKUs with promotional offering context" + } + ] +} diff --git a/static/schemas/v1/index.json b/static/schemas/v1/index.json index 363ad8f923..999f6566d8 100644 --- a/static/schemas/v1/index.json +++ b/static/schemas/v1/index.json @@ -82,6 +82,14 @@ "property": { "$ref": "/schemas/v1/core/property.json", "description": "An advertising property that can be validated via adagents.json" + }, + "brand-card": { + "$ref": "/schemas/v1/core/brand-card.json", + "description": "Standardized brand information manifest for creative generation and media buying" + }, + "promoted-products": { + "$ref": "/schemas/v1/core/promoted-products.json", + "description": "Product or offering selection for campaigns with multiple selection methods" } } }, diff --git a/static/schemas/v1/media-buy/build-creative-request.json b/static/schemas/v1/media-buy/build-creative-request.json index f507e9857d..90cd8d3c20 100644 --- a/static/schemas/v1/media-buy/build-creative-request.json +++ b/static/schemas/v1/media-buy/build-creative-request.json @@ -41,9 +41,46 @@ "default": "manifest", "description": "Output format - 'manifest' for asset-based creatives, 'code' for executable creative code" }, + "brand_card": { + "$ref": "/schemas/v1/core/brand-card.json", + "description": "Brand information manifest providing context for creative generation. Replaces brand_guidelines with a more comprehensive and standardized format." + }, + "promoted_products": { + "$ref": "/schemas/v1/core/promoted-products.json", + "description": "Products or offerings being promoted in this creative. Supports SKU selection from brand card's product catalog, or inline offerings for non-commerce campaigns." + }, + "asset_filters": { + "type": "object", + "description": "Filters to select specific assets from the brand card's asset library", + "properties": { + "tags": { + "type": "array", + "description": "Select assets matching any of these tags (e.g., ['holiday', 'winter'])", + "items": { + "type": "string" + } + }, + "asset_types": { + "type": "array", + "description": "Limit to specific asset types", + "items": { + "type": "string", + "enum": ["image", "video", "audio", "text"] + } + }, + "exclude_tags": { + "type": "array", + "description": "Exclude assets with these tags", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, "brand_guidelines": { "type": "object", - "description": "Brand-specific guidelines and constraints", + "description": "DEPRECATED: Use brand_card instead. Legacy brand-specific guidelines and constraints.", "properties": { "colors": { "type": "array", diff --git a/static/schemas/v1/media-buy/create-media-buy-request.json b/static/schemas/v1/media-buy/create-media-buy-request.json index ef4787bb35..6fb482fe28 100644 --- a/static/schemas/v1/media-buy/create-media-buy-request.json +++ b/static/schemas/v1/media-buy/create-media-buy-request.json @@ -26,6 +26,14 @@ "type": "string", "description": "Description of advertiser and what is being promoted" }, + "brand_card": { + "$ref": "/schemas/v1/core/brand-card.json", + "description": "Optional brand information manifest for creative generation and campaign context. Can be cached and reused across multiple requests." + }, + "promoted_products": { + "$ref": "/schemas/v1/core/promoted-products.json", + "description": "Products or offerings being promoted in this media buy. Supports SKU selection from brand card's product catalog, or inline offerings for non-commerce campaigns." + }, "po_number": { "type": "string", "description": "Purchase order number for tracking" From 9a77aabe43707ed0d658af9cf6996bfb0a7d1b6f Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 11 Oct 2025 09:22:25 -0400 Subject: [PATCH 2/4] feat: make brand card the namespace for media buys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes brand_card the central identifier and required field for media buys, emphasizing its role as the namespace for all advertising activity. ## Changes - **Brand Card**: Require either `url` OR `name` (supports brands without URLs) - **create_media_buy**: Make `brand_card` required, deprecate `promoted_offering` - **Documentation**: Emphasize brand card as namespace and identity - **Examples**: Add white-label brand example without URL ## Brand Card as Namespace The brand card now serves as the primary identifier for: - All media buys for a brand - All creative generation requests - Asset library access - Product catalog references This enables: - Natural grouping of campaigns by brand - Consistent brand identity across all requests - Better caching (fetch once, use everywhere) - Simplified querying ("show all campaigns for this brand") ## Brands Without URLs Supports name-only brands for: - White-label/store brands (e.g., "Great Value", "Kirkland") - Local businesses without websites - B2B brands without public sites - Sub-brands under parent company URLs ## Migration Existing implementations should update from: ```json {"promoted_offering": "Campaign Name", "brand_card": {...}} ``` To: ```json {"brand_card": {...}, "promoted_products": {...}} ``` The `promoted_offering` field is now deprecated. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../task-reference/create_media_buy.md | 5 +- docs/reference/brand-card.md | 46 +++++++++++++++---- static/schemas/v1/core/brand-card.json | 21 ++++++++- .../media-buy/create-media-buy-request.json | 12 ++--- 4 files changed, 66 insertions(+), 18 deletions(-) diff --git a/docs/media-buy/task-reference/create_media_buy.md b/docs/media-buy/task-reference/create_media_buy.md index a833dd75d2..60629ac22a 100644 --- a/docs/media-buy/task-reference/create_media_buy.md +++ b/docs/media-buy/task-reference/create_media_buy.md @@ -21,8 +21,9 @@ Create a media buy from selected packages. This task handles the complete workfl |-----------|------|----------|-------------| | `buyer_ref` | string | Yes | Buyer's reference identifier for this media buy | | `packages` | Package[] | Yes | Array of package configurations (see Package Object below) | -| `promoted_offering` | string | Yes | Description of advertiser and what is being promoted | -| `brand_card` | BrandCard | No | Optional brand information manifest for creative generation and campaign context. Can be cached and reused across multiple requests. See [Brand Card](../../reference/brand-card) for details. | +| `brand_card` | BrandCard | Yes | Brand information manifest serving as the namespace and identity for this media buy. Provides brand context, assets, and product catalog. Can be cached and reused across multiple requests. See [Brand Card](../../reference/brand-card) for details. | +| `promoted_products` | PromotedProducts | No | Products or offerings being promoted in this media buy. Supports SKU selection from brand card's product catalog, or inline offerings for non-commerce campaigns. | +| `promoted_offering` | string | No | **DEPRECATED**: Use `brand_card` with `promoted_products` instead. Legacy field for describing what is being promoted. | | `po_number` | string | No | Purchase order number for tracking | | `start_time` | string | Yes | Campaign start date/time in ISO 8601 format (UTC unless timezone specified) | | `end_time` | string | Yes | Campaign end date/time in ISO 8601 format (UTC unless timezone specified) | diff --git a/docs/reference/brand-card.md b/docs/reference/brand-card.md index 610653ec98..13ddc47fad 100644 --- a/docs/reference/brand-card.md +++ b/docs/reference/brand-card.md @@ -6,16 +6,23 @@ keywords: [brand card, brand manifest, creative generation, brand guidelines] # Brand Card -The **Brand Card** is a standardized manifest format for sharing brand information across AdCP workflows. It enables low-friction creative generation by providing brand context that can be easily cached and reused across multiple requests. +The **Brand Card** is a standardized manifest format that serves as the **namespace and identity** for brands in AdCP. It provides brand context, assets, and product catalogs that can be cached and reused across all media buys and creative generation requests. ## Overview -Brand cards solve a key problem identified in creative agent workflows: how to efficiently provide brand context without requiring complex authorization flows or repeated data entry. The format supports both simple use cases (just a URL) and enterprise scenarios (comprehensive brand assets and guidelines). +Brand cards solve a key problem: how to efficiently provide brand context without requiring complex authorization flows or repeated data entry. By making the brand card the central identifier for all advertising activity, AdCP enables: + +- **Natural grouping**: All media buys and creatives for a brand reference the same card +- **Consistent identity**: Brand guidelines automatically travel with every request +- **Better caching**: Fetch once, use everywhere +- **Simplified queries**: "Show me all campaigns for this brand" +- **Asset discovery**: Creative requests automatically access brand assets ### Key Benefits -- **Minimal Friction**: Start with just a URL, expand as needed -- **Cacheable**: Same brand card can be reused across requests +- **Namespace**: Brand card serves as the primary identifier for all advertising activity +- **Minimal Friction**: Start with just a name or URL, expand as needed +- **Cacheable**: Same brand card reused across all requests - **Standardized**: Consistent format across all AdCP implementations - **Flexible**: Supports SMB to enterprise use cases - **AI-Optimized**: Structured for easy ingestion by creative agents @@ -83,10 +90,9 @@ Large retailers can provide product feeds and asset libraries: { "url": "https://bigretail.com", "name": "BigRetail", - "product_feed": "https://bigretail.com/catalog.json", - "asset_library": { - "images": "https://assets.bigretail.com/api/images", - "videos": "https://assets.bigretail.com/api/videos" + "product_catalog": { + "feed_url": "https://bigretail.com/catalog.xml", + "feed_format": "google_merchant_center" }, "disclaimers": [ { @@ -98,15 +104,39 @@ Large retailers can provide product feeds and asset libraries: } ``` +### Brands Without URLs + +Some brands don't have dedicated URLs (white-label products, local businesses, B2B brands). Brand cards support name-only identification: + +```json +{ + "name": "Great Value", + "colors": { + "primary": "#0071CE", + "secondary": "#FFC220" + }, + "tone": "affordable and trustworthy" +} +``` + +**Common cases for name-only brands:** +- White-label/store brands (e.g., "Great Value", "Kirkland") +- Local businesses without websites +- B2B brands without public sites +- Sub-brands under parent company URLs + ## Brand Card Schema **Schema URL**: [/schemas/v1/core/brand-card.json](/schemas/v1/core/brand-card.json) ### Required Fields +**Either `url` OR `name` is required** (both can be provided): + | Field | Type | Description | |-------|------|-------------| | `url` | string (uri) | Primary brand URL for context and asset discovery | +| `name` | string | Brand or business name (required if no URL provided) | ### Optional Fields diff --git a/static/schemas/v1/core/brand-card.json b/static/schemas/v1/core/brand-card.json index 6349785343..e16eac69e5 100644 --- a/static/schemas/v1/core/brand-card.json +++ b/static/schemas/v1/core/brand-card.json @@ -273,12 +273,29 @@ } } }, - "required": ["url"], + "anyOf": [ + { + "required": ["url"] + }, + { + "required": ["name"] + } + ], "additionalProperties": false, "examples": [ { "url": "https://bobsfunburgers.com", - "name": "Bob's Fun Burgers" + "name": "Bob's Fun Burgers", + "description": "Example with both URL and name" + }, + { + "name": "Great Value", + "description": "Example: white-label brand without dedicated URL", + "colors": { + "primary": "#0071CE", + "secondary": "#FFC220" + }, + "tone": "affordable and trustworthy" }, { "url": "https://acmecorp.com", diff --git a/static/schemas/v1/media-buy/create-media-buy-request.json b/static/schemas/v1/media-buy/create-media-buy-request.json index 6fb482fe28..f535d87965 100644 --- a/static/schemas/v1/media-buy/create-media-buy-request.json +++ b/static/schemas/v1/media-buy/create-media-buy-request.json @@ -22,13 +22,13 @@ "$ref": "/schemas/v1/media-buy/package-request.json" } }, - "promoted_offering": { - "type": "string", - "description": "Description of advertiser and what is being promoted" - }, "brand_card": { "$ref": "/schemas/v1/core/brand-card.json", - "description": "Optional brand information manifest for creative generation and campaign context. Can be cached and reused across multiple requests." + "description": "Brand information manifest serving as the namespace and identity for this media buy. Provides brand context, assets, and product catalog. Can be cached and reused across multiple requests." + }, + "promoted_offering": { + "type": "string", + "description": "DEPRECATED: Use brand_card with promoted_products instead. Legacy field for describing what is being promoted." }, "promoted_products": { "$ref": "/schemas/v1/core/promoted-products.json", @@ -88,6 +88,6 @@ "additionalProperties": false } }, - "required": ["buyer_ref", "packages", "promoted_offering", "start_time", "end_time", "budget"], + "required": ["buyer_ref", "packages", "brand_card", "start_time", "end_time", "budget"], "additionalProperties": false } \ No newline at end of file From 5c193e64f52da9be83436a6771c4463c859e68c6 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 11 Oct 2025 09:39:18 -0400 Subject: [PATCH 3/4] feat: remove manage_creative_library task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes manage_creative_library task as asset management is now handled entirely through brand cards. This simplifies creative agents to be pure generators with no storage responsibilities. ## Rationale With brand card as the namespace providing: - Explicit asset arrays with tags for brand-level assets - Product catalog references for large inventories - Inline assets in promoted_products for campaign-specific needs There is no need for a separate asset library management system. ## Changes - Removed `manage_creative_library` task schemas and documentation - Updated generative creative docs to reference brand card for assets - Removed creative-library-item schema - Updated sidebar navigation ## Creative Agent Responsibilities (Simplified) ✅ `build_creative`: Generate manifests from provided context ✅ `preview_creative`: Show previews of manifests ✅ `list_creative_formats`: Advertise capabilities ❌ Asset storage/management (handled by brand card) ❌ Creative manifest storage (caller's responsibility) Creative agents are now pure generators - no database, no CRUD operations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- docs/creative/generative-creative.md | 59 +-- .../task-reference/manage_creative_library.md | 370 ------------------ docs/media-buy/creatives/creative-library.md | 347 ---------------- docs/media-buy/creatives/index.md | 7 +- sidebars.ts | 2 - .../v1/core/creative-library-item.json | 153 -------- static/schemas/v1/index.json | 14 - .../manage-creative-library-request.json | 110 ------ .../manage-creative-library-response.json | 164 -------- 9 files changed, 16 insertions(+), 1210 deletions(-) delete mode 100644 docs/creative/task-reference/manage_creative_library.md delete mode 100644 docs/media-buy/creatives/creative-library.md delete mode 100644 static/schemas/v1/core/creative-library-item.json delete mode 100644 static/schemas/v1/media-buy/manage-creative-library-request.json delete mode 100644 static/schemas/v1/media-buy/manage-creative-library-response.json diff --git a/docs/creative/generative-creative.md b/docs/creative/generative-creative.md index 62bd41a8b6..211c9a6520 100644 --- a/docs/creative/generative-creative.md +++ b/docs/creative/generative-creative.md @@ -6,10 +6,13 @@ The Creative Protocol enables AI-powered creative generation and asset managemen ## Overview -The Creative Protocol provides two main capabilities: +The Creative Protocol provides AI-powered creative generation: - **`build_creative`**: Generate creative content using AI with either static manifests or dynamic code -- **`manage_creative_library`**: Organize and search creative assets with intelligent tagging +- **`preview_creative`**: Generate previews of creative manifests +- **`list_creative_formats`**: Discover supported creative formats + +Assets are provided via [Brand Card](../reference/brand-card) - no separate asset library management needed. ## Quick Start: Generate Your First Creative @@ -170,42 +173,6 @@ For custom publisher formats, specify the source: } ``` -## Asset Library Management - -### Organizing Assets - -Tag your assets for easy discovery: - -```json -{ - "action": "upload", - "asset": { - "type": "image", - "url": "https://brand.com/summer-menu.jpg", - "tags": ["seasonal", "summer", "menu", "photography"], - "metadata": { - "campaign": "summer_2024", - "dimensions": {"width": 1200, "height": 800} - } - } -} -``` - -### Searching Assets - -Find assets using natural language: - -```json -{ - "action": "search", - "query": "summer beverage photos for social media", - "filters": { - "asset_types": ["image"], - "tags": ["summer", "beverages"] - } -} -``` - ## Next Steps - **Browse Examples**: See [Task Reference](task-reference/build_creative.md) for detailed examples @@ -224,13 +191,13 @@ If you get a format error, the publisher may not support that format. Try: ### Creative Quality Issues To improve creative output: 1. Be more specific in your message: "Create a minimalist coffee ad with earth tones" -2. Provide brand guidelines in the request -3. Use the conversational refinement feature to iterate - -### Asset Library Organization -For better asset management: -1. Use consistent tagging conventions -2. Include campaign and date information -3. Add descriptive metadata for easier searching +2. Provide comprehensive brand card with assets and guidelines +3. Use the conversational refinement feature to iterate (via `context_id`) + +### Asset Management +Assets are provided via [Brand Card](../reference/brand-card): +1. Include assets in brand card with descriptive tags +2. Use `asset_filters` in requests to select specific assets +3. Reference product catalogs for large inventories Ready to create your first creative? Start with the basic example above and explore from there! \ No newline at end of file diff --git a/docs/creative/task-reference/manage_creative_library.md b/docs/creative/task-reference/manage_creative_library.md deleted file mode 100644 index f030fd0826..0000000000 --- a/docs/creative/task-reference/manage_creative_library.md +++ /dev/null @@ -1,370 +0,0 @@ ---- -title: manage_creative_library -sidebar_position: 14 ---- - -# manage_creative_library - -Manage assets in the creative library, including adding, updating, removing, and organizing assets with tags. - -## Request Parameters - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `action` | string | Yes | `"add"`, `"update"`, `"remove"`, `"list"`, or `"search"` | -| `library_id` | string | Yes | The library to manage | -| `asset` | object | No* | Asset details (*Required for add/update actions) | -| `asset_id` | string | No* | Asset identifier (*Required for update/remove actions) | -| `tags` | array | No | Tags for filtering or updating | -| `search_query` | string | No | Search query for list/search actions | -| `filters` | object | No | Additional filters for list/search | - -### Asset Structure - -```typescript -{ - asset_id?: string; // Auto-generated if not provided - name: string; // Human-readable name - type: string; // "image", "video", "audio", "text", "logo", etc. - url?: string; // URL for media assets - content?: string; // Inline content for text assets - metadata?: { - width?: number; - height?: number; - duration?: number; // For video/audio in seconds - file_size?: number; // In bytes - mime_type?: string; - alt_text?: string; // For accessibility - }; - tags: string[]; // Organizational tags - usage_rights?: string; // "unlimited", "limited", "exclusive" - expires_at?: string; // ISO date for time-limited assets -} -``` - -### Filter Structure - -```typescript -{ - type?: string | string[]; // Filter by asset type(s) - tags?: string[]; // Must have all specified tags - created_after?: string; // ISO date - created_before?: string; // ISO date - usage_rights?: string; // Filter by usage rights - has_expiry?: boolean; // Filter by expiration status -} -``` - -## Response Format - -```json -{ - "message": "string", - "success": true, - "result": "object" -} -``` - -### Result Formats by Action - -#### Add/Update Result -```json -{ - "asset": { - "asset_id": "asset_123", - "name": "Summer Campaign Hero Image", - "type": "image", - "url": "https://cdn.example.com/assets/summer-hero.jpg", - "metadata": { - "width": 1920, - "height": 1080, - "file_size": 2048000, - "mime_type": "image/jpeg" - }, - "tags": ["summer_2024", "hero_image", "lifestyle"], - "created_at": "2024-02-15T10:00:00Z", - "updated_at": "2024-02-15T10:00:00Z" - } -} -``` - -#### List/Search Result -```json -{ - "assets": [ - { - "asset_id": "asset_123", - "name": "Summer Campaign Hero Image", - "type": "image", - "tags": ["summer_2024", "hero_image"], - "url": "https://cdn.example.com/assets/summer-hero.jpg" - } - ], - "total_count": 42, - "page": 1, - "page_size": 20 -} -``` - -#### Remove Result -```json -{ - "removed_asset_id": "asset_123", - "removed_at": "2024-02-15T10:00:00Z" -} -``` - -## Examples - -### Example 1: Adding Assets with Tags - -```json -{ - "action": "add", - "library_id": "purina_assets", - "asset": { - "name": "July 4th Sale - Hero Banner", - "type": "image", - "url": "https://cdn.purina.com/campaigns/july4th/hero-banner.jpg", - "metadata": { - "width": 1200, - "height": 628, - "alt_text": "Save 20% on all Purina products this July 4th" - }, - "tags": ["july_us_sale", "hero_banner", "promotional", "q3_2024"], - "usage_rights": "unlimited", - "expires_at": "2024-07-31T23:59:59Z" - } -} -``` - -#### Response -```json -{ - "message": "Asset 'July 4th Sale - Hero Banner' added successfully to purina_assets library", - "success": true, - "result": { - "asset": { - "asset_id": "asset_july4th_hero_001", - "name": "July 4th Sale - Hero Banner", - "type": "image", - "url": "https://cdn.purina.com/campaigns/july4th/hero-banner.jpg", - "metadata": { - "width": 1200, - "height": 628, - "file_size": 856320, - "mime_type": "image/jpeg", - "alt_text": "Save 20% on all Purina products this July 4th" - }, - "tags": ["july_us_sale", "hero_banner", "promotional", "q3_2024"], - "usage_rights": "unlimited", - "expires_at": "2024-07-31T23:59:59Z", - "created_at": "2024-02-15T10:00:00Z" - } - } -} -``` - -### Example 2: Bulk Add with Common Tags - -```json -{ - "action": "add", - "library_id": "purina_assets", - "asset": [ - { - "name": "July Sale - Dog Food Product Shot", - "type": "image", - "url": "https://cdn.purina.com/campaigns/july4th/dog-food.jpg", - "tags": ["july_us_sale", "product_shot", "dog_food"] - }, - { - "name": "July Sale - Cat Food Product Shot", - "type": "image", - "url": "https://cdn.purina.com/campaigns/july4th/cat-food.jpg", - "tags": ["july_us_sale", "product_shot", "cat_food"] - }, - { - "name": "July Sale - Promo Video", - "type": "video", - "url": "https://cdn.purina.com/campaigns/july4th/promo.mp4", - "metadata": { - "duration": 15, - "width": 1920, - "height": 1080 - }, - "tags": ["july_us_sale", "promotional_video", "social_media"] - } - ] -} -``` - -### Example 3: Searching by Tags - -```json -{ - "action": "search", - "library_id": "purina_assets", - "tags": ["july_us_sale"], - "filters": { - "type": "image" - } -} -``` - -#### Response -```json -{ - "message": "Found 12 image assets tagged with 'july_us_sale'", - "success": true, - "result": { - "assets": [ - { - "asset_id": "asset_july4th_hero_001", - "name": "July 4th Sale - Hero Banner", - "type": "image", - "tags": ["july_us_sale", "hero_banner", "promotional", "q3_2024"], - "url": "https://cdn.purina.com/campaigns/july4th/hero-banner.jpg" - }, - { - "asset_id": "asset_july4th_prod_001", - "name": "July Sale - Dog Food Product Shot", - "type": "image", - "tags": ["july_us_sale", "product_shot", "dog_food"], - "url": "https://cdn.purina.com/campaigns/july4th/dog-food.jpg" - } - ], - "total_count": 12, - "page": 1, - "page_size": 20 - } -} -``` - -### Example 4: Updating Asset Tags - -```json -{ - "action": "update", - "library_id": "purina_assets", - "asset_id": "asset_july4th_hero_001", - "asset": { - "tags": ["july_us_sale", "hero_banner", "promotional", "q3_2024", "best_performer"] - } -} -``` - -### Example 5: Removing Expired Assets - -```json -{ - "action": "search", - "library_id": "purina_assets", - "filters": { - "created_before": "2024-08-01T00:00:00Z", - "has_expiry": true - } -} -``` - -Then remove each expired asset: -```json -{ - "action": "remove", - "library_id": "purina_assets", - "asset_id": "asset_july4th_hero_001" -} -``` - -## Tag Management Best Practices - -### Recommended Tag Categories - -1. **Campaign Tags**: `"july_us_sale"`, `"black_friday_2024"`, `"spring_launch"` -2. **Asset Type Tags**: `"hero_image"`, `"product_shot"`, `"lifestyle"`, `"logo"` -3. **Channel Tags**: `"social_media"`, `"email"`, `"display"`, `"video"` -4. **Temporal Tags**: `"q1_2024"`, `"seasonal"`, `"evergreen"` -5. **Performance Tags**: `"best_performer"`, `"testing"`, `"archived"` -6. **Product Tags**: `"dog_food"`, `"cat_food"`, `"treats"`, `"toys"` -7. **Audience Tags**: `"gen_z"`, `"pet_parents"`, `"new_customers"` - -### Tag Naming Conventions - -- Use lowercase with underscores: `"july_us_sale"` not `"July US Sale"` -- Be specific but not too granular: `"summer_2024"` not `"june_15_2024"` -- Use consistent prefixes for categories: `"product_dog_food"`, `"product_cat_food"` -- Avoid special characters except underscores - -## Implementation Guide - -### Asset Storage Integration - -```python -def add_asset_to_library(library_id, asset_data): - # Validate asset data - validate_asset(asset_data) - - # Generate ID if not provided - if not asset_data.get('asset_id'): - asset_data['asset_id'] = generate_asset_id(asset_data) - - # Process media if URL provided - if asset_data.get('url'): - metadata = extract_media_metadata(asset_data['url']) - asset_data['metadata'] = {**metadata, **asset_data.get('metadata', {})} - - # Add timestamps - asset_data['created_at'] = datetime.now().isoformat() - asset_data['updated_at'] = asset_data['created_at'] - - # Store in library - library = get_library(library_id) - library.add_asset(asset_data) - - # Index by tags for fast retrieval - index_asset_tags(library_id, asset_data['asset_id'], asset_data.get('tags', [])) - - return asset_data -``` - -### Tag-Based Search - -```python -def search_assets_by_tags(library_id, tags, filters=None): - library = get_library(library_id) - - # Get assets with ALL specified tags - asset_ids = library.get_assets_with_tags(tags) - - # Apply additional filters - if filters: - asset_ids = apply_filters(asset_ids, filters) - - # Retrieve asset details - assets = [library.get_asset(aid) for aid in asset_ids] - - return assets -``` - -### Automatic Tag Suggestions - -```python -def suggest_tags(asset): - suggestions = [] - - # Based on asset type - if asset['type'] == 'image': - if asset.get('metadata', {}).get('width', 0) > 1000: - suggestions.append('high_res') - - # Based on filename/URL - if 'summer' in asset.get('name', '').lower(): - suggestions.append('seasonal') - suggestions.append('summer_2024') - - # Based on upload date - quarter = get_quarter(asset.get('created_at')) - suggestions.append(f'q{quarter}_2024') - - return suggestions -``` \ No newline at end of file diff --git a/docs/media-buy/creatives/creative-library.md b/docs/media-buy/creatives/creative-library.md deleted file mode 100644 index f00b303d3b..0000000000 --- a/docs/media-buy/creatives/creative-library.md +++ /dev/null @@ -1,347 +0,0 @@ ---- -title: Creative Library ---- - -# Creative Library - -The AdCP Creative Library provides centralized management for all creative assets at the advertiser/account level. This industry-standard approach eliminates redundant uploads, enables creative reuse across campaigns, and provides better governance and performance tracking. - -## Overview - -Unlike the traditional model where creatives are uploaded directly to campaigns, AdCP's Creative Library follows the standard approach used by major ad platforms: - -1. **Upload Once**: Creatives are uploaded to a central library -2. **Assign Many**: Library creatives can be assigned to multiple campaigns -3. **Manage Centrally**: All creative operations happen at the library level -4. **Track Globally**: Performance and compliance tracked across all uses - -This approach mirrors how Google Ad Manager, Meta Business Manager, and other major platforms handle creative assets. - -## Quick Start - -Ready to start using the Creative Library? Here's the essential workflow: - -1. **📤 Upload creatives**: [`sync_creatives`](../task-reference/sync_creatives) - Add assets to your library -2. **🔍 Find creatives**: [`list_creatives`](../task-reference/list_creatives) - Search and filter your library -3. **🎯 Assign to campaigns**: Use assignments in [`sync_creatives`](../task-reference/sync_creatives) or [`create_media_buy`](../task-reference/create_media_buy) - -**New to creative management?** Start with the [Creative Lifecycle](./index.md) conceptual overview. - -## Library Architecture - -### Creative Storage - -All creatives are stored at the **advertiser/account level**, making them available for any media buy within that account. Each creative in the library has: - -- **Unique Identity**: `creative_id` that remains consistent across all uses -- **Rich Metadata**: Name, tags, format information, compliance status -- **Assignment Tracking**: Real-time view of which campaigns use the creative -- **Performance History**: Aggregated metrics across all assignments - -### Assignment Model - -Creatives are **assigned** to specific packages within media buys rather than being uploaded directly: - -``` -Creative Library - ├── Creative A (video_hero_30s) - │ ├── Assigned to: Campaign 1, Package A - │ └── Assigned to: Campaign 2, Package C - │ - ├── Creative B (display_banner_300x250) - │ └── Assigned to: Campaign 1, Package B - │ - └── Creative C (audio_spot_15s) - └── Unassigned (available for future use) -``` - -## Core Operations - -The creative library supports two primary operations: - -### 1. Creative Management - -Use [`sync_creatives`](../task-reference/sync_creatives) to: -- Upload new creatives to the library -- Update existing creative metadata -- Assign creatives to packages -- Bulk operations with upsert semantics - -**Benefits:** -- No immediate campaign assignment required -- Creative available for multiple future uses -- Validation and approval before assignment -- Suggested adaptations for better performance - -**📋 Get Started:** See the [`sync_creatives`](../task-reference/sync_creatives) technical documentation for detailed examples and parameters. - -### 2. Creative Discovery - -Use [`list_creatives`](../task-reference/list_creatives) to: -- Search and filter library creatives -- Find available assets for new campaigns -- Track assignment status -- Analyze performance across creatives - -**Use Cases:** -- Find creatives for new campaigns -- Audit unused assets -- Performance analysis across creatives -- Compliance reviews - -**🔍 Get Started:** See the [`list_creatives`](../task-reference/list_creatives) technical documentation for advanced filtering and querying options. - -### 3. Assign (`action: "assign"`) - -Connect library creatives to campaign packages: - -```json -{ - "action": "assign", - "creative_ids": ["brand_video_30s", "brand_video_15s"], - "media_buy_id": "mb_12345", - "package_assignments": ["pkg_ctv_prime", "pkg_ctv_daytime"] -} -``` - -**Benefits:** -- Instant campaign setup with existing assets -- No re-upload or re-approval needed -- Flexible assignment to specific packages -- Bulk assignment operations - -### 4. Update (`action: "update"`) - -Modify creative metadata: - -```json -{ - "action": "update", - "creative_id": "brand_video_30s", - "updates": { - "click_url": "https://brand.com/spring-sale", - "name": "Brand Hero Video 30s - Spring Sale" - } -} -``` - -**Applies To:** All current and future assignments of the creative - -### 5. Unassign (`action: "unassign"`) - -Remove creative from specific campaigns while keeping in library: - -```json -{ - "action": "unassign", - "creative_ids": ["brand_video_30s"], - "package_ids": ["pkg_ctv_prime"] -} -``` - -**Preserves:** Creative remains in library for future use - -### 6. Archival - -Creatives can be archived through [`sync_creatives`](../task-reference/sync_creatives) status updates: - -**Options:** -- **Archive**: Soft delete, preserves for reporting -- **Delete**: Permanent removal (use with caution) - -## Library Organization - -### Naming Conventions - -Use consistent `creative_id` patterns for better organization: - -``` -Format: {brand}_{type}_{duration/size}_{version} - -Examples: -- nike_hero_video_30s_v1 -- nike_display_banner_300x250_v2 -- nike_audio_spot_15s_v1 -``` - -### Tag Strategy - -Organize creatives with meaningful tags: - -**Campaign Tags:** -- `q1_2024`, `holiday_campaign`, `summer_sale` - -**Format Tags:** -- `video`, `audio`, `display`, `mobile_optimized` - -**Performance Tags:** -- `high_ctr`, `approved_creative`, `needs_optimization` - -**Brand Tags:** -- `nike_air`, `nike_jordan`, `brand_logo` - -### Status Management - -Track creative lifecycle through status values: - -- **`approved`**: Ready for campaign assignment -- **`pending_review`**: Uploaded, awaiting platform approval -- **`rejected`**: Failed validation, needs revision -- **`processing`**: Being transcoded or processed -- **`archived`**: Soft-deleted, preserved for reporting - -## Platform Integration - -### Google Ad Manager -- Maps to advertiser-level creative library -- Supports standard IAB creative formats -- Automatic policy compliance checking -- Creative approval typically within 24 hours - -### Meta Business Manager -- Integrates with ad account creative library -- Supports video, image, and carousel formats -- Automatic optimization suggestions -- Real-time creative performance tracking - -### Kevel -- Uses template-based creative system -- Supports custom creative formats -- Real-time creative decisioning -- Flexible creative assignment rules - -### Triton Digital -- Station-level creative management -- Audio format specialization -- Broadcast compliance tracking -- Daypart-specific creative rotation - -## Performance & Analytics - -### Creative Performance Tracking - -Library creatives accumulate performance data across all assignments: - -```json -{ - "creative_id": "brand_video_30s", - "performance_metrics": { - "total_impressions": 1250000, - "total_clicks": 15750, - "average_ctr": 0.0126, - "assignments": 3, - "campaigns_used": 2 - } -} -``` - -### Cross-Campaign Analysis - -Compare creative performance across different contexts: - -- **Format Analysis**: Which video lengths perform best? -- **Campaign Context**: Does the same creative perform differently across campaigns? -- **Platform Optimization**: Which adaptations work best on each platform? -- **Audience Insights**: Creative performance by targeting dimension - -## Best Practices - -### Upload Strategy - -1. **Upload Early**: Add creatives to library before campaign planning -2. **Version Control**: Use clear version numbers for creative iterations -3. **Format Planning**: Consider multiple formats (mobile, desktop, audio) during upload -4. **Tag Consistently**: Use standardized tagging for easy discovery - -### Assignment Workflow - -1. **Search First**: Check library for existing suitable creatives -2. **Bulk Assign**: Use batch operations for efficiency -3. **Monitor Performance**: Track how library creatives perform across campaigns -4. **Optimize Continuously**: Update click URLs and metadata based on performance - -### Library Maintenance - -1. **Regular Audits**: Review unused or underperforming creatives -2. **Archive Outdated**: Remove expired promotional creatives -3. **Performance Reviews**: Identify top-performing creatives for reuse -4. **Compliance Monitoring**: Ensure all creatives meet current policy requirements - -### Creative Governance - -1. **Approval Workflows**: Establish library upload approval processes -2. **Brand Guidelines**: Ensure all uploads meet brand standards -3. **Usage Tracking**: Monitor which creatives are being used where -4. **Performance Standards**: Set minimum performance thresholds - -## Migration to Creative Library - -If migrating from deprecated creative workflows: - -### Step 1: Upload Existing Creatives -Use [`sync_creatives`](../task-reference/sync_creatives) to add assets to the library: -```json -{ - "creatives": [/* your existing creative assets */] -} -``` - -### Step 2: Assign to Current Campaigns -Use the `assignments` parameter in [`sync_creatives`](../task-reference/sync_creatives) or create new campaigns with [`create_media_buy`](../task-reference/create_media_buy). - -### Step 3: Adopt Library Workflow -- Use [`list_creatives`](../task-reference/list_creatives) to search before creating new creatives -- Reuse approved creatives across campaigns -- Manage all creative operations through the library - -## Troubleshooting - -### Common Issues - -**Creative Not Found** -- Verify `creative_id` exists in library -- Check creative status (may be archived) -- Ensure proper account-level access - -**Assignment Failed** -- Verify media buy exists and is active -- Check package IDs are valid -- Ensure creative format matches package requirements - -**Performance Discrepancies** -- Library metrics are aggregated across all assignments -- Use campaign-specific reporting for individual performance -- Consider assignment timing when analyzing performance - -### Support Resources - -- Use [`list_creatives`](../task-reference/list_creatives) to audit current library state -- Check creative status and assignment history -- Review platform-specific creative requirements -- Monitor adaptation suggestions for optimization opportunities - -## Ready to Get Started? - -Now that you understand the Creative Library architecture, here are your next steps: - -### 🏗️ **Implementation** -- **Start uploading**: Follow [`sync_creatives`](../task-reference/sync_creatives) for technical implementation -- **Query your library**: Use [`list_creatives`](../task-reference/list_creatives) for advanced filtering and search -- **Understand the workflow**: Read [Creative Lifecycle](./index.md) for end-to-end process - -### 📋 **Planning** -- **Review formats**: Check [Creative Formats](../../creative/formats) for platform requirements -- **Design your library**: Plan your creative ID conventions and tagging strategy -- **Map your workflow**: Align the library approach with your existing creative operations - -### 🔗 **Integration** -- **Connect platforms**: Integrate with your existing creative management tools -- **Enable AI workflows**: Set up [MCP integration](../../protocols/mcp-guide) for AI assistant access -- **Build automations**: Leverage [A2A protocol](../../protocols/a2a-guide) for natural language operations - -## Related Documentation - -- [`sync_creatives`](../task-reference/sync_creatives) - Creative management API reference -- [`list_creatives`](../task-reference/list_creatives) - Creative query API reference -- [Creative Lifecycle](./index.md) - End-to-end creative workflow -- [Creative Formats](../../creative/formats) - Understanding format specifications and discovery \ No newline at end of file diff --git a/docs/media-buy/creatives/index.md b/docs/media-buy/creatives/index.md index 45548c6686..3954a9c8cb 100644 --- a/docs/media-buy/creatives/index.md +++ b/docs/media-buy/creatives/index.md @@ -122,12 +122,11 @@ Once you understand format requirements, create the actual creative assets accor AdCP uses a centralized creative library where assets are uploaded once and assigned to multiple campaigns. This industry-standard approach enables: - Upload creatives to account-level library -- Assign library assets to specific campaigns/packages +- Assign creatives to specific campaigns/packages - Reuse creatives across multiple media buys - Track performance across all assignments -- Update metadata globally for all uses -**For complete details on library operations, organization, and best practices**, see [Creative Library](./creative-library.md). +Asset management is handled through [Brand Cards](../../reference/brand-card), which provide brand-level assets with tags for discovery. ## Platform Considerations @@ -171,7 +170,7 @@ Creative operations have varying response times: - **[`sync_creatives`](../task-reference/sync_creatives)** - Bulk creative management with upsert semantics - **[`list_creatives`](../task-reference/list_creatives)** - Advanced creative library querying and filtering - **[`list_creative_formats`](../task-reference/list_creative_formats)** - Understanding format requirements -- **[Creative Library](./creative-library)** - Centralized creative management concepts +- **[Brand Card](../../reference/brand-card)** - Brand identity and asset management - **[Creative Formats](../../creative/formats)** - Understanding format specifications and discovery - **[Creative Channel Guides](../../creative/channels/video)** - Format examples across video, display, audio, DOOH, and carousels - **[Asset Types](../../creative/asset-types)** - Understanding asset roles and specifications \ No newline at end of file diff --git a/sidebars.ts b/sidebars.ts index 148c2c3575..5536f33185 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -109,7 +109,6 @@ const sidebars: SidebarsConfig = { label: 'Creatives', items: [ 'media-buy/creatives/index', - 'media-buy/creatives/creative-library', ], }, { @@ -153,7 +152,6 @@ const sidebars: SidebarsConfig = { label: 'Task Reference', items: [ 'creative/task-reference/build_creative', - 'creative/task-reference/manage_creative_library', 'creative/task-reference/preview_creative', 'creative/task-reference/list_creative_formats', ], diff --git a/static/schemas/v1/core/creative-library-item.json b/static/schemas/v1/core/creative-library-item.json deleted file mode 100644 index e72f14bb2c..0000000000 --- a/static/schemas/v1/core/creative-library-item.json +++ /dev/null @@ -1,153 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/core/creative-library-item.json", - "title": "Creative Library Item", - "description": "Creative asset as it appears in the centralized library", - "type": "object", - "properties": { - "creative_id": { - "type": "string", - "description": "Unique identifier for the creative" - }, - "name": { - "type": "string", - "description": "Human-readable creative name" - }, - "format": { - "type": "string", - "description": "Creative format type (e.g., video, audio, display)" - }, - "status": { - "$ref": "/schemas/v1/enums/creative-status.json" - }, - "platform_id": { - "type": "string", - "description": "Platform-specific ID assigned to the creative" - }, - "created_date": { - "type": "string", - "format": "date-time", - "description": "When the creative was uploaded to the library" - }, - "last_updated": { - "type": "string", - "format": "date-time", - "description": "When the creative was last modified" - }, - "media_url": { - "type": "string", - "format": "uri", - "description": "URL of the creative file" - }, - "click_url": { - "type": "string", - "format": "uri", - "description": "Landing page URL for the creative" - }, - "duration": { - "type": "number", - "description": "Duration in milliseconds (for video/audio)", - "minimum": 0 - }, - "width": { - "type": "number", - "description": "Width in pixels (for video/display)", - "minimum": 0 - }, - "height": { - "type": "number", - "description": "Height in pixels (for video/display)", - "minimum": 0 - }, - "file_size": { - "type": "integer", - "description": "File size in bytes", - "minimum": 0 - }, - "assignments": { - "type": "array", - "description": "Current package assignments for this creative", - "items": { - "type": "string" - } - }, - "assignment_count": { - "type": "integer", - "description": "Number of active package assignments", - "minimum": 0 - }, - "performance_metrics": { - "type": "object", - "description": "Aggregated performance data across all assignments", - "properties": { - "total_impressions": { - "type": "integer", - "description": "Total impressions delivered", - "minimum": 0 - }, - "total_clicks": { - "type": "integer", - "description": "Total clicks generated", - "minimum": 0 - }, - "average_ctr": { - "type": "number", - "description": "Average click-through rate across assignments", - "minimum": 0, - "maximum": 1 - }, - "last_served": { - "type": "string", - "format": "date-time", - "description": "When this creative last served an impression" - } - }, - "additionalProperties": false - }, - "compliance": { - "type": "object", - "description": "Compliance review status", - "properties": { - "status": { - "type": "string", - "description": "Compliance status", - "enum": ["approved", "pending", "rejected", "flagged"] - }, - "issues": { - "type": "array", - "description": "Array of compliance issues", - "items": { - "type": "string" - } - }, - "reviewed_date": { - "type": "string", - "format": "date-time", - "description": "When compliance review was completed" - } - }, - "required": ["status"], - "additionalProperties": false - }, - "review_feedback": { - "type": "string", - "description": "Latest feedback from platform review" - }, - "tags": { - "type": "array", - "description": "User-defined tags for organization", - "items": { - "type": "string" - } - }, - "assets": { - "type": "array", - "description": "Sub-assets for multi-asset formats like carousels", - "items": { - "$ref": "/schemas/v1/core/sub-asset.json" - } - } - }, - "required": ["creative_id", "name", "format", "status", "created_date"], - "additionalProperties": false -} \ No newline at end of file diff --git a/static/schemas/v1/index.json b/static/schemas/v1/index.json index 23605b5763..2e7da3cb7a 100644 --- a/static/schemas/v1/index.json +++ b/static/schemas/v1/index.json @@ -71,10 +71,6 @@ "$ref": "/schemas/v1/core/creative-assignment.json", "description": "Assignment of a creative asset to a package" }, - "creative-library-item": { - "$ref": "/schemas/v1/core/creative-library-item.json", - "description": "Creative asset as it appears in the centralized library" - }, "creative-manifest": { "$ref": "/schemas/v1/core/creative-manifest.json", "description": "Complete specification of a creative with all assets needed for rendering" @@ -264,16 +260,6 @@ "description": "Response payload for build_creative task" } }, - "manage-creative-library": { - "request": { - "$ref": "/schemas/v1/media-buy/manage-creative-library-request.json", - "description": "Request parameters for managing creative library assets" - }, - "response": { - "$ref": "/schemas/v1/media-buy/manage-creative-library-response.json", - "description": "Response payload for manage_creative_library task" - } - }, "preview-creative": { "request": { "$ref": "/schemas/v1/creative/preview-creative-request.json", diff --git a/static/schemas/v1/media-buy/manage-creative-library-request.json b/static/schemas/v1/media-buy/manage-creative-library-request.json deleted file mode 100644 index 032fac08d6..0000000000 --- a/static/schemas/v1/media-buy/manage-creative-library-request.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/manage-creative-library-request.json", - "title": "Manage Creative Library Request", - "description": "Request parameters for managing creative library assets", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version for this request", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "default": "1.6.0" - }, - "action": { - "type": "string", - "enum": ["search", "upload", "tag", "organize", "get_details"], - "description": "The management action to perform" - }, - "query": { - "type": "string", - "description": "Natural language search query (for search action)" - }, - "asset": { - "$ref": "/schemas/v1/core/creative-asset.json", - "description": "Asset to upload or update (for upload/tag actions)" - }, - "asset_id": { - "type": "string", - "description": "ID of existing asset to operate on (for tag/organize/get_details actions)" - }, - "tags": { - "type": "array", - "items": {"type": "string"}, - "description": "Tags to add or update for the asset" - }, - "organization": { - "type": "object", - "description": "Organization structure for assets", - "properties": { - "folder": {"type": "string"}, - "campaign_association": {"type": "string"}, - "priority": { - "type": "string", - "enum": ["high", "medium", "low"] - } - }, - "additionalProperties": false - }, - "filters": { - "type": "object", - "description": "Filters for search operations", - "properties": { - "asset_types": { - "type": "array", - "items": {"type": "string"}, - "description": "Filter by asset types (image, video, text, etc.)" - }, - "tags": { - "type": "array", - "items": {"type": "string"}, - "description": "Filter by tags" - }, - "date_range": { - "type": "object", - "properties": { - "start": {"type": "string", "format": "date"}, - "end": {"type": "string", "format": "date"} - } - }, - "format_types": { - "type": "array", - "items": {"type": "string"}, - "description": "Filter by compatible format types" - } - }, - "additionalProperties": false - } - }, - "required": ["action"], - "allOf": [ - { - "if": { - "properties": {"action": {"const": "search"}} - }, - "then": { - "anyOf": [ - {"required": ["query"]}, - {"required": ["filters"]} - ] - } - }, - { - "if": { - "properties": {"action": {"const": "upload"}} - }, - "then": { - "required": ["asset"] - } - }, - { - "if": { - "properties": {"action": {"enum": ["tag", "organize", "get_details"]}} - }, - "then": { - "required": ["asset_id"] - } - } - ], - "additionalProperties": false -} \ No newline at end of file diff --git a/static/schemas/v1/media-buy/manage-creative-library-response.json b/static/schemas/v1/media-buy/manage-creative-library-response.json deleted file mode 100644 index 30029baee0..0000000000 --- a/static/schemas/v1/media-buy/manage-creative-library-response.json +++ /dev/null @@ -1,164 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/v1/media-buy/manage-creative-library-response.json", - "title": "Manage Creative Library Response", - "description": "Response payload for manage_creative_library task", - "type": "object", - "properties": { - "adcp_version": { - "type": "string", - "description": "AdCP schema version used for this response", - "pattern": "^\\d+\\.\\d+\\.\\d+$" - }, - "action": { - "type": "string", - "enum": ["search", "upload", "tag", "organize", "get_details"], - "description": "The management action that was performed" - }, - "result": { - "type": "object", - "description": "Action-specific result data" - } - }, - "allOf": [ - { - "if": { - "properties": {"action": {"const": "search"}} - }, - "then": { - "properties": { - "result": { - "type": "object", - "properties": { - "assets": { - "type": "array", - "description": "Matching creative assets", - "items": { - "$ref": "/schemas/v1/core/creative-asset.json" - } - }, - "total_count": { - "type": "integer", - "description": "Total number of matching assets" - }, - "suggestions": { - "type": "array", - "description": "Search refinement suggestions", - "items": { - "type": "object", - "properties": { - "type": {"type": "string"}, - "description": {"type": "string"}, - "query": {"type": "string"} - } - } - } - }, - "required": ["assets", "total_count"] - } - } - } - }, - { - "if": { - "properties": {"action": {"const": "upload"}} - }, - "then": { - "properties": { - "result": { - "type": "object", - "properties": { - "asset": { - "$ref": "/schemas/v1/core/creative-asset.json", - "description": "The uploaded asset with assigned ID" - }, - "upload_url": { - "type": "string", - "description": "URL for direct file upload if needed" - }, - "processing_status": { - "type": "string", - "enum": ["uploaded", "processing", "ready", "failed"], - "description": "Current processing status of the asset" - } - }, - "required": ["asset", "processing_status"] - } - } - } - }, - { - "if": { - "properties": {"action": {"enum": ["tag", "organize"]}} - }, - "then": { - "properties": { - "result": { - "type": "object", - "properties": { - "asset": { - "$ref": "/schemas/v1/core/creative-asset.json", - "description": "The updated asset" - }, - "success": { - "type": "boolean", - "description": "Whether the operation was successful" - } - }, - "required": ["asset", "success"] - } - } - } - }, - { - "if": { - "properties": {"action": {"const": "get_details"}} - }, - "then": { - "properties": { - "result": { - "type": "object", - "properties": { - "asset": { - "$ref": "/schemas/v1/core/creative-asset.json", - "description": "Detailed asset information" - }, - "usage_history": { - "type": "array", - "description": "History of where this asset has been used", - "items": { - "type": "object", - "properties": { - "campaign_id": {"type": "string"}, - "campaign_name": {"type": "string"}, - "usage_date": {"type": "string", "format": "date-time"}, - "performance_metrics": {"type": "object"} - } - } - }, - "related_assets": { - "type": "array", - "description": "Related or similar assets", - "items": { - "$ref": "/schemas/v1/core/creative-asset.json" - } - } - }, - "required": ["asset"] - } - } - } - } - ], - "properties": { - "errors": { - "type": "array", - "description": "Task-specific errors and warnings", - "items": { - "$ref": "/schemas/v1/core/error.json" - } - } - }, - "required": ["adcp_version", "action", "result"], - "additionalProperties": false -} \ No newline at end of file From 76434d845d7240c168a52ce243062fe1d42ae17c Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 11 Oct 2025 11:04:01 -0400 Subject: [PATCH 4/4] docs: clarify UNION logic for promoted products selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update promoted-products schema to explicitly document that multiple selection methods (skus, tags, category) use UNION (OR) logic rather than INTERSECTION (AND). When combining selection criteria: - skus: ["SKU-123"] - tags: ["organic"] - category: "food" Products are selected as: (SKU-123) OR (tagged organic) OR (in food category) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- static/schemas/v1/core/promoted-products.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/schemas/v1/core/promoted-products.json b/static/schemas/v1/core/promoted-products.json index ee790fa989..74ac1d3ec9 100644 --- a/static/schemas/v1/core/promoted-products.json +++ b/static/schemas/v1/core/promoted-products.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "/schemas/v1/core/promoted-products.json", "title": "Promoted Products", - "description": "Specification of products or offerings being promoted in a campaign. Supports multiple selection methods that can be combined: direct SKUs, tag-based filtering, category selection, natural language queries, and inline offering definitions for non-commerce campaigns.", + "description": "Specification of products or offerings being promoted in a campaign. Supports multiple selection methods that can be combined using UNION (OR) logic: direct SKUs, tag-based filtering, category selection, natural language queries, and inline offering definitions for non-commerce campaigns. When multiple selection methods are provided, products matching ANY of the criteria are selected (logical OR, not AND).", "type": "object", "properties": { "skus": { @@ -113,7 +113,7 @@ { "tags": ["organic", "sauces"], "category": "food/condiments", - "description": "Combine tags and category for refined selection" + "description": "UNION selection: products tagged 'organic' OR 'sauces' OR in 'food/condiments' category" }, { "query": "all Kraft Heinz pasta sauces under $5",