adcp 2.12.2__py3-none-any.whl → 2.14.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- adcp/__init__.py +14 -1
- adcp/adagents.py +53 -9
- adcp/client.py +361 -57
- adcp/protocols/mcp.py +1 -3
- adcp/types/__init__.py +9 -33
- adcp/types/_generated.py +82 -13
- adcp/types/aliases.py +23 -0
- adcp/types/base.py +193 -0
- adcp/types/generated_poc/adagents.py +9 -13
- adcp/types/generated_poc/core/activation_key.py +12 -2
- adcp/types/generated_poc/core/assets/daast_asset.py +12 -2
- adcp/types/generated_poc/core/assets/image_asset.py +9 -5
- adcp/types/generated_poc/core/assets/vast_asset.py +12 -2
- adcp/types/generated_poc/core/assets/video_asset.py +9 -5
- adcp/types/generated_poc/core/async_response_data.py +72 -0
- adcp/types/generated_poc/core/brand_manifest_ref.py +35 -0
- adcp/types/generated_poc/core/creative_asset.py +4 -6
- adcp/types/generated_poc/core/creative_manifest.py +4 -6
- adcp/types/generated_poc/core/deployment.py +16 -8
- adcp/types/generated_poc/core/destination.py +12 -2
- adcp/types/generated_poc/core/format.py +3 -3
- adcp/types/generated_poc/core/{webhook_payload.py → mcp_webhook_payload.py} +8 -33
- adcp/types/generated_poc/core/pricing_option.py +51 -0
- adcp/types/generated_poc/core/product.py +4 -29
- adcp/types/generated_poc/core/promoted_offerings.py +5 -21
- adcp/types/generated_poc/core/property.py +4 -6
- adcp/types/generated_poc/core/publisher_property_selector.py +15 -2
- adcp/types/generated_poc/core/push_notification_config.py +1 -4
- adcp/types/generated_poc/core/start_timing.py +18 -0
- adcp/types/generated_poc/core/sub_asset.py +12 -2
- adcp/types/generated_poc/creative/preview_creative_response.py +3 -14
- adcp/types/generated_poc/creative/preview_render.py +3 -11
- adcp/types/generated_poc/media_buy/create_media_buy_async_response_input_required.py +37 -0
- adcp/types/generated_poc/media_buy/create_media_buy_async_response_submitted.py +19 -0
- adcp/types/generated_poc/media_buy/create_media_buy_async_response_working.py +31 -0
- adcp/types/generated_poc/media_buy/create_media_buy_request.py +7 -26
- adcp/types/generated_poc/media_buy/get_media_buy_delivery_response.py +4 -2
- adcp/types/generated_poc/media_buy/get_products_async_response_input_required.py +38 -0
- adcp/types/generated_poc/media_buy/get_products_async_response_submitted.py +24 -0
- adcp/types/generated_poc/media_buy/get_products_async_response_working.py +35 -0
- adcp/types/generated_poc/media_buy/get_products_request.py +5 -20
- adcp/types/generated_poc/media_buy/list_creatives_response.py +5 -7
- adcp/types/generated_poc/media_buy/sync_creatives_async_response_input_required.py +31 -0
- adcp/types/generated_poc/media_buy/sync_creatives_async_response_submitted.py +19 -0
- adcp/types/generated_poc/media_buy/sync_creatives_async_response_working.py +37 -0
- adcp/types/generated_poc/media_buy/update_media_buy_async_response_input_required.py +30 -0
- adcp/types/generated_poc/media_buy/update_media_buy_async_response_submitted.py +19 -0
- adcp/types/generated_poc/media_buy/update_media_buy_async_response_working.py +31 -0
- adcp/types/generated_poc/media_buy/update_media_buy_request.py +4 -14
- adcp/types/generated_poc/signals/activate_signal_request.py +2 -2
- adcp/types/generated_poc/signals/activate_signal_response.py +2 -2
- adcp/types/generated_poc/signals/get_signals_request.py +2 -2
- adcp/types/generated_poc/signals/get_signals_response.py +2 -3
- adcp/utils/preview_cache.py +6 -4
- adcp/webhooks.py +508 -0
- {adcp-2.12.2.dist-info → adcp-2.14.0.dist-info}/METADATA +2 -2
- {adcp-2.12.2.dist-info → adcp-2.14.0.dist-info}/RECORD +61 -45
- adcp/types/generated_poc/core/dimensions.py +0 -18
- {adcp-2.12.2.dist-info → adcp-2.14.0.dist-info}/WHEEL +0 -0
- {adcp-2.12.2.dist-info → adcp-2.14.0.dist-info}/entry_points.txt +0 -0
- {adcp-2.12.2.dist-info → adcp-2.14.0.dist-info}/licenses/LICENSE +0 -0
- {adcp-2.12.2.dist-info → adcp-2.14.0.dist-info}/top_level.txt +0 -0
adcp/types/base.py
CHANGED
|
@@ -2,10 +2,189 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
"""Base model for AdCP types with spec-compliant serialization."""
|
|
4
4
|
|
|
5
|
+
from collections.abc import Callable
|
|
5
6
|
from typing import Any
|
|
6
7
|
|
|
7
8
|
from pydantic import BaseModel
|
|
8
9
|
|
|
10
|
+
# Type alias to shorten long type annotations
|
|
11
|
+
MessageFormatter = Callable[[Any], str]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _pluralize(count: int, singular: str, plural: str | None = None) -> str:
|
|
15
|
+
"""Return singular or plural form based on count."""
|
|
16
|
+
if count == 1:
|
|
17
|
+
return singular
|
|
18
|
+
return plural if plural else f"{singular}s"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Registry of human-readable message formatters for response types.
|
|
22
|
+
# Key is the class name, value is a callable that takes the instance and returns a message.
|
|
23
|
+
_RESPONSE_MESSAGE_REGISTRY: dict[str, MessageFormatter] = {}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _register_response_message(cls_name: str) -> Callable[[MessageFormatter], MessageFormatter]:
|
|
27
|
+
"""Decorator to register a message formatter for a response type."""
|
|
28
|
+
|
|
29
|
+
def decorator(func: MessageFormatter) -> MessageFormatter:
|
|
30
|
+
_RESPONSE_MESSAGE_REGISTRY[cls_name] = func
|
|
31
|
+
return func
|
|
32
|
+
|
|
33
|
+
return decorator
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Response message formatters
|
|
37
|
+
@_register_response_message("GetProductsResponse")
|
|
38
|
+
def _get_products_message(self: Any) -> str:
|
|
39
|
+
products = getattr(self, "products", None)
|
|
40
|
+
if products is None or len(products) == 0:
|
|
41
|
+
return "No products matched your requirements."
|
|
42
|
+
count = len(products)
|
|
43
|
+
return f"Found {count} {_pluralize(count, 'product')} matching your requirements."
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@_register_response_message("ListCreativeFormatsResponse")
|
|
47
|
+
def _list_creative_formats_message(self: Any) -> str:
|
|
48
|
+
formats = getattr(self, "formats", None)
|
|
49
|
+
if formats is None:
|
|
50
|
+
return "No creative formats found."
|
|
51
|
+
count = len(formats)
|
|
52
|
+
return f"Found {count} supported creative {_pluralize(count, 'format')}."
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@_register_response_message("GetSignalsResponse")
|
|
56
|
+
def _get_signals_message(self: Any) -> str:
|
|
57
|
+
signals = getattr(self, "signals", None)
|
|
58
|
+
if signals is None:
|
|
59
|
+
return "No signals found."
|
|
60
|
+
count = len(signals)
|
|
61
|
+
return f"Found {count} {_pluralize(count, 'signal')} available for targeting."
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@_register_response_message("ListAuthorizedPropertiesResponse")
|
|
65
|
+
def _list_authorized_properties_message(self: Any) -> str:
|
|
66
|
+
domains = getattr(self, "publisher_domains", None)
|
|
67
|
+
if domains is None:
|
|
68
|
+
return "No authorized properties found."
|
|
69
|
+
count = len(domains)
|
|
70
|
+
return f"Authorized to represent {count} publisher {_pluralize(count, 'domain')}."
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@_register_response_message("ListCreativesResponse")
|
|
74
|
+
def _list_creatives_message(self: Any) -> str:
|
|
75
|
+
creatives = getattr(self, "creatives", None)
|
|
76
|
+
if creatives is None:
|
|
77
|
+
return "No creatives found."
|
|
78
|
+
count = len(creatives)
|
|
79
|
+
return f"Found {count} {_pluralize(count, 'creative')} in the system."
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@_register_response_message("CreateMediaBuyResponse1")
|
|
83
|
+
def _create_media_buy_success_message(self: Any) -> str:
|
|
84
|
+
media_buy_id = getattr(self, "media_buy_id", None)
|
|
85
|
+
packages = getattr(self, "packages", None)
|
|
86
|
+
package_count = len(packages) if packages else 0
|
|
87
|
+
return (
|
|
88
|
+
f"Media buy {media_buy_id} created with "
|
|
89
|
+
f"{package_count} {_pluralize(package_count, 'package')}."
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@_register_response_message("CreateMediaBuyResponse2")
|
|
94
|
+
def _create_media_buy_error_message(self: Any) -> str:
|
|
95
|
+
errors = getattr(self, "errors", None)
|
|
96
|
+
error_count = len(errors) if errors else 0
|
|
97
|
+
return f"Media buy creation failed with {error_count} {_pluralize(error_count, 'error')}."
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@_register_response_message("UpdateMediaBuyResponse1")
|
|
101
|
+
def _update_media_buy_success_message(self: Any) -> str:
|
|
102
|
+
media_buy_id = getattr(self, "media_buy_id", None)
|
|
103
|
+
return f"Media buy {media_buy_id} updated successfully."
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@_register_response_message("UpdateMediaBuyResponse2")
|
|
107
|
+
def _update_media_buy_error_message(self: Any) -> str:
|
|
108
|
+
errors = getattr(self, "errors", None)
|
|
109
|
+
error_count = len(errors) if errors else 0
|
|
110
|
+
return f"Media buy update failed with {error_count} {_pluralize(error_count, 'error')}."
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@_register_response_message("SyncCreativesResponse1")
|
|
114
|
+
def _sync_creatives_success_message(self: Any) -> str:
|
|
115
|
+
creatives = getattr(self, "creatives", None)
|
|
116
|
+
creative_count = len(creatives) if creatives else 0
|
|
117
|
+
return f"Synced {creative_count} {_pluralize(creative_count, 'creative')} successfully."
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@_register_response_message("SyncCreativesResponse2")
|
|
121
|
+
def _sync_creatives_error_message(self: Any) -> str:
|
|
122
|
+
errors = getattr(self, "errors", None)
|
|
123
|
+
error_count = len(errors) if errors else 0
|
|
124
|
+
return f"Creative sync failed with {error_count} {_pluralize(error_count, 'error')}."
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@_register_response_message("ActivateSignalResponse1")
|
|
128
|
+
def _activate_signal_success_message(self: Any) -> str:
|
|
129
|
+
return "Signal activated successfully."
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@_register_response_message("ActivateSignalResponse2")
|
|
133
|
+
def _activate_signal_error_message(self: Any) -> str:
|
|
134
|
+
errors = getattr(self, "errors", None)
|
|
135
|
+
error_count = len(errors) if errors else 0
|
|
136
|
+
return f"Signal activation failed with {error_count} {_pluralize(error_count, 'error')}."
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@_register_response_message("PreviewCreativeResponse1")
|
|
140
|
+
def _preview_creative_single_message(self: Any) -> str:
|
|
141
|
+
previews = getattr(self, "previews", None)
|
|
142
|
+
preview_count = len(previews) if previews else 0
|
|
143
|
+
return f"Generated {preview_count} {_pluralize(preview_count, 'preview')}."
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@_register_response_message("PreviewCreativeResponse2")
|
|
147
|
+
def _preview_creative_batch_message(self: Any) -> str:
|
|
148
|
+
results = getattr(self, "results", None)
|
|
149
|
+
result_count = len(results) if results else 0
|
|
150
|
+
return f"Generated previews for {result_count} {_pluralize(result_count, 'manifest')}."
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@_register_response_message("BuildCreativeResponse1")
|
|
154
|
+
def _build_creative_success_message(self: Any) -> str:
|
|
155
|
+
return "Creative built successfully."
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@_register_response_message("BuildCreativeResponse2")
|
|
159
|
+
def _build_creative_error_message(self: Any) -> str:
|
|
160
|
+
errors = getattr(self, "errors", None)
|
|
161
|
+
error_count = len(errors) if errors else 0
|
|
162
|
+
return f"Creative build failed with {error_count} {_pluralize(error_count, 'error')}."
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@_register_response_message("GetMediaBuyDeliveryResponse")
|
|
166
|
+
def _get_media_buy_delivery_message(self: Any) -> str:
|
|
167
|
+
deliveries = getattr(self, "media_buy_deliveries", None)
|
|
168
|
+
if deliveries is None:
|
|
169
|
+
return "No delivery data available."
|
|
170
|
+
count = len(deliveries)
|
|
171
|
+
return f"Retrieved delivery data for {count} media {_pluralize(count, 'buy', 'buys')}."
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@_register_response_message("ProvidePerformanceFeedbackResponse1")
|
|
175
|
+
def _provide_performance_feedback_success_message(self: Any) -> str:
|
|
176
|
+
return "Performance feedback recorded successfully."
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@_register_response_message("ProvidePerformanceFeedbackResponse2")
|
|
180
|
+
def _provide_performance_feedback_error_message(self: Any) -> str:
|
|
181
|
+
errors = getattr(self, "errors", None)
|
|
182
|
+
error_count = len(errors) if errors else 0
|
|
183
|
+
return (
|
|
184
|
+
f"Performance feedback recording failed with "
|
|
185
|
+
f"{error_count} {_pluralize(error_count, 'error')}."
|
|
186
|
+
)
|
|
187
|
+
|
|
9
188
|
|
|
10
189
|
class AdCPBaseModel(BaseModel):
|
|
11
190
|
"""Base model for AdCP types with spec-compliant serialization.
|
|
@@ -24,3 +203,17 @@ class AdCPBaseModel(BaseModel):
|
|
|
24
203
|
if "exclude_none" not in kwargs:
|
|
25
204
|
kwargs["exclude_none"] = True
|
|
26
205
|
return super().model_dump_json(**kwargs)
|
|
206
|
+
|
|
207
|
+
def summary(self) -> str:
|
|
208
|
+
"""Human-readable summary for protocol responses.
|
|
209
|
+
|
|
210
|
+
Returns a standardized human-readable message suitable for MCP tool
|
|
211
|
+
results, A2A task communications, and REST API responses.
|
|
212
|
+
|
|
213
|
+
For types without a registered formatter, returns a generic message
|
|
214
|
+
with the class name.
|
|
215
|
+
"""
|
|
216
|
+
formatter = _RESPONSE_MESSAGE_REGISTRY.get(self.__class__.__name__)
|
|
217
|
+
if formatter:
|
|
218
|
+
return formatter(self)
|
|
219
|
+
return f"{self.__class__.__name__} response"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: adagents.json
|
|
3
|
-
# timestamp: 2025-
|
|
3
|
+
# timestamp: 2025-12-18T20:00:24+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
@@ -19,7 +19,7 @@ class AuthorizedSalesAgents1(AdCPBaseModel):
|
|
|
19
19
|
field_schema: Annotated[
|
|
20
20
|
str | None,
|
|
21
21
|
Field(alias='$schema', description='JSON Schema identifier for this adagents.json file'),
|
|
22
|
-
] =
|
|
22
|
+
] = None
|
|
23
23
|
authoritative_location: Annotated[
|
|
24
24
|
AnyUrl,
|
|
25
25
|
Field(
|
|
@@ -156,11 +156,7 @@ class AuthorizedAgents3(AdCPBaseModel):
|
|
|
156
156
|
),
|
|
157
157
|
]
|
|
158
158
|
publisher_properties: Annotated[
|
|
159
|
-
list[
|
|
160
|
-
publisher_property_selector.PublisherPropertySelector1
|
|
161
|
-
| publisher_property_selector.PublisherPropertySelector2
|
|
162
|
-
| publisher_property_selector.PublisherPropertySelector3
|
|
163
|
-
],
|
|
159
|
+
list[publisher_property_selector.PublisherPropertySelector],
|
|
164
160
|
Field(
|
|
165
161
|
description='Properties from other publisher domains this agent is authorized for. Each entry specifies a publisher domain and which of their properties this agent can sell',
|
|
166
162
|
min_length=1,
|
|
@@ -202,7 +198,7 @@ class AuthorizedSalesAgents2(AdCPBaseModel):
|
|
|
202
198
|
field_schema: Annotated[
|
|
203
199
|
str | None,
|
|
204
200
|
Field(alias='$schema', description='JSON Schema identifier for this adagents.json file'),
|
|
205
|
-
] =
|
|
201
|
+
] = None
|
|
206
202
|
authorized_agents: Annotated[
|
|
207
203
|
list[AuthorizedAgents | AuthorizedAgents1 | AuthorizedAgents2 | AuthorizedAgents3],
|
|
208
204
|
Field(
|
|
@@ -242,12 +238,12 @@ class AuthorizedSalesAgents(RootModel[AuthorizedSalesAgents1 | AuthorizedSalesAg
|
|
|
242
238
|
description='Declaration of authorized sales agents for advertising inventory. Hosted at /.well-known/adagents.json on publisher domains. Can either contain the full structure inline or reference an authoritative URL.',
|
|
243
239
|
examples=[
|
|
244
240
|
{
|
|
245
|
-
'$schema': '
|
|
241
|
+
'$schema': '/schemas/latest/adagents.json',
|
|
246
242
|
'authoritative_location': 'https://cdn.example.com/adagents/v2/adagents.json',
|
|
247
243
|
'last_updated': '2025-01-15T10:00:00Z',
|
|
248
244
|
},
|
|
249
245
|
{
|
|
250
|
-
'$schema': '
|
|
246
|
+
'$schema': '/schemas/latest/adagents.json',
|
|
251
247
|
'authorized_agents': [
|
|
252
248
|
{
|
|
253
249
|
'authorization_type': 'property_tags',
|
|
@@ -273,7 +269,7 @@ class AuthorizedSalesAgents(RootModel[AuthorizedSalesAgents1 | AuthorizedSalesAg
|
|
|
273
269
|
},
|
|
274
270
|
},
|
|
275
271
|
{
|
|
276
|
-
'$schema': '
|
|
272
|
+
'$schema': '/schemas/latest/adagents.json',
|
|
277
273
|
'authorized_agents': [
|
|
278
274
|
{
|
|
279
275
|
'authorization_type': 'property_tags',
|
|
@@ -338,7 +334,7 @@ class AuthorizedSalesAgents(RootModel[AuthorizedSalesAgents1 | AuthorizedSalesAg
|
|
|
338
334
|
},
|
|
339
335
|
},
|
|
340
336
|
{
|
|
341
|
-
'$schema': '
|
|
337
|
+
'$schema': '/schemas/latest/adagents.json',
|
|
342
338
|
'authorized_agents': [
|
|
343
339
|
{
|
|
344
340
|
'authorization_type': 'property_tags',
|
|
@@ -366,7 +362,7 @@ class AuthorizedSalesAgents(RootModel[AuthorizedSalesAgents1 | AuthorizedSalesAg
|
|
|
366
362
|
},
|
|
367
363
|
},
|
|
368
364
|
{
|
|
369
|
-
'$schema': '
|
|
365
|
+
'$schema': '/schemas/latest/adagents.json',
|
|
370
366
|
'authorized_agents': [
|
|
371
367
|
{
|
|
372
368
|
'authorization_type': 'publisher_properties',
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: core/activation_key.json
|
|
3
|
-
# timestamp: 2025-
|
|
3
|
+
# timestamp: 2025-12-11T15:09:37+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
from typing import Annotated, Literal
|
|
8
8
|
|
|
9
9
|
from adcp.types.base import AdCPBaseModel
|
|
10
|
-
from pydantic import ConfigDict, Field
|
|
10
|
+
from pydantic import ConfigDict, Field, RootModel
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class ActivationKey1(AdCPBaseModel):
|
|
@@ -28,3 +28,13 @@ class ActivationKey2(AdCPBaseModel):
|
|
|
28
28
|
key: Annotated[str, Field(description='The targeting parameter key')]
|
|
29
29
|
type: Annotated[Literal['key_value'], Field(description='Key-value pair based targeting')]
|
|
30
30
|
value: Annotated[str, Field(description='The targeting parameter value')]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ActivationKey(RootModel[ActivationKey1 | ActivationKey2]):
|
|
34
|
+
root: Annotated[
|
|
35
|
+
ActivationKey1 | ActivationKey2,
|
|
36
|
+
Field(
|
|
37
|
+
description="Universal identifier for using a signal on a destination platform. Can be either a segment ID or a key-value pair depending on the platform's targeting mechanism.",
|
|
38
|
+
title='Activation Key',
|
|
39
|
+
),
|
|
40
|
+
]
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: core/assets/daast_asset.json
|
|
3
|
-
# timestamp: 2025-
|
|
3
|
+
# timestamp: 2025-12-11T15:09:37+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
from typing import Annotated, Literal
|
|
8
8
|
|
|
9
9
|
from adcp.types.base import AdCPBaseModel
|
|
10
|
-
from pydantic import AnyUrl, ConfigDict, Field
|
|
10
|
+
from pydantic import AnyUrl, ConfigDict, Field, RootModel
|
|
11
11
|
|
|
12
12
|
from ...enums import daast_tracking_event
|
|
13
13
|
from ...enums import daast_version as daast_version_1
|
|
@@ -59,3 +59,13 @@ class DaastAsset2(AdCPBaseModel):
|
|
|
59
59
|
list[daast_tracking_event.DaastTrackingEvent] | None,
|
|
60
60
|
Field(description='Tracking events supported by this DAAST tag'),
|
|
61
61
|
] = None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class DaastAsset(RootModel[DaastAsset1 | DaastAsset2]):
|
|
65
|
+
root: Annotated[
|
|
66
|
+
DaastAsset1 | DaastAsset2,
|
|
67
|
+
Field(
|
|
68
|
+
description='DAAST (Digital Audio Ad Serving Template) tag for third-party audio ad serving',
|
|
69
|
+
title='DAAST Asset',
|
|
70
|
+
),
|
|
71
|
+
]
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: core/assets/image_asset.json
|
|
3
|
-
# timestamp: 2025-
|
|
3
|
+
# timestamp: 2025-12-18T20:00:24+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
from typing import Annotated
|
|
8
8
|
|
|
9
|
-
from
|
|
9
|
+
from adcp.types.base import AdCPBaseModel
|
|
10
|
+
from pydantic import AnyUrl, ConfigDict, Field
|
|
10
11
|
|
|
11
|
-
from ..dimensions import Dimensions
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
class ImageAsset(AdCPBaseModel):
|
|
14
|
+
model_config = ConfigDict(
|
|
15
|
+
extra='forbid',
|
|
16
|
+
)
|
|
15
17
|
alt_text: Annotated[str | None, Field(description='Alternative text for accessibility')] = None
|
|
16
18
|
format: Annotated[
|
|
17
19
|
str | None, Field(description='Image file format (jpg, png, gif, webp, etc.)')
|
|
18
20
|
] = None
|
|
21
|
+
height: Annotated[int, Field(description='Height in pixels', ge=1)]
|
|
19
22
|
url: Annotated[AnyUrl, Field(description='URL to the image asset')]
|
|
23
|
+
width: Annotated[int, Field(description='Width in pixels', ge=1)]
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: core/assets/vast_asset.json
|
|
3
|
-
# timestamp: 2025-
|
|
3
|
+
# timestamp: 2025-12-11T15:09:37+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
from typing import Annotated, Literal
|
|
8
8
|
|
|
9
9
|
from adcp.types.base import AdCPBaseModel
|
|
10
|
-
from pydantic import AnyUrl, ConfigDict, Field
|
|
10
|
+
from pydantic import AnyUrl, ConfigDict, Field, RootModel
|
|
11
11
|
|
|
12
12
|
from ...enums import vast_tracking_event
|
|
13
13
|
from ...enums import vast_version as vast_version_1
|
|
@@ -61,3 +61,13 @@ class VastAsset2(AdCPBaseModel):
|
|
|
61
61
|
bool | None,
|
|
62
62
|
Field(description='Whether VPAID (Video Player-Ad Interface Definition) is supported'),
|
|
63
63
|
] = None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class VastAsset(RootModel[VastAsset1 | VastAsset2]):
|
|
67
|
+
root: Annotated[
|
|
68
|
+
VastAsset1 | VastAsset2,
|
|
69
|
+
Field(
|
|
70
|
+
description='VAST (Video Ad Serving Template) tag for third-party video ad serving',
|
|
71
|
+
title='VAST Asset',
|
|
72
|
+
),
|
|
73
|
+
]
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: core/assets/video_asset.json
|
|
3
|
-
# timestamp: 2025-
|
|
3
|
+
# timestamp: 2025-12-18T20:00:24+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
from typing import Annotated
|
|
8
8
|
|
|
9
|
-
from
|
|
9
|
+
from adcp.types.base import AdCPBaseModel
|
|
10
|
+
from pydantic import AnyUrl, ConfigDict, Field
|
|
10
11
|
|
|
11
|
-
from ..dimensions import Dimensions
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
class VideoAsset(AdCPBaseModel):
|
|
14
|
+
model_config = ConfigDict(
|
|
15
|
+
extra='forbid',
|
|
16
|
+
)
|
|
15
17
|
bitrate_kbps: Annotated[
|
|
16
18
|
int | None, Field(description='Video bitrate in kilobits per second', ge=1)
|
|
17
19
|
] = None
|
|
@@ -21,4 +23,6 @@ class VideoAsset(Dimensions):
|
|
|
21
23
|
format: Annotated[str | None, Field(description='Video file format (mp4, webm, mov, etc.)')] = (
|
|
22
24
|
None
|
|
23
25
|
)
|
|
26
|
+
height: Annotated[int, Field(description='Height in pixels', ge=1)]
|
|
24
27
|
url: Annotated[AnyUrl, Field(description='URL to the video asset')]
|
|
28
|
+
width: Annotated[int, Field(description='Width in pixels', ge=1)]
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# generated by datamodel-codegen:
|
|
2
|
+
# filename: core/async_response_data.json
|
|
3
|
+
# timestamp: 2025-12-11T15:09:37+00:00
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
|
|
9
|
+
from pydantic import Field, RootModel
|
|
10
|
+
|
|
11
|
+
from ..media_buy import (
|
|
12
|
+
create_media_buy_async_response_input_required,
|
|
13
|
+
create_media_buy_async_response_submitted,
|
|
14
|
+
create_media_buy_async_response_working,
|
|
15
|
+
create_media_buy_response,
|
|
16
|
+
get_products_async_response_input_required,
|
|
17
|
+
get_products_async_response_submitted,
|
|
18
|
+
get_products_async_response_working,
|
|
19
|
+
get_products_response,
|
|
20
|
+
sync_creatives_async_response_input_required,
|
|
21
|
+
sync_creatives_async_response_submitted,
|
|
22
|
+
sync_creatives_async_response_working,
|
|
23
|
+
sync_creatives_response,
|
|
24
|
+
update_media_buy_async_response_input_required,
|
|
25
|
+
update_media_buy_async_response_submitted,
|
|
26
|
+
update_media_buy_async_response_working,
|
|
27
|
+
update_media_buy_response,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AdcpAsyncResponseData(
|
|
32
|
+
RootModel[
|
|
33
|
+
get_products_response.GetProductsResponse
|
|
34
|
+
| get_products_async_response_working.GetProductsWorking
|
|
35
|
+
| get_products_async_response_input_required.GetProductsInputRequired
|
|
36
|
+
| get_products_async_response_submitted.GetProductsSubmitted
|
|
37
|
+
| create_media_buy_response.CreateMediaBuyResponse
|
|
38
|
+
| create_media_buy_async_response_working.CreateMediaBuyWorking
|
|
39
|
+
| create_media_buy_async_response_input_required.CreateMediaBuyInputRequired
|
|
40
|
+
| create_media_buy_async_response_submitted.CreateMediaBuySubmitted
|
|
41
|
+
| update_media_buy_response.UpdateMediaBuyResponse
|
|
42
|
+
| update_media_buy_async_response_working.UpdateMediaBuyWorking
|
|
43
|
+
| update_media_buy_async_response_input_required.UpdateMediaBuyInputRequired
|
|
44
|
+
| update_media_buy_async_response_submitted.UpdateMediaBuySubmitted
|
|
45
|
+
| sync_creatives_response.SyncCreativesResponse
|
|
46
|
+
| sync_creatives_async_response_working.SyncCreativesWorking
|
|
47
|
+
| sync_creatives_async_response_input_required.SyncCreativesInputRequired
|
|
48
|
+
| sync_creatives_async_response_submitted.SyncCreativesSubmitted
|
|
49
|
+
]
|
|
50
|
+
):
|
|
51
|
+
root: Annotated[
|
|
52
|
+
get_products_response.GetProductsResponse
|
|
53
|
+
| get_products_async_response_working.GetProductsWorking
|
|
54
|
+
| get_products_async_response_input_required.GetProductsInputRequired
|
|
55
|
+
| get_products_async_response_submitted.GetProductsSubmitted
|
|
56
|
+
| create_media_buy_response.CreateMediaBuyResponse
|
|
57
|
+
| create_media_buy_async_response_working.CreateMediaBuyWorking
|
|
58
|
+
| create_media_buy_async_response_input_required.CreateMediaBuyInputRequired
|
|
59
|
+
| create_media_buy_async_response_submitted.CreateMediaBuySubmitted
|
|
60
|
+
| update_media_buy_response.UpdateMediaBuyResponse
|
|
61
|
+
| update_media_buy_async_response_working.UpdateMediaBuyWorking
|
|
62
|
+
| update_media_buy_async_response_input_required.UpdateMediaBuyInputRequired
|
|
63
|
+
| update_media_buy_async_response_submitted.UpdateMediaBuySubmitted
|
|
64
|
+
| sync_creatives_response.SyncCreativesResponse
|
|
65
|
+
| sync_creatives_async_response_working.SyncCreativesWorking
|
|
66
|
+
| sync_creatives_async_response_input_required.SyncCreativesInputRequired
|
|
67
|
+
| sync_creatives_async_response_submitted.SyncCreativesSubmitted,
|
|
68
|
+
Field(
|
|
69
|
+
description='Union of all possible data payloads for async task webhook responses. For completed/failed statuses, use the main task response schema. For working/input-required/submitted, use the status-specific schemas.',
|
|
70
|
+
title='AdCP Async Response Data',
|
|
71
|
+
),
|
|
72
|
+
]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# generated by datamodel-codegen:
|
|
2
|
+
# filename: core/brand_manifest_ref.json
|
|
3
|
+
# timestamp: 2025-12-11T15:09:37+00:00
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
|
|
9
|
+
from pydantic import AnyUrl, Field, RootModel
|
|
10
|
+
|
|
11
|
+
from . import brand_manifest
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BrandManifestReference(RootModel[brand_manifest.BrandManifest | AnyUrl]):
|
|
15
|
+
root: Annotated[
|
|
16
|
+
brand_manifest.BrandManifest | AnyUrl,
|
|
17
|
+
Field(
|
|
18
|
+
description='Brand manifest provided either as an inline object or a URL string pointing to a hosted manifest',
|
|
19
|
+
examples=[
|
|
20
|
+
{
|
|
21
|
+
'data': {
|
|
22
|
+
'colors': {'primary': '#FF6B35'},
|
|
23
|
+
'name': 'ACME Corporation',
|
|
24
|
+
'url': 'https://acmecorp.com',
|
|
25
|
+
},
|
|
26
|
+
'description': 'Inline brand manifest',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
'data': 'https://cdn.acmecorp.com/brand-manifest.json',
|
|
30
|
+
'description': 'URL string reference to hosted manifest',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
title='Brand Manifest Reference',
|
|
34
|
+
),
|
|
35
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: core/creative_asset.json
|
|
3
|
-
# timestamp: 2025-
|
|
3
|
+
# timestamp: 2025-12-11T15:09:37+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
@@ -59,12 +59,10 @@ class CreativeAsset(AdCPBaseModel):
|
|
|
59
59
|
| html_asset.HtmlAsset
|
|
60
60
|
| css_asset.CssAsset
|
|
61
61
|
| javascript_asset.JavascriptAsset
|
|
62
|
+
| vast_asset.VastAsset
|
|
63
|
+
| daast_asset.DaastAsset
|
|
62
64
|
| promoted_offerings.PromotedOfferings
|
|
63
|
-
| url_asset.UrlAsset
|
|
64
|
-
| vast_asset.VastAsset1
|
|
65
|
-
| vast_asset.VastAsset2
|
|
66
|
-
| daast_asset.DaastAsset1
|
|
67
|
-
| daast_asset.DaastAsset2,
|
|
65
|
+
| url_asset.UrlAsset,
|
|
68
66
|
],
|
|
69
67
|
Field(description='Assets required by the format, keyed by asset_role'),
|
|
70
68
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: core/creative_manifest.json
|
|
3
|
-
# timestamp: 2025-
|
|
3
|
+
# timestamp: 2025-12-11T15:09:37+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
@@ -37,17 +37,15 @@ class CreativeManifest(AdCPBaseModel):
|
|
|
37
37
|
image_asset.ImageAsset
|
|
38
38
|
| video_asset.VideoAsset
|
|
39
39
|
| audio_asset.AudioAsset
|
|
40
|
+
| vast_asset.VastAsset
|
|
40
41
|
| text_asset.TextAsset
|
|
41
42
|
| url_asset.UrlAsset
|
|
42
43
|
| html_asset.HtmlAsset
|
|
43
44
|
| javascript_asset.JavascriptAsset
|
|
44
45
|
| webhook_asset.WebhookAsset
|
|
45
46
|
| css_asset.CssAsset
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
| vast_asset.VastAsset2
|
|
49
|
-
| daast_asset.DaastAsset1
|
|
50
|
-
| daast_asset.DaastAsset2,
|
|
47
|
+
| daast_asset.DaastAsset
|
|
48
|
+
| promoted_offerings.PromotedOfferings,
|
|
51
49
|
],
|
|
52
50
|
Field(
|
|
53
51
|
description="Map of asset IDs to actual asset content. Each key MUST match an asset_id from the format's assets_required array (e.g., 'banner_image', 'clickthrough_url', 'video_file', 'vast_tag'). The asset_id is the technical identifier used to match assets to format requirements.\n\nIMPORTANT: Creative manifest validation MUST be performed in the context of the format specification. The format defines what type each asset_id should be, which eliminates any validation ambiguity."
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: core/deployment.json
|
|
3
|
-
# timestamp: 2025-
|
|
3
|
+
# timestamp: 2025-12-11T15:09:37+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
from typing import Annotated, Literal
|
|
8
8
|
|
|
9
9
|
from adcp.types.base import AdCPBaseModel
|
|
10
|
-
from pydantic import AnyUrl, AwareDatetime, ConfigDict, Field
|
|
10
|
+
from pydantic import AnyUrl, AwareDatetime, ConfigDict, Field, RootModel
|
|
11
11
|
|
|
12
12
|
from . import activation_key as activation_key_1
|
|
13
13
|
|
|
@@ -18,10 +18,9 @@ class Deployment1(AdCPBaseModel):
|
|
|
18
18
|
)
|
|
19
19
|
account: Annotated[str | None, Field(description='Account identifier if applicable')] = None
|
|
20
20
|
activation_key: Annotated[
|
|
21
|
-
activation_key_1.
|
|
21
|
+
activation_key_1.ActivationKey | None,
|
|
22
22
|
Field(
|
|
23
|
-
description='The key to use for targeting. Only present if is_live=true AND requester has access to this deployment.'
|
|
24
|
-
title='Activation Key',
|
|
23
|
+
description='The key to use for targeting. Only present if is_live=true AND requester has access to this deployment.'
|
|
25
24
|
),
|
|
26
25
|
] = None
|
|
27
26
|
deployed_at: Annotated[
|
|
@@ -51,10 +50,9 @@ class Deployment2(AdCPBaseModel):
|
|
|
51
50
|
)
|
|
52
51
|
account: Annotated[str | None, Field(description='Account identifier if applicable')] = None
|
|
53
52
|
activation_key: Annotated[
|
|
54
|
-
activation_key_1.
|
|
53
|
+
activation_key_1.ActivationKey | None,
|
|
55
54
|
Field(
|
|
56
|
-
description='The key to use for targeting. Only present if is_live=true AND requester has access to this deployment.'
|
|
57
|
-
title='Activation Key',
|
|
55
|
+
description='The key to use for targeting. Only present if is_live=true AND requester has access to this deployment.'
|
|
58
56
|
),
|
|
59
57
|
] = None
|
|
60
58
|
agent_url: Annotated[AnyUrl, Field(description='URL identifying the deployment agent')]
|
|
@@ -76,3 +74,13 @@ class Deployment2(AdCPBaseModel):
|
|
|
76
74
|
Literal['agent'],
|
|
77
75
|
Field(description='Discriminator indicating this is an agent URL-based deployment'),
|
|
78
76
|
]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class Deployment(RootModel[Deployment1 | Deployment2]):
|
|
80
|
+
root: Annotated[
|
|
81
|
+
Deployment1 | Deployment2,
|
|
82
|
+
Field(
|
|
83
|
+
description='A signal deployment to a specific deployment target with activation status and key',
|
|
84
|
+
title='Deployment',
|
|
85
|
+
),
|
|
86
|
+
]
|