python-amazon-ad-api 1.2.7__tar.gz → 1.2.9__tar.gz

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 (123) hide show
  1. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/PKG-INFO +2 -2
  2. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/README.md +1 -1
  3. python_amazon_ad_api-1.2.9/ad_api/api/billing.py +551 -0
  4. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/invoices.py +10 -8
  5. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/recommendations.py +39 -2
  6. python_amazon_ad_api-1.2.9/ad_api/version.py +1 -0
  7. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/python_amazon_ad_api.egg-info/PKG-INFO +2 -2
  8. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/setup.cfg +1 -1
  9. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/setup.py +1 -1
  10. python_amazon_ad_api-1.2.7/ad_api/api/billing.py +0 -87
  11. python_amazon_ad_api-1.2.7/ad_api/version.py +0 -1
  12. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/LICENSE +0 -0
  13. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/__init__.py +0 -0
  14. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/__init__.py +0 -0
  15. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/account.py +0 -0
  16. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/advertising_test_account.py +0 -0
  17. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/attribution.py +0 -0
  18. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/audiences.py +0 -0
  19. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/brand_metrics.py +0 -0
  20. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/creative_assets.py +0 -0
  21. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/eligibility.py +0 -0
  22. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/exports.py +0 -0
  23. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/history.py +0 -0
  24. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/insights.py +0 -0
  25. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/localization.py +0 -0
  26. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/manager_accounts.py +0 -0
  27. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/metadata.py +0 -0
  28. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/portfolios.py +0 -0
  29. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/portfolios_v3.py +0 -0
  30. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/profiles.py +0 -0
  31. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/reports.py +0 -0
  32. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/__init__.py +0 -0
  33. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/ad_creatives_v4.py +0 -0
  34. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/ad_groups.py +0 -0
  35. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/ad_groups_v4.py +0 -0
  36. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/ads_v4.py +0 -0
  37. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/benchmarks.py +0 -0
  38. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/bid_recommendations.py +0 -0
  39. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/brands.py +0 -0
  40. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/budget_rules.py +0 -0
  41. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/campaigns.py +0 -0
  42. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/campaigns_v4.py +0 -0
  43. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/forecast.py +0 -0
  44. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/keywords.py +0 -0
  45. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/keywords_recommendations.py +0 -0
  46. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/landing_page_asins.py +0 -0
  47. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/media.py +0 -0
  48. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/migration.py +0 -0
  49. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/negative_keywords.py +0 -0
  50. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/negative_product_targeting.py +0 -0
  51. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/optimization_rules.py +0 -0
  52. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/product_targeting.py +0 -0
  53. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/recommendations.py +0 -0
  54. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/reports.py +0 -0
  55. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/stores.py +0 -0
  56. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/targeting_categories.py +0 -0
  57. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/targeting_recommendations.py +0 -0
  58. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sb/themes.py +0 -0
  59. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/__init__.py +0 -0
  60. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/ad_groups.py +0 -0
  61. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/bid_recommendations.py +0 -0
  62. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/brand_safety.py +0 -0
  63. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/budget_rules.py +0 -0
  64. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/campaigns.py +0 -0
  65. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/campaigns_budget_usage.py +0 -0
  66. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/creatives.py +0 -0
  67. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/forecast.py +0 -0
  68. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/negative_product_targeting.py +0 -0
  69. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/product_ads.py +0 -0
  70. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/product_targeting.py +0 -0
  71. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/recommendations.py +0 -0
  72. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/reports.py +0 -0
  73. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/snapshots.py +0 -0
  74. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sd/targeting_recommendations.py +0 -0
  75. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/__init__.py +0 -0
  76. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/ad_groups_v3.py +0 -0
  77. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/bid_recommendations_v3.py +0 -0
  78. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/budget_initial_recommendation.py +0 -0
  79. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/budget_recommendations.py +0 -0
  80. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/budget_rules.py +0 -0
  81. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/budget_rules_recommendations.py +0 -0
  82. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/campaign_consolidated_recommendations.py +0 -0
  83. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/campaign_negative_keywords_v3.py +0 -0
  84. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/campaign_negative_targets.py +0 -0
  85. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/campaigns_budget_usage.py +0 -0
  86. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/campaigns_v3.py +0 -0
  87. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/campaings_optimization.py +0 -0
  88. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/keywords_v3.py +0 -0
  89. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/negative_keywords_v3.py +0 -0
  90. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/negative_product_targeting_v3.py +0 -0
  91. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/product_ads_v3.py +0 -0
  92. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/product_recommendations.py +0 -0
  93. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/product_targeting_v3.py +0 -0
  94. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/ranked_keywords_recommendations.py +0 -0
  95. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/sp/schedule_based_bid_optimization.py +0 -0
  96. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/stores.py +0 -0
  97. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/stream.py +0 -0
  98. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/v1/__init__.py +0 -0
  99. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/v1/ad_groups.py +0 -0
  100. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/v1/ads.py +0 -0
  101. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/v1/campaigns.py +0 -0
  102. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/v1/targets.py +0 -0
  103. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/api/validation_configurations.py +0 -0
  104. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/auth/__init__.py +0 -0
  105. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/auth/access_token_client.py +0 -0
  106. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/auth/access_token_response.py +0 -0
  107. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/auth/credentials.py +0 -0
  108. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/auth/exceptions.py +0 -0
  109. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/base/__init__.py +0 -0
  110. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/base/api_response.py +0 -0
  111. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/base/base_client.py +0 -0
  112. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/base/client.py +0 -0
  113. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/base/config.py +0 -0
  114. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/base/credential_provider.py +0 -0
  115. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/base/exceptions.py +0 -0
  116. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/base/helpers.py +0 -0
  117. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/base/marketplaces.py +0 -0
  118. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/ad_api/base/utils.py +0 -0
  119. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/pyproject.toml +0 -0
  120. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/python_amazon_ad_api.egg-info/SOURCES.txt +0 -0
  121. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/python_amazon_ad_api.egg-info/dependency_links.txt +0 -0
  122. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/python_amazon_ad_api.egg-info/requires.txt +0 -0
  123. {python_amazon_ad_api-1.2.7 → python_amazon_ad_api-1.2.9}/python_amazon_ad_api.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-amazon-ad-api
3
- Version: 1.2.7
3
+ Version: 1.2.9
4
4
  Summary: Python wrapper for the Amazon Advertising API
5
5
  Home-page: https://github.com/denisneuf/python-amazon-ad-api
6
6
  Author: Daniel Alvaro
@@ -274,7 +274,7 @@ curl \
274
274
  * [Localization](https://python-amazon-ad-api.readthedocs.io/en/latest/api/localization.html)
275
275
  * [Product Selector](https://python-amazon-ad-api.readthedocs.io/en/latest/api/metadata.html)
276
276
  * [Validation Configurations](https://python-amazon-ad-api.readthedocs.io/en/latest/api/validation_configurations.html)
277
- * [Tactical recommendations beta](https://python-amazon-ad-api.readthedocs.io/en/latest/api/recommendations.html)
277
+ * [Tactical recommendations](https://python-amazon-ad-api.readthedocs.io/en/latest/api/recommendations.html)
278
278
  * [Exports](https://advertising.amazon.com/API/docs/en-us/exports)
279
279
 
280
280
 
@@ -246,7 +246,7 @@ curl \
246
246
  * [Localization](https://python-amazon-ad-api.readthedocs.io/en/latest/api/localization.html)
247
247
  * [Product Selector](https://python-amazon-ad-api.readthedocs.io/en/latest/api/metadata.html)
248
248
  * [Validation Configurations](https://python-amazon-ad-api.readthedocs.io/en/latest/api/validation_configurations.html)
249
- * [Tactical recommendations beta](https://python-amazon-ad-api.readthedocs.io/en/latest/api/recommendations.html)
249
+ * [Tactical recommendations](https://python-amazon-ad-api.readthedocs.io/en/latest/api/recommendations.html)
250
250
  * [Exports](https://advertising.amazon.com/API/docs/en-us/exports)
251
251
 
252
252
 
@@ -0,0 +1,551 @@
1
+ from ad_api.base import Client, sp_endpoint, fill_query_params, ApiResponse, Utils
2
+
3
+
4
+ class Billing(Client):
5
+ @sp_endpoint('/billing/statuses', method='POST')
6
+ def list_billing_status(self, **kwargs) -> ApiResponse:
7
+ r"""
8
+ Get the billing status for a list of advertising accounts.
9
+
10
+ Request Body
11
+ | Bulk Get Billing Statuses Request Body {
12
+ | The properties needed to get the billing statuses for a set of advertisers.
13
+ | **advertiserMarketplaces**\* (array) minItems: 0 maxItems: 100 [
14
+ | advertiserMarketplace {
15
+ | **marketplaceId**\* (string)
16
+ | **advertiserId**\* (string)
17
+ | }
18
+ | ]
19
+ | **locale** (string) Locale. Enum: ['ar_AE', 'cs_CZ', 'de_DE', 'en_AU', 'en_CA', 'en_GB', 'en_IN', 'en_SG', 'es_ES', 'es_MX', 'fr_CA', 'fr_FR', 'he_IL', 'hi_IN', 'it_IT', 'ja_JP', 'ko_KR', 'nl_NL', 'pl_PL', 'pt_BR', 'sv_SE', 'ta_IN', 'tr_TR', 'zh_CN', 'zh_TW']
20
+ | }
21
+ Returns
22
+ ApiResponse
23
+ """
24
+
25
+ request_contentType = 'application/vnd.bulkgetbillingstatusrequestbody.v1+json'
26
+ accept_contentType = 'application/vnd.bulkgetbillingstatusresponse.v1+json'
27
+ headers = {'Content-Type': request_contentType, 'Accept': accept_contentType}
28
+
29
+ body = Utils.convert_body(kwargs.pop('body'), False)
30
+ return self._request(kwargs.pop('path'), data=body, params=kwargs, headers=headers)
31
+
32
+ @sp_endpoint('/billing/notifications', method='POST')
33
+ def list_billing_notifications(self, **kwargs) -> ApiResponse:
34
+ r"""
35
+ Get the billing notifications for a list advertising accounts.
36
+
37
+ Request Body
38
+ | Bulk Get Billing Notifications Request Body {
39
+ | The properties needed to get the billing notifications for a set of advertisers.
40
+ | **advertiserMarketplaces**\* (array) minItems: 0 maxItems: 100 [
41
+ | advertiserMarketplace {
42
+ | **marketplaceId**\* (string)
43
+ | **advertiserId**\* (string)
44
+ | }
45
+ | ]
46
+ | **locale** (string) Locale. Enum: ['ar_AE', 'cs_CZ', 'de_DE', 'en_AU', 'en_CA', 'en_GB', 'en_IN', 'en_SG', 'es_ES', 'es_MX', 'fr_CA', 'fr_FR', 'he_IL', 'hi_IN', 'it_IT', 'ja_JP', 'ko_KR', 'nl_NL', 'pl_PL', 'pt_BR', 'sv_SE', 'ta_IN', 'tr_TR', 'zh_CN', 'zh_TW']
47
+ | }
48
+ Returns
49
+ ApiResponse
50
+ """
51
+
52
+ request_contentType = 'application/vnd.billingnotifications.v1+json'
53
+ accept_contentType = 'application/vnd.bulkgetbillingnotificationsresponse.v1+json'
54
+ headers = {'Content-Type': request_contentType, 'Accept': accept_contentType}
55
+
56
+ body = Utils.convert_body(kwargs.pop('body'))
57
+ return self._request(kwargs.pop('path'), data=body, params=kwargs, headers=headers)
58
+
59
+ @sp_endpoint('/billing/paymentMethods/list', method='POST')
60
+ def get_customer_payment_methods(self, **kwargs) -> ApiResponse:
61
+ r"""
62
+ Lists the ways this account can pay.
63
+
64
+ Query
65
+
66
+ - ``criteriaType`` (string): required. ``PAY_NOW`` or ``AUTO_PAY``. The
67
+ service answers ``400 Value null at 'criteriaType' failed to satisfy
68
+ constraint`` when it is missing. It does not go in the body; this route
69
+ takes no body.
70
+
71
+ Returns
72
+ ApiResponse carrying five lists, always the same five, some empty:
73
+
74
+ - ``creditCardPaymentMethods``
75
+ - ``externalDeductFromPaymentPaymentMethods``
76
+ - ``externalPayByInvoicePaymentMethods``
77
+ - ``payByInvoicePaymentMethods``
78
+ - ``sellerPayablePaymentMethods``
79
+
80
+ A card entry carries ``brand``, ``tail`` (the last four digits),
81
+ ``expiryDetails`` with ``month`` and ``year``, ``eligibleCountries``
82
+ and an ``instrumentId`` that identifies the instrument for later
83
+ calls. Treat the ``instrumentId`` as a credential.
84
+
85
+ """
86
+ accept_contentType = 'application/vnd.paymentmethods.v1+json'
87
+ headers = {'Accept': accept_contentType}
88
+ return self._request(kwargs.pop('path'), params=kwargs, headers=headers)
89
+
90
+ @sp_endpoint('/billing/invoices/pay', method='POST')
91
+ def pay_invoices(self, **kwargs) -> ApiResponse:
92
+ r"""
93
+ Collects the outstanding balance for one or more countries.
94
+
95
+ This does not name invoices. The body carries no invoice ids: it names the
96
+ countries whose debt is collected, and the service settles whatever is
97
+ open there through a payment agreement. To read which invoices exist, use
98
+ ``Invoices.list_invoices``.
99
+
100
+ .. warning::
101
+
102
+ Written from the contract. No live call was possible: the account
103
+ held no ISSUED invoice, and ``EXECUTE`` moves money.
104
+
105
+ Request Body (required)
106
+
107
+ - ``idempotenceId`` (string): required, and the only required member. Two
108
+ requests carrying the same id are treated as one, so a retry after a
109
+ timeout does not charge twice.
110
+ - ``mode`` (string): ``EXECUTE`` charges, ``PREVIEW`` simulates and moves
111
+ nothing. Use ``PREVIEW`` to check a body before committing to it.
112
+ - ``paymentAgreementId`` (string): the agreement to charge, whose payment
113
+ profile decides the method. Omit it and the advertiser's latest
114
+ agreement is used.
115
+ - ``reasonLocale`` (string): the locale of the reason text, such as
116
+ ``es_ES``.
117
+ - ``targetCountryCodes`` (array): the countries whose balance is
118
+ collected. This is what selects the debt.
119
+
120
+ Returns
121
+ ApiResponse carrying ``success`` and ``failure``, both always present.
122
+ An empty ``failure`` means every collection went through. A ``200``
123
+ does not by itself mean the money moved: read ``failure``.
124
+
125
+ """
126
+ accept_contentType = 'application/vnd.invoices.v1+json'
127
+ headers = {'Accept': accept_contentType}
128
+ body = Utils.convert_body(kwargs.pop('body'), False)
129
+ return self._request(kwargs.pop('path'), data=body, params=kwargs, headers=headers)
130
+
131
+ @sp_endpoint('/billing/paymentAgreements/list', method='POST')
132
+ def get_payment_agreements(self, **kwargs) -> ApiResponse:
133
+ r"""
134
+ Lists the payment agreements this account holds.
135
+
136
+ Query
137
+
138
+ - ``agreementType`` (string): required. ``AUTO_PAY`` or ``PAY_NOW``. The
139
+ service answers ``400 Value null at 'agreementType' failed to satisfy
140
+ constraint`` when it is missing. It does not go in the body; this route
141
+ takes no body.
142
+
143
+ Returns
144
+ ApiResponse with ``paymentAgreements``, a list. An account that pays
145
+ automatically holds ``AUTO_PAY`` agreements and answers an empty list
146
+ for ``PAY_NOW``, and the reverse, so an empty answer here means the
147
+ account holds none of that type rather than that the call failed.
148
+
149
+ Each agreement carries a ``paymentAgreementId`` and a
150
+ ``paymentProfile`` whose ``paymentMethods`` are ordered by
151
+ ``priority``, starting at 0. The lowest priority is tried first and
152
+ the next covers if it cannot be charged.
153
+
154
+ """
155
+ accept_contentType = 'application/vnd.paymentagreements.v1+json'
156
+ headers = {'Accept': accept_contentType}
157
+ return self._request(kwargs.pop('path'), params=kwargs, headers=headers)
158
+
159
+ @sp_endpoint('/billing/paymentAgreements', method='POST')
160
+ def create_payment_agreements(self, **kwargs) -> ApiResponse:
161
+ r"""
162
+ Creates a payment agreement, which decides how an account gets charged.
163
+
164
+ .. warning::
165
+
166
+ Written from the contract, and the contract describes this route
167
+ thinly: it names the media type and nothing else. No body is
168
+ documented here because none is documented there, and the call was
169
+ not made because a payment agreement is not something to create by
170
+ way of a test.
171
+
172
+ What the route takes can be inferred from
173
+ ``get_payment_agreements``, which returns the shape it produces: an
174
+ agreement carries a ``paymentProfile`` whose ``paymentMethods`` are
175
+ ordered by ``priority``. Building one means naming those methods.
176
+
177
+ Read the live schema before using this. Until then, treat the body as
178
+ unknown rather than copying a guess from here.
179
+
180
+ Returns
181
+ ApiResponse with the created agreement, in the shape
182
+ ``get_payment_agreements`` lists.
183
+
184
+ """
185
+ accept_contentType = 'application/vnd.paymentagreements.v1+json'
186
+ headers = {'Accept': accept_contentType}
187
+ body = Utils.convert_body(kwargs.pop('body'), False)
188
+ return self._request(kwargs.pop('path'), data=body, params=kwargs, headers=headers)
189
+
190
+ @sp_endpoint('/invoiceSummaries/list', method='POST')
191
+ def invoice_summaries(self, **kwargs) -> ApiResponse:
192
+ r"""
193
+ Lists invoice summaries with filters, sorting and paging.
194
+
195
+ This is the route to reach for when the question is "which invoices fall
196
+ in this period". ``Invoices.list_invoices`` returns a flat page and leaves
197
+ the filtering to the caller; this one filters on the service, by issued
198
+ date, due date, status, country, invoice number and payment method.
199
+
200
+ Note the date format. Here it is ISO-8601 with the date alone,
201
+ ``"2026-09-01"``. ``Invoices.list_invoices`` answers dates as
202
+ ``"20260902"``. The two shapes are not interchangeable.
203
+
204
+ Request Body (optional)
205
+
206
+ Every member is optional. An empty object returns the first page.
207
+
208
+ - ``invoiceIssuedDateRangeFilter`` (object): ``startDate`` and
209
+ ``endDate``, both inclusive, both ``"YYYY-MM-DD"``.
210
+ - ``invoiceDueDateRangeFilter`` (object): same shape, for the due date.
211
+ - ``statusValueFilter`` (object): ``include``, a list of statuses such as
212
+ ``PAID_IN_FULL`` or ``ACCUMULATING``.
213
+ - ``countryValueFilter`` (object): ``include``, up to 30 country codes.
214
+ - ``invoiceNumberFilter`` (object): ``include``, up to 30 invoice numbers.
215
+ - ``paymentMethodTypeValueFilter`` (object): ``include``, up to 10 method
216
+ types.
217
+ - ``reserveOrderNumberFilter`` (object): ``include``, up to 30 reserve
218
+ order numbers.
219
+ - ``sort`` (object): ``attribute`` and ``direction``. The only
220
+ attributes the service accepts are ``invoiceIssuedDate`` and
221
+ ``invoiceDueDate``; anything else answers
222
+ ``400 Invalid input because of error(s): [sort:attribute field is
223
+ invalid]``. Those are the names the answer uses, not the filter names:
224
+ ``invoiceDate``, ``issuedDate``, ``dueDate``, ``amountDue`` and
225
+ ``status`` are all refused.
226
+ - ``maxResults`` (integer): page size.
227
+ - ``nextToken`` (string): token from a previous answer.
228
+ - ``aggregation`` (object): ``attribute`` and ``groupBy``, to total
229
+ rather than list.
230
+
231
+ The ``include`` filters also accept ``queryTermMatchType``, which decides
232
+ how the term is matched.
233
+
234
+ Returns
235
+ ApiResponse with ``invoiceSummaries``. Each entry is richer than what
236
+ ``Invoices.list_invoices`` returns and shaped differently: dates come
237
+ as ``"2026-10-26"`` rather than ``"20261026"``, and most fields are
238
+ ``{"code": ..., "value": ...}`` pairs rather than plain strings. A
239
+ summary carries ``id``, ``invoiceIssuedDate``, ``invoiceDueDate``,
240
+ ``amountDue`` and ``remainingAmountDue`` (each with a
241
+ ``currencyCode`` and a ``value``), ``status``, ``paymentStatus``,
242
+ ``country``, ``product``, ``paymentMethodType``, ``invoicingLevel``
243
+ and ``fxInformation``.
244
+
245
+ """
246
+ headers = {
247
+ 'Accept': 'application/vnd.billingInvoiceSummary.v1+json',
248
+ 'Content-Type': 'application/vnd.billingInvoiceSummary.v1+json',
249
+ }
250
+ body = Utils.convert_body(kwargs.pop('body'), False)
251
+ return self._request(kwargs.pop('path'), data=body, params=kwargs, headers=headers)
252
+
253
+ @sp_endpoint('/billingProfiles/list', method='POST')
254
+ def list_billing_profiles(self, **kwargs) -> ApiResponse:
255
+ r"""
256
+ Lists the billing profiles of the account.
257
+
258
+ A billing profile decides who gets invoiced and with which payment
259
+ method, so this is the starting point before reading usages or creating
260
+ a statement.
261
+
262
+ Request Body (optional)
263
+
264
+ - ``filters`` (object): narrow the list.
265
+ - ``maxResults`` (integer): page size.
266
+ - ``nextToken`` (string): token from a previous answer.
267
+
268
+ .. warning::
269
+
270
+ The service refuses marketplace accounts. Called from a regional
271
+ seller account it answers ``400 The API doesnot support marketplace
272
+ accounts``. It wants a Global, Manager or Sponsored Ads account.
273
+
274
+ Returns
275
+ ApiResponse with the profiles and the token for the next page.
276
+
277
+ """
278
+ headers = {
279
+ 'Accept': 'application/vnd.billingProfile.v1+json',
280
+ 'Content-Type': 'application/vnd.billingProfile.v1+json',
281
+ }
282
+ body = Utils.convert_body(kwargs.pop('body'), False)
283
+ return self._request(kwargs.pop('path'), data=body, params=kwargs, headers=headers)
284
+
285
+ @sp_endpoint('/billingProfileUsages/list', method='POST')
286
+ def list_billing_profile_usages(self, **kwargs) -> ApiResponse:
287
+ r"""
288
+ Lists which billing profile each country uses.
289
+
290
+ The answer links a country to a ``billingProfileId``. With
291
+ ``expandBillingProfile`` it carries the whole profile rather than the
292
+ identifier.
293
+
294
+ Request Body (optional)
295
+
296
+ - ``expandBillingProfile`` (boolean): return the full profile, not only
297
+ its id.
298
+ - ``expandFallbackBillingProfile`` (boolean): also return the profile
299
+ that would apply if the main one could not be used.
300
+ - ``filters`` (object): narrow by country or profile.
301
+ - ``maxResults`` (integer): page size.
302
+ - ``nextToken`` (string): token from a previous answer.
303
+
304
+ .. warning::
305
+
306
+ Same account restriction as ``list_billing_profiles``, and the
307
+ message names what it wants: ``only Global, Manager and Sponsored
308
+ Ads marketplace accounts are supported``.
309
+
310
+ Returns
311
+ ApiResponse with one entry per country and profile pairing.
312
+
313
+ """
314
+ headers = {
315
+ 'Accept': 'application/vnd.billingProfileUsage.v1+json',
316
+ 'Content-Type': 'application/vnd.billingProfileUsage.v1+json',
317
+ }
318
+ body = Utils.convert_body(kwargs.pop('body'), False)
319
+ return self._request(kwargs.pop('path'), data=body, params=kwargs, headers=headers)
320
+
321
+ @sp_endpoint('/billing/documents/{}', method='GET')
322
+ def get_billing_document(self, documentId, **kwargs) -> ApiResponse:
323
+ r"""
324
+ Reads one billing document.
325
+
326
+ Path
327
+
328
+ - ``documentId`` (string): required.
329
+
330
+ Query
331
+
332
+ - ``docType`` (string): required in practice, though the contract lists
333
+ it as a plain parameter. Without it the service answers
334
+ ``400 Value null at 'docType' failed to satisfy constraint``.
335
+
336
+ Returns
337
+ ApiResponse with the document.
338
+
339
+ """
340
+ headers = {'Accept': 'application/vnd.billingDocuments.v1+json'}
341
+ return self._request(fill_query_params(kwargs.pop('path'), documentId),
342
+ params=kwargs, headers=headers)
343
+
344
+ @sp_endpoint('/billingProfileAgreementContents/{}', method='GET')
345
+ def get_billing_profile_agreement_content(self, billingProfileAgreementContentId, **kwargs) -> ApiResponse:
346
+ r"""
347
+ Reads the agreement text attached to a billing profile.
348
+
349
+ Path
350
+
351
+ - ``billingProfileAgreementContentId`` (string): required.
352
+
353
+ Query
354
+
355
+ - ``languageOfPreference`` (string): the language the text comes back in.
356
+
357
+ Returns
358
+ ApiResponse with the agreement content.
359
+
360
+ """
361
+ headers = {'Accept': 'application/vnd.billingProfileAgreement.v1+json'}
362
+ return self._request(
363
+ fill_query_params(kwargs.pop('path'), billingProfileAgreementContentId),
364
+ params=kwargs, headers=headers)
365
+
366
+ @sp_endpoint('/billingStatements/{}', method='GET')
367
+ def get_billing_statement(self, billingStatementRequestId, **kwargs) -> ApiResponse:
368
+ r"""
369
+ Reports on a billing statement request.
370
+
371
+ The identifier comes from the route that creates the statement request,
372
+ and this reads its progress or its result.
373
+
374
+ .. note::
375
+
376
+ The contract answers this read with
377
+ ``vnd.createbillingstatementsrequest.v1``, the same media type the
378
+ creation route uses. That is what it declares, odd as the name is.
379
+
380
+ Path
381
+
382
+ - ``billingStatementRequestId`` (string): required. Three names are in
383
+ play for this one value: the contract calls it
384
+ ``billingStatementRequestId``, the method takes
385
+ ``billingStatementRequestId``, and a rejected call comes back naming
386
+ ``billingStatementId``.
387
+
388
+ The error for a malformed value also mentions a ``request`` parameter the
389
+ contract does not list.
390
+
391
+ Returns
392
+ ApiResponse with the state of that request.
393
+
394
+ """
395
+ headers = {'Accept': 'application/vnd.createbillingstatementsrequest.v1+json'}
396
+ return self._request(fill_query_params(kwargs.pop('path'), billingStatementRequestId),
397
+ params=kwargs, headers=headers)
398
+
399
+ @sp_endpoint('/billingStatements', method='POST')
400
+ def create_billing_statement(self, **kwargs) -> ApiResponse:
401
+ r"""
402
+ Asks the service to generate a billing statement for a period.
403
+
404
+ The work is asynchronous. This answers a ``requestId``, and
405
+ ``get_billing_statement`` reads the state of that request.
406
+
407
+ Request Body (required)
408
+
409
+ - ``startDate`` (string): required. The first day of the period.
410
+ - ``endDate`` (string): required. The last day of the period.
411
+ - ``locale`` (string): required. The language the statement comes back
412
+ in.
413
+ - ``countryCodes`` (array): the countries to cover.
414
+ - ``format`` (string): ``CSV`` is the only value the contract lists.
415
+
416
+ Returns
417
+ ApiResponse with the request identifier. The contract answers
418
+ ``207``, a multi-status, not ``200``.
419
+
420
+ """
421
+ headers = {
422
+ 'Accept': 'application/vnd.createbillingstatementsrequest.v1+json',
423
+ 'Content-Type': 'application/vnd.createbillingstatementsrequest.v1+json',
424
+ }
425
+ body = Utils.convert_body(kwargs.pop('body'), False)
426
+ return self._request(kwargs.pop('path'), data=body, params=kwargs, headers=headers)
427
+
428
+ @sp_endpoint('/billingProfileUsages', method='POST')
429
+ def apply_billing_profile(self, **kwargs) -> ApiResponse:
430
+ r"""
431
+ Links one or more countries to a billing profile.
432
+
433
+ The service calls this applying a profile: after it, the countries named
434
+ charge through that profile.
435
+
436
+ Request Body (required)
437
+
438
+ - ``billingProfileUsages`` (array): required. One entry per country and
439
+ profile pairing, which reads back in the same shape
440
+ ``list_billing_profile_usages`` returns.
441
+
442
+ The contract does not describe the fields inside each entry, so read one
443
+ back from ``list_billing_profile_usages`` before building a body here.
444
+
445
+ .. warning::
446
+
447
+ Not exercised. Applying a profile changes how an account gets
448
+ charged.
449
+
450
+ Returns
451
+ ApiResponse. The contract answers ``207``, a multi-status, not
452
+ ``200``.
453
+
454
+ """
455
+ headers = {
456
+ 'Accept': 'application/vnd.billingProfileUsage.v1+json',
457
+ 'Content-Type': 'application/vnd.billingProfileUsage.v1+json',
458
+ }
459
+ body = Utils.convert_body(kwargs.pop('body'), False)
460
+ return self._request(kwargs.pop('path'), data=body, params=kwargs, headers=headers)
461
+
462
+ @sp_endpoint('/billingProfiles', method='POST')
463
+ def create_billing_profiles(self, **kwargs) -> ApiResponse:
464
+ r"""
465
+ Creates one or more billing profiles.
466
+
467
+ Request Body (required)
468
+
469
+ - ``billingProfiles`` (array): required, between 0 and 100 entries. Each
470
+ one describes a profile to create.
471
+
472
+ The contract names the list and stops there: the fields of an entry are
473
+ not described. Read one back from ``list_billing_profiles`` for the
474
+ shape, rather than guessing at it.
475
+
476
+ .. warning::
477
+
478
+ Not exercised. Creating a billing profile changes how an account gets
479
+ invoiced.
480
+
481
+ Returns
482
+ ApiResponse. The contract answers ``207``, a multi-status, not
483
+ ``200``.
484
+
485
+ """
486
+ headers = {
487
+ 'Accept': 'application/vnd.billingProfile.v1+json',
488
+ 'Content-Type': 'application/json',
489
+ }
490
+ body = Utils.convert_body(kwargs.pop('body'), False)
491
+ return self._request(kwargs.pop('path'), data=body, params=kwargs, headers=headers)
492
+
493
+ @sp_endpoint('/billingProfiles', method='PUT')
494
+ def update_billing_profiles(self, **kwargs) -> ApiResponse:
495
+ r"""
496
+ Updates one or more billing profiles.
497
+
498
+ Request Body
499
+
500
+ - ``billingProfiles`` (array): between 0 and 100 entries. Each one names
501
+ a profile and the fields to change.
502
+
503
+ The same gap as ``create_billing_profiles``: the contract does not
504
+ describe the fields inside an entry.
505
+
506
+ .. warning::
507
+
508
+ Not exercised, for the same reason as the create route.
509
+
510
+ Returns
511
+ ApiResponse. The contract answers ``207``, a multi-status, not
512
+ ``200``.
513
+
514
+ """
515
+ headers = {
516
+ 'Accept': 'application/vnd.billingProfile.v1+json',
517
+ 'Content-Type': 'application/json',
518
+ }
519
+ body = Utils.convert_body(kwargs.pop('body'), False)
520
+ return self._request(kwargs.pop('path'), data=body, params=kwargs, headers=headers)
521
+
522
+ @sp_endpoint('/billing/paymentProfiles', method='POST')
523
+ def create_payment_profiles(self, **kwargs) -> ApiResponse:
524
+ r"""
525
+ Creates one or more payment profiles.
526
+
527
+ Request Body (required)
528
+
529
+ - ``paymentProfiles`` (array): required. Each entry describes a profile:
530
+ which payment methods to use and in what order.
531
+
532
+ The contract names the list and does not describe its entries. The shape
533
+ of a payment method reads back from ``get_payment_agreements``, whose
534
+ agreements carry a ``paymentProfile`` holding ``paymentMethods`` ordered
535
+ by ``priority``.
536
+
537
+ .. warning::
538
+
539
+ Not exercised. A payment profile decides where money is taken from.
540
+
541
+ Returns
542
+ ApiResponse. The contract answers ``207``, a multi-status, not
543
+ ``200``.
544
+
545
+ """
546
+ headers = {
547
+ 'Accept': 'application/vnd.paymentprofiles.v1+json',
548
+ 'Content-Type': 'application/json',
549
+ }
550
+ body = Utils.convert_body(kwargs.pop('body'), False)
551
+ return self._request(kwargs.pop('path'), data=body, params=kwargs, headers=headers)
@@ -5,9 +5,6 @@ class Invoices(Client):
5
5
  @sp_endpoint('/invoices', method='GET')
6
6
  def list_invoices(self, **kwargs) -> ApiResponse:
7
7
  r"""
8
-
9
- list_invoices(**kwargs) -> ApiResponse
10
-
11
8
  Get invoices for advertiser. Requires one of these permissions: ["nemo_transactions_view","nemo_transactions_edit"]
12
9
 
13
10
  query **invoiceStatuses**:*string* | Optional. Available values : ISSUED, PAID_IN_PART, PAID_IN_FULL, WRITTEN_OFF. (Not documented: ACCUMULATING)
@@ -19,7 +16,14 @@ class Invoices(Client):
19
16
 
20
17
  Returns:
21
18
 
22
- ApiResponse
19
+ ApiResponse whose payload carries a second layer::
20
+
21
+ {"status": "success",
22
+ "payload": {"nextCursor": "...", "invoiceSummaries": [...]}}
23
+
24
+ The invoices sit at ``res.payload["payload"]["invoiceSummaries"]``.
25
+ Reading ``res.payload["invoiceSummaries"]`` gives ``None``, because
26
+ that key belongs to the inner object.
23
27
 
24
28
  """
25
29
  return self._request(kwargs.pop('path'), params=kwargs)
@@ -27,16 +31,14 @@ class Invoices(Client):
27
31
  @sp_endpoint('/invoices/{}', method='GET')
28
32
  def get_invoice(self, invoiceId, **kwargs) -> ApiResponse:
29
33
  r"""
30
-
31
- get_invoice(invoiceId: str) -> ApiResponse
32
-
33
34
  Get invoice data by invoice ID. Requires one of these permissions: ["nemo_transactions_view","nemo_transactions_edit"]
34
35
 
35
36
  path **invoiceId**:*string* | required. ID of invoice to fetch
36
37
 
37
38
  Returns:
38
39
 
39
- ApiResponse
40
+ ApiResponse with the same two layers as ``list_invoices``: the
41
+ invoice data sits under ``res.payload["payload"]``.
40
42
 
41
43
  """
42
44
  return self._request(fill_query_params(kwargs.pop('path'), invoiceId), params=kwargs)