airbyte-agent-amazon-ads 0.1.2__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.
Files changed (57) hide show
  1. airbyte_agent_amazon_ads/__init__.py +57 -0
  2. airbyte_agent_amazon_ads/_vendored/__init__.py +1 -0
  3. airbyte_agent_amazon_ads/_vendored/connector_sdk/__init__.py +82 -0
  4. airbyte_agent_amazon_ads/_vendored/connector_sdk/auth_strategies.py +1173 -0
  5. airbyte_agent_amazon_ads/_vendored/connector_sdk/auth_template.py +135 -0
  6. airbyte_agent_amazon_ads/_vendored/connector_sdk/cloud_utils/__init__.py +5 -0
  7. airbyte_agent_amazon_ads/_vendored/connector_sdk/cloud_utils/client.py +213 -0
  8. airbyte_agent_amazon_ads/_vendored/connector_sdk/connector_model_loader.py +986 -0
  9. airbyte_agent_amazon_ads/_vendored/connector_sdk/constants.py +78 -0
  10. airbyte_agent_amazon_ads/_vendored/connector_sdk/exceptions.py +23 -0
  11. airbyte_agent_amazon_ads/_vendored/connector_sdk/executor/__init__.py +31 -0
  12. airbyte_agent_amazon_ads/_vendored/connector_sdk/executor/hosted_executor.py +196 -0
  13. airbyte_agent_amazon_ads/_vendored/connector_sdk/executor/local_executor.py +1773 -0
  14. airbyte_agent_amazon_ads/_vendored/connector_sdk/executor/models.py +190 -0
  15. airbyte_agent_amazon_ads/_vendored/connector_sdk/extensions.py +693 -0
  16. airbyte_agent_amazon_ads/_vendored/connector_sdk/http/__init__.py +37 -0
  17. airbyte_agent_amazon_ads/_vendored/connector_sdk/http/adapters/__init__.py +9 -0
  18. airbyte_agent_amazon_ads/_vendored/connector_sdk/http/adapters/httpx_adapter.py +251 -0
  19. airbyte_agent_amazon_ads/_vendored/connector_sdk/http/config.py +98 -0
  20. airbyte_agent_amazon_ads/_vendored/connector_sdk/http/exceptions.py +119 -0
  21. airbyte_agent_amazon_ads/_vendored/connector_sdk/http/protocols.py +114 -0
  22. airbyte_agent_amazon_ads/_vendored/connector_sdk/http/response.py +104 -0
  23. airbyte_agent_amazon_ads/_vendored/connector_sdk/http_client.py +693 -0
  24. airbyte_agent_amazon_ads/_vendored/connector_sdk/introspection.py +262 -0
  25. airbyte_agent_amazon_ads/_vendored/connector_sdk/logging/__init__.py +11 -0
  26. airbyte_agent_amazon_ads/_vendored/connector_sdk/logging/logger.py +273 -0
  27. airbyte_agent_amazon_ads/_vendored/connector_sdk/logging/types.py +93 -0
  28. airbyte_agent_amazon_ads/_vendored/connector_sdk/observability/__init__.py +11 -0
  29. airbyte_agent_amazon_ads/_vendored/connector_sdk/observability/config.py +179 -0
  30. airbyte_agent_amazon_ads/_vendored/connector_sdk/observability/models.py +19 -0
  31. airbyte_agent_amazon_ads/_vendored/connector_sdk/observability/redactor.py +81 -0
  32. airbyte_agent_amazon_ads/_vendored/connector_sdk/observability/session.py +103 -0
  33. airbyte_agent_amazon_ads/_vendored/connector_sdk/performance/__init__.py +6 -0
  34. airbyte_agent_amazon_ads/_vendored/connector_sdk/performance/instrumentation.py +57 -0
  35. airbyte_agent_amazon_ads/_vendored/connector_sdk/performance/metrics.py +93 -0
  36. airbyte_agent_amazon_ads/_vendored/connector_sdk/schema/__init__.py +75 -0
  37. airbyte_agent_amazon_ads/_vendored/connector_sdk/schema/base.py +169 -0
  38. airbyte_agent_amazon_ads/_vendored/connector_sdk/schema/components.py +239 -0
  39. airbyte_agent_amazon_ads/_vendored/connector_sdk/schema/connector.py +120 -0
  40. airbyte_agent_amazon_ads/_vendored/connector_sdk/schema/extensions.py +230 -0
  41. airbyte_agent_amazon_ads/_vendored/connector_sdk/schema/operations.py +146 -0
  42. airbyte_agent_amazon_ads/_vendored/connector_sdk/schema/security.py +237 -0
  43. airbyte_agent_amazon_ads/_vendored/connector_sdk/secrets.py +182 -0
  44. airbyte_agent_amazon_ads/_vendored/connector_sdk/telemetry/__init__.py +10 -0
  45. airbyte_agent_amazon_ads/_vendored/connector_sdk/telemetry/config.py +32 -0
  46. airbyte_agent_amazon_ads/_vendored/connector_sdk/telemetry/events.py +59 -0
  47. airbyte_agent_amazon_ads/_vendored/connector_sdk/telemetry/tracker.py +155 -0
  48. airbyte_agent_amazon_ads/_vendored/connector_sdk/types.py +254 -0
  49. airbyte_agent_amazon_ads/_vendored/connector_sdk/utils.py +60 -0
  50. airbyte_agent_amazon_ads/_vendored/connector_sdk/validation.py +828 -0
  51. airbyte_agent_amazon_ads/connector.py +578 -0
  52. airbyte_agent_amazon_ads/connector_model.py +1074 -0
  53. airbyte_agent_amazon_ads/models.py +170 -0
  54. airbyte_agent_amazon_ads/types.py +48 -0
  55. airbyte_agent_amazon_ads-0.1.2.dist-info/METADATA +136 -0
  56. airbyte_agent_amazon_ads-0.1.2.dist-info/RECORD +57 -0
  57. airbyte_agent_amazon_ads-0.1.2.dist-info/WHEEL +4 -0
@@ -0,0 +1,578 @@
1
+ """
2
+ Amazon-Ads connector.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import logging
8
+ from typing import TYPE_CHECKING, Any, Callable, TypeVar, overload
9
+ try:
10
+ from typing import Literal
11
+ except ImportError:
12
+ from typing_extensions import Literal
13
+
14
+ from .connector_model import AmazonAdsConnectorModel
15
+ from ._vendored.connector_sdk.introspection import describe_entities, generate_tool_description
16
+ from .types import (
17
+ PortfoliosGetParams,
18
+ PortfoliosListParams,
19
+ ProfilesGetParams,
20
+ ProfilesListParams,
21
+ SponsoredProductCampaignsGetParams,
22
+ SponsoredProductCampaignsListParams,
23
+ SponsoredProductCampaignsListParamsStatefilter,
24
+ )
25
+ if TYPE_CHECKING:
26
+ from .models import AmazonAdsAuthConfig
27
+ # Import response models and envelope models at runtime
28
+ from .models import (
29
+ AmazonAdsExecuteResult,
30
+ AmazonAdsExecuteResultWithMeta,
31
+ ProfilesListResult,
32
+ PortfoliosListResult,
33
+ SponsoredProductCampaignsListResult,
34
+ Portfolio,
35
+ Profile,
36
+ SponsoredProductCampaign,
37
+ )
38
+
39
+ # TypeVar for decorator type preservation
40
+ _F = TypeVar("_F", bound=Callable[..., Any])
41
+
42
+
43
+
44
+ class AmazonAdsConnector:
45
+ """
46
+ Type-safe Amazon-Ads API connector.
47
+
48
+ Auto-generated from OpenAPI specification with full type safety.
49
+ """
50
+
51
+ connector_name = "amazon-ads"
52
+ connector_version = "1.0.1"
53
+ vendored_sdk_version = "0.1.0" # Version of vendored connector-sdk
54
+
55
+ # Map of (entity, action) -> needs_envelope for envelope wrapping decision
56
+ _ENVELOPE_MAP = {
57
+ ("profiles", "list"): True,
58
+ ("profiles", "get"): None,
59
+ ("portfolios", "list"): True,
60
+ ("portfolios", "get"): None,
61
+ ("sponsored_product_campaigns", "list"): True,
62
+ ("sponsored_product_campaigns", "get"): None,
63
+ }
64
+
65
+ # Map of (entity, action) -> {python_param_name: api_param_name}
66
+ # Used to convert snake_case TypedDict keys to API parameter names in execute()
67
+ _PARAM_MAP = {
68
+ ('profiles', 'list'): {'profile_type_filter': 'profileTypeFilter'},
69
+ ('profiles', 'get'): {'profile_id': 'profileId'},
70
+ ('portfolios', 'list'): {'include_extended_data_fields': 'includeExtendedDataFields'},
71
+ ('portfolios', 'get'): {'portfolio_id': 'portfolioId'},
72
+ ('sponsored_product_campaigns', 'list'): {'state_filter': 'stateFilter', 'max_results': 'maxResults', 'next_token': 'nextToken'},
73
+ ('sponsored_product_campaigns', 'get'): {'campaign_id': 'campaignId'},
74
+ }
75
+
76
+ def __init__(
77
+ self,
78
+ auth_config: AmazonAdsAuthConfig | None = None,
79
+ external_user_id: str | None = None,
80
+ airbyte_client_id: str | None = None,
81
+ airbyte_client_secret: str | None = None,
82
+ on_token_refresh: Any | None = None,
83
+ region_url: str | None = None ):
84
+ """
85
+ Initialize a new amazon-ads connector instance.
86
+
87
+ Supports both local and hosted execution modes:
88
+ - Local mode: Provide `auth_config` for direct API calls
89
+ - Hosted mode: Provide `external_user_id`, `airbyte_client_id`, and `airbyte_client_secret` for hosted execution
90
+
91
+ Args:
92
+ auth_config: Typed authentication configuration (required for local mode)
93
+ external_user_id: External user ID (required for hosted mode)
94
+ airbyte_client_id: Airbyte OAuth client ID (required for hosted mode)
95
+ airbyte_client_secret: Airbyte OAuth client secret (required for hosted mode)
96
+ on_token_refresh: Optional callback for OAuth2 token refresh persistence.
97
+ Called with new_tokens dict when tokens are refreshed. Can be sync or async.
98
+ Example: lambda tokens: save_to_database(tokens) region_url: The Amazon Ads API endpoint URL based on region:
99
+ - NA (North America): https://advertising-api.amazon.com
100
+ - EU (Europe): https://advertising-api-eu.amazon.com
101
+ - FE (Far East): https://advertising-api-fe.amazon.com
102
+
103
+ Examples:
104
+ # Local mode (direct API calls)
105
+ connector = AmazonAdsConnector(auth_config=AmazonAdsAuthConfig(client_id="...", client_secret="...", refresh_token="..."))
106
+ # Hosted mode (executed on Airbyte cloud)
107
+ connector = AmazonAdsConnector(
108
+ external_user_id="user-123",
109
+ airbyte_client_id="client_abc123",
110
+ airbyte_client_secret="secret_xyz789"
111
+ )
112
+
113
+ # Local mode with OAuth2 token refresh callback
114
+ def save_tokens(new_tokens: dict) -> None:
115
+ # Persist updated tokens to your storage (file, database, etc.)
116
+ with open("tokens.json", "w") as f:
117
+ json.dump(new_tokens, f)
118
+
119
+ connector = AmazonAdsConnector(
120
+ auth_config=AmazonAdsAuthConfig(access_token="...", refresh_token="..."),
121
+ on_token_refresh=save_tokens
122
+ )
123
+ """
124
+ # Hosted mode: external_user_id, airbyte_client_id, and airbyte_client_secret provided
125
+ if external_user_id and airbyte_client_id and airbyte_client_secret:
126
+ from ._vendored.connector_sdk.executor import HostedExecutor
127
+ self._executor = HostedExecutor(
128
+ external_user_id=external_user_id,
129
+ airbyte_client_id=airbyte_client_id,
130
+ airbyte_client_secret=airbyte_client_secret,
131
+ connector_definition_id=str(AmazonAdsConnectorModel.id),
132
+ )
133
+ else:
134
+ # Local mode: auth_config required
135
+ if not auth_config:
136
+ raise ValueError(
137
+ "Either provide (external_user_id, airbyte_client_id, airbyte_client_secret) for hosted mode "
138
+ "or auth_config for local mode"
139
+ )
140
+
141
+ from ._vendored.connector_sdk.executor import LocalExecutor
142
+
143
+ # Build config_values dict from server variables
144
+ config_values: dict[str, str] = {}
145
+ if region_url:
146
+ config_values["region_url"] = region_url
147
+
148
+ self._executor = LocalExecutor(
149
+ model=AmazonAdsConnectorModel,
150
+ auth_config=auth_config.model_dump() if auth_config else None,
151
+ config_values=config_values,
152
+ on_token_refresh=on_token_refresh
153
+ )
154
+
155
+ # Update base_url with server variables if provided
156
+ base_url = self._executor.http_client.base_url
157
+ if region_url:
158
+ base_url = base_url.replace("{region_url}", region_url)
159
+ self._executor.http_client.base_url = base_url
160
+
161
+ # Initialize entity query objects
162
+ self.profiles = ProfilesQuery(self)
163
+ self.portfolios = PortfoliosQuery(self)
164
+ self.sponsored_product_campaigns = SponsoredProductCampaignsQuery(self)
165
+
166
+ # ===== TYPED EXECUTE METHOD (Recommended Interface) =====
167
+
168
+ @overload
169
+ async def execute(
170
+ self,
171
+ entity: Literal["profiles"],
172
+ action: Literal["list"],
173
+ params: "ProfilesListParams"
174
+ ) -> "ProfilesListResult": ...
175
+
176
+ @overload
177
+ async def execute(
178
+ self,
179
+ entity: Literal["profiles"],
180
+ action: Literal["get"],
181
+ params: "ProfilesGetParams"
182
+ ) -> "Profile": ...
183
+
184
+ @overload
185
+ async def execute(
186
+ self,
187
+ entity: Literal["portfolios"],
188
+ action: Literal["list"],
189
+ params: "PortfoliosListParams"
190
+ ) -> "PortfoliosListResult": ...
191
+
192
+ @overload
193
+ async def execute(
194
+ self,
195
+ entity: Literal["portfolios"],
196
+ action: Literal["get"],
197
+ params: "PortfoliosGetParams"
198
+ ) -> "Portfolio": ...
199
+
200
+ @overload
201
+ async def execute(
202
+ self,
203
+ entity: Literal["sponsored_product_campaigns"],
204
+ action: Literal["list"],
205
+ params: "SponsoredProductCampaignsListParams"
206
+ ) -> "SponsoredProductCampaignsListResult": ...
207
+
208
+ @overload
209
+ async def execute(
210
+ self,
211
+ entity: Literal["sponsored_product_campaigns"],
212
+ action: Literal["get"],
213
+ params: "SponsoredProductCampaignsGetParams"
214
+ ) -> "SponsoredProductCampaign": ...
215
+
216
+
217
+ @overload
218
+ async def execute(
219
+ self,
220
+ entity: str,
221
+ action: str,
222
+ params: dict[str, Any]
223
+ ) -> AmazonAdsExecuteResult[Any] | AmazonAdsExecuteResultWithMeta[Any, Any] | Any: ...
224
+
225
+ async def execute(
226
+ self,
227
+ entity: str,
228
+ action: str,
229
+ params: dict[str, Any] | None = None
230
+ ) -> Any:
231
+ """
232
+ Execute an entity operation with full type safety.
233
+
234
+ This is the recommended interface for blessed connectors as it:
235
+ - Uses the same signature as non-blessed connectors
236
+ - Provides full IDE autocomplete for entity/action/params
237
+ - Makes migration from generic to blessed connectors seamless
238
+
239
+ Args:
240
+ entity: Entity name (e.g., "customers")
241
+ action: Operation action (e.g., "create", "get", "list")
242
+ params: Operation parameters (typed based on entity+action)
243
+
244
+ Returns:
245
+ Typed response based on the operation
246
+
247
+ Example:
248
+ customer = await connector.execute(
249
+ entity="customers",
250
+ action="get",
251
+ params={"id": "cus_123"}
252
+ )
253
+ """
254
+ from ._vendored.connector_sdk.executor import ExecutionConfig
255
+
256
+ # Remap parameter names from snake_case (TypedDict keys) to API parameter names
257
+ if params:
258
+ param_map = self._PARAM_MAP.get((entity, action), {})
259
+ if param_map:
260
+ params = {param_map.get(k, k): v for k, v in params.items()}
261
+
262
+ # Use ExecutionConfig for both local and hosted executors
263
+ config = ExecutionConfig(
264
+ entity=entity,
265
+ action=action,
266
+ params=params
267
+ )
268
+
269
+ result = await self._executor.execute(config)
270
+
271
+ if not result.success:
272
+ raise RuntimeError(f"Execution failed: {result.error}")
273
+
274
+ # Check if this operation has extractors configured
275
+ has_extractors = self._ENVELOPE_MAP.get((entity, action), False)
276
+
277
+ if has_extractors:
278
+ # With extractors - return Pydantic envelope with data and meta
279
+ if result.meta is not None:
280
+ return AmazonAdsExecuteResultWithMeta[Any, Any](
281
+ data=result.data,
282
+ meta=result.meta
283
+ )
284
+ else:
285
+ return AmazonAdsExecuteResult[Any](data=result.data)
286
+ else:
287
+ # No extractors - return raw response data
288
+ return result.data
289
+
290
+ # ===== INTROSPECTION METHODS =====
291
+
292
+ @classmethod
293
+ def describe(cls, func: _F) -> _F:
294
+ """
295
+ Decorator that populates a function's docstring with connector capabilities.
296
+
297
+ This class method can be used as a decorator to automatically generate
298
+ comprehensive documentation for AI tool functions.
299
+
300
+ Usage:
301
+ @mcp.tool()
302
+ @AmazonAdsConnector.describe
303
+ async def execute(entity: str, action: str, params: dict):
304
+ '''Execute operations.'''
305
+ ...
306
+
307
+ The decorated function's __doc__ will be updated with:
308
+ - Available entities and their actions
309
+ - Parameter signatures with required (*) and optional (?) markers
310
+ - Response structure documentation
311
+ - Example questions (if available in OpenAPI spec)
312
+
313
+ Args:
314
+ func: The function to decorate
315
+
316
+ Returns:
317
+ The same function with updated __doc__
318
+ """
319
+ description = generate_tool_description(AmazonAdsConnectorModel)
320
+
321
+ original_doc = func.__doc__ or ""
322
+ if original_doc.strip():
323
+ func.__doc__ = f"{original_doc.strip()}\n{description}"
324
+ else:
325
+ func.__doc__ = description
326
+
327
+ return func
328
+
329
+ def list_entities(self) -> list[dict[str, Any]]:
330
+ """
331
+ Get structured data about available entities, actions, and parameters.
332
+
333
+ Returns a list of entity descriptions with:
334
+ - entity_name: Name of the entity (e.g., "contacts", "deals")
335
+ - description: Entity description from the first endpoint
336
+ - available_actions: List of actions (e.g., ["list", "get", "create"])
337
+ - parameters: Dict mapping action -> list of parameter dicts
338
+
339
+ Example:
340
+ entities = connector.list_entities()
341
+ for entity in entities:
342
+ print(f"{entity['entity_name']}: {entity['available_actions']}")
343
+ """
344
+ return describe_entities(AmazonAdsConnectorModel)
345
+
346
+ def entity_schema(self, entity: str) -> dict[str, Any] | None:
347
+ """
348
+ Get the JSON schema for an entity.
349
+
350
+ Args:
351
+ entity: Entity name (e.g., "contacts", "companies")
352
+
353
+ Returns:
354
+ JSON schema dict describing the entity structure, or None if not found.
355
+
356
+ Example:
357
+ schema = connector.entity_schema("contacts")
358
+ if schema:
359
+ print(f"Contact properties: {list(schema.get('properties', {}).keys())}")
360
+ """
361
+ entity_def = next(
362
+ (e for e in AmazonAdsConnectorModel.entities if e.name == entity),
363
+ None
364
+ )
365
+ if entity_def is None:
366
+ logging.getLogger(__name__).warning(
367
+ f"Entity '{entity}' not found. Available entities: "
368
+ f"{[e.name for e in AmazonAdsConnectorModel.entities]}"
369
+ )
370
+ return entity_def.entity_schema if entity_def else None
371
+
372
+
373
+
374
+ class ProfilesQuery:
375
+ """
376
+ Query class for Profiles entity operations.
377
+ """
378
+
379
+ def __init__(self, connector: AmazonAdsConnector):
380
+ """Initialize query with connector reference."""
381
+ self._connector = connector
382
+
383
+ async def list(
384
+ self,
385
+ profile_type_filter: str | None = None,
386
+ **kwargs
387
+ ) -> ProfilesListResult:
388
+ """
389
+ Returns a list of advertising profiles associated with the authenticated user.
390
+ Profiles represent an advertiser's account in a specific marketplace. Advertisers
391
+ may have a single profile if they advertise in only one marketplace, or a separate
392
+ profile for each marketplace if they advertise regionally or globally.
393
+
394
+
395
+ Args:
396
+ profile_type_filter: Filter profiles by type. Comma-separated list of profile types.
397
+ Valid values: seller, vendor, agency
398
+
399
+ **kwargs: Additional parameters
400
+
401
+ Returns:
402
+ ProfilesListResult
403
+ """
404
+ params = {k: v for k, v in {
405
+ "profileTypeFilter": profile_type_filter,
406
+ **kwargs
407
+ }.items() if v is not None}
408
+
409
+ result = await self._connector.execute("profiles", "list", params)
410
+ # Cast generic envelope to concrete typed result
411
+ return ProfilesListResult(
412
+ data=result.data
413
+ )
414
+
415
+
416
+
417
+ async def get(
418
+ self,
419
+ profile_id: str,
420
+ **kwargs
421
+ ) -> Profile:
422
+ """
423
+ Retrieves a single advertising profile by its ID. The profile contains
424
+ information about the advertiser's account in a specific marketplace.
425
+
426
+
427
+ Args:
428
+ profile_id: The unique identifier of the profile
429
+ **kwargs: Additional parameters
430
+
431
+ Returns:
432
+ Profile
433
+ """
434
+ params = {k: v for k, v in {
435
+ "profileId": profile_id,
436
+ **kwargs
437
+ }.items() if v is not None}
438
+
439
+ result = await self._connector.execute("profiles", "get", params)
440
+ return result
441
+
442
+
443
+
444
+ class PortfoliosQuery:
445
+ """
446
+ Query class for Portfolios entity operations.
447
+ """
448
+
449
+ def __init__(self, connector: AmazonAdsConnector):
450
+ """Initialize query with connector reference."""
451
+ self._connector = connector
452
+
453
+ async def list(
454
+ self,
455
+ include_extended_data_fields: str | None = None,
456
+ **kwargs
457
+ ) -> PortfoliosListResult:
458
+ """
459
+ Returns a list of portfolios for the specified profile. Portfolios are used to
460
+ group campaigns together for organizational and budget management purposes.
461
+
462
+
463
+ Args:
464
+ include_extended_data_fields: Whether to include extended data fields in the response
465
+ **kwargs: Additional parameters
466
+
467
+ Returns:
468
+ PortfoliosListResult
469
+ """
470
+ params = {k: v for k, v in {
471
+ "includeExtendedDataFields": include_extended_data_fields,
472
+ **kwargs
473
+ }.items() if v is not None}
474
+
475
+ result = await self._connector.execute("portfolios", "list", params)
476
+ # Cast generic envelope to concrete typed result
477
+ return PortfoliosListResult(
478
+ data=result.data
479
+ )
480
+
481
+
482
+
483
+ async def get(
484
+ self,
485
+ portfolio_id: str,
486
+ **kwargs
487
+ ) -> Portfolio:
488
+ """
489
+ Retrieves a single portfolio by its ID using the v2 API.
490
+
491
+
492
+ Args:
493
+ portfolio_id: The unique identifier of the portfolio
494
+ **kwargs: Additional parameters
495
+
496
+ Returns:
497
+ Portfolio
498
+ """
499
+ params = {k: v for k, v in {
500
+ "portfolioId": portfolio_id,
501
+ **kwargs
502
+ }.items() if v is not None}
503
+
504
+ result = await self._connector.execute("portfolios", "get", params)
505
+ return result
506
+
507
+
508
+
509
+ class SponsoredProductCampaignsQuery:
510
+ """
511
+ Query class for SponsoredProductCampaigns entity operations.
512
+ """
513
+
514
+ def __init__(self, connector: AmazonAdsConnector):
515
+ """Initialize query with connector reference."""
516
+ self._connector = connector
517
+
518
+ async def list(
519
+ self,
520
+ state_filter: SponsoredProductCampaignsListParamsStatefilter | None = None,
521
+ max_results: int | None = None,
522
+ next_token: str | None = None,
523
+ **kwargs
524
+ ) -> SponsoredProductCampaignsListResult:
525
+ """
526
+ Returns a list of sponsored product campaigns for the specified profile.
527
+ Sponsored Products campaigns promote individual product listings on Amazon.
528
+
529
+
530
+ Args:
531
+ state_filter: Parameter stateFilter
532
+ max_results: Maximum number of results to return
533
+ next_token: Token for pagination
534
+ **kwargs: Additional parameters
535
+
536
+ Returns:
537
+ SponsoredProductCampaignsListResult
538
+ """
539
+ params = {k: v for k, v in {
540
+ "stateFilter": state_filter,
541
+ "maxResults": max_results,
542
+ "nextToken": next_token,
543
+ **kwargs
544
+ }.items() if v is not None}
545
+
546
+ result = await self._connector.execute("sponsored_product_campaigns", "list", params)
547
+ # Cast generic envelope to concrete typed result
548
+ return SponsoredProductCampaignsListResult(
549
+ data=result.data
550
+ )
551
+
552
+
553
+
554
+ async def get(
555
+ self,
556
+ campaign_id: str,
557
+ **kwargs
558
+ ) -> SponsoredProductCampaign:
559
+ """
560
+ Retrieves a single sponsored product campaign by its ID using the v2 API.
561
+
562
+
563
+ Args:
564
+ campaign_id: The unique identifier of the campaign
565
+ **kwargs: Additional parameters
566
+
567
+ Returns:
568
+ SponsoredProductCampaign
569
+ """
570
+ params = {k: v for k, v in {
571
+ "campaignId": campaign_id,
572
+ **kwargs
573
+ }.items() if v is not None}
574
+
575
+ result = await self._connector.execute("sponsored_product_campaigns", "get", params)
576
+ return result
577
+
578
+