python-amazon-ad-api 1.2.7__py3-none-any.whl → 1.2.9__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.
- ad_api/api/billing.py +469 -5
- ad_api/api/invoices.py +10 -8
- ad_api/api/recommendations.py +39 -2
- ad_api/version.py +1 -1
- {python_amazon_ad_api-1.2.7.dist-info → python_amazon_ad_api-1.2.9.dist-info}/METADATA +2 -2
- {python_amazon_ad_api-1.2.7.dist-info → python_amazon_ad_api-1.2.9.dist-info}/RECORD +9 -9
- {python_amazon_ad_api-1.2.7.dist-info → python_amazon_ad_api-1.2.9.dist-info}/WHEEL +0 -0
- {python_amazon_ad_api-1.2.7.dist-info → python_amazon_ad_api-1.2.9.dist-info}/licenses/LICENSE +0 -0
- {python_amazon_ad_api-1.2.7.dist-info → python_amazon_ad_api-1.2.9.dist-info}/top_level.txt +0 -0
ad_api/api/billing.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from ad_api.base import Client, sp_endpoint, ApiResponse, Utils
|
|
1
|
+
from ad_api.base import Client, sp_endpoint, fill_query_params, ApiResponse, Utils
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class Billing(Client):
|
|
@@ -58,14 +58,71 @@ class Billing(Client):
|
|
|
58
58
|
|
|
59
59
|
@sp_endpoint('/billing/paymentMethods/list', method='POST')
|
|
60
60
|
def get_customer_payment_methods(self, **kwargs) -> ApiResponse:
|
|
61
|
-
r"""
|
|
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
|
+
"""
|
|
62
86
|
accept_contentType = 'application/vnd.paymentmethods.v1+json'
|
|
63
87
|
headers = {'Accept': accept_contentType}
|
|
64
88
|
return self._request(kwargs.pop('path'), params=kwargs, headers=headers)
|
|
65
89
|
|
|
66
90
|
@sp_endpoint('/billing/invoices/pay', method='POST')
|
|
67
91
|
def pay_invoices(self, **kwargs) -> ApiResponse:
|
|
68
|
-
r"""
|
|
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
|
+
"""
|
|
69
126
|
accept_contentType = 'application/vnd.invoices.v1+json'
|
|
70
127
|
headers = {'Accept': accept_contentType}
|
|
71
128
|
body = Utils.convert_body(kwargs.pop('body'), False)
|
|
@@ -73,15 +130,422 @@ class Billing(Client):
|
|
|
73
130
|
|
|
74
131
|
@sp_endpoint('/billing/paymentAgreements/list', method='POST')
|
|
75
132
|
def get_payment_agreements(self, **kwargs) -> ApiResponse:
|
|
76
|
-
r"""
|
|
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
|
+
"""
|
|
77
155
|
accept_contentType = 'application/vnd.paymentagreements.v1+json'
|
|
78
156
|
headers = {'Accept': accept_contentType}
|
|
79
157
|
return self._request(kwargs.pop('path'), params=kwargs, headers=headers)
|
|
80
158
|
|
|
81
159
|
@sp_endpoint('/billing/paymentAgreements', method='POST')
|
|
82
160
|
def create_payment_agreements(self, **kwargs) -> ApiResponse:
|
|
83
|
-
r"""
|
|
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
|
+
"""
|
|
84
185
|
accept_contentType = 'application/vnd.paymentagreements.v1+json'
|
|
85
186
|
headers = {'Accept': accept_contentType}
|
|
86
187
|
body = Utils.convert_body(kwargs.pop('body'), False)
|
|
87
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)
|
ad_api/api/invoices.py
CHANGED
|
@@ -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)
|
ad_api/api/recommendations.py
CHANGED
|
@@ -13,7 +13,7 @@ class Recommendations(Client):
|
|
|
13
13
|
| ListRecommendationsRequest {
|
|
14
14
|
| **maxResults** (integer) default: 500 minimum: 1 maximum: 500
|
|
15
15
|
| **nextToken** (string) Token to retrieve the next page of results.
|
|
16
|
-
| **filters
|
|
16
|
+
| **filters** (array) minItems: 1 maxItems: 10 [
|
|
17
17
|
| ListRecommendationsFilter {
|
|
18
18
|
| **include** (boolean): Flag to specify if the filter should be included or excluded. default: true
|
|
19
19
|
| **field**\* FilterField (string): Field to filter by. Enum: ['RECOMMENDATION_ID', 'AD_PRODUCT', 'RECOMMENDATION_TYPE', 'STATUS', 'GROUPING_TYPE', 'CAMPAIGN_ID']
|
|
@@ -24,8 +24,27 @@ class Recommendations(Client):
|
|
|
24
24
|
| }
|
|
25
25
|
| ]
|
|
26
26
|
| }
|
|
27
|
+
|
|
28
|
+
The values ``STATUS`` accepts are not the states of a campaign. They are
|
|
29
|
+
the stages a recommendation passes through, and the service names them in
|
|
30
|
+
its rejection message: ``PUBLISHED``, ``APPLY_IN_PROGRESS``,
|
|
31
|
+
``APPLY_SUCCESS``, ``APPLY_FAILED`` and ``REJECTED``. ``ENABLED`` and
|
|
32
|
+
``ACTIVE`` are refused.
|
|
33
|
+
|
|
34
|
+
``filters`` behaves oddly. An empty list answers
|
|
35
|
+
``400 Member must have length greater than or equal to 1``, yet leaving
|
|
36
|
+
the member out altogether answers ``200`` with the account's
|
|
37
|
+
recommendations. So it is required when present, and optional in
|
|
38
|
+
practice.
|
|
39
|
+
|
|
40
|
+
A body is required: without one the call fails before reaching the
|
|
41
|
+
service, with ``KeyError: 'body'``.
|
|
42
|
+
|
|
27
43
|
Returns
|
|
28
|
-
ApiResponse
|
|
44
|
+
ApiResponse with ``recommendations``, ``totalResults`` and
|
|
45
|
+
``nextToken``. The list is empty for an account that has none, which
|
|
46
|
+
is a fact about the account rather than a failed call.
|
|
47
|
+
|
|
29
48
|
"""
|
|
30
49
|
schema_version = 'application/vnd.listRecommendationsRequest.v' + str(version) + '+json'
|
|
31
50
|
headers = {"Accept": schema_version, "Content-Type": schema_version}
|
|
@@ -42,6 +61,15 @@ class Recommendations(Client):
|
|
|
42
61
|
| (string) Recommendation identifier.
|
|
43
62
|
| ]
|
|
44
63
|
| }
|
|
64
|
+
|
|
65
|
+
.. warning::
|
|
66
|
+
|
|
67
|
+
This changes campaigns. Applying a recommendation edits real bidding
|
|
68
|
+
and budgets on the account, and there is no undo richer than
|
|
69
|
+
changing them back by hand.
|
|
70
|
+
|
|
71
|
+
Not exercised: no recommendation existed on the account to apply.
|
|
72
|
+
|
|
45
73
|
Returns
|
|
46
74
|
ApiResponse
|
|
47
75
|
"""
|
|
@@ -79,6 +107,15 @@ class Recommendations(Client):
|
|
|
79
107
|
| }
|
|
80
108
|
| }
|
|
81
109
|
| }
|
|
110
|
+
|
|
111
|
+
.. warning::
|
|
112
|
+
|
|
113
|
+
This edits a recommendation before it is applied. Read one first with
|
|
114
|
+
``list_recommendations`` for the shape it expects, since the fields
|
|
115
|
+
change with ``recommendationType``.
|
|
116
|
+
|
|
117
|
+
Not exercised, for the same reason as ``apply_recommendations``.
|
|
118
|
+
|
|
82
119
|
Returns
|
|
83
120
|
ApiResponse
|
|
84
121
|
|
ad_api/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.2.
|
|
1
|
+
__version__ = "1.2.9"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-amazon-ad-api
|
|
3
|
-
Version: 1.2.
|
|
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
|
|
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
|
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
ad_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
ad_api/version.py,sha256=
|
|
2
|
+
ad_api/version.py,sha256=Oh3Y6CIypkhAjW-aquBTyP3_cA-gKgKTwq9EpcWpjps,22
|
|
3
3
|
ad_api/api/__init__.py,sha256=E9c0ZyK4vplMlKKEBF8CV5u7P4uSkTMSQsAuSQu5bfY,1514
|
|
4
4
|
ad_api/api/account.py,sha256=CmOvCfHoPWaeTUJvtB0pNoNulZVSz4oMMCKIpVTpHos,2931
|
|
5
5
|
ad_api/api/advertising_test_account.py,sha256=btOVbdk2tBDmyKSJaQbcIFyzNG8KFJVUmTe4p9xMhpU,1507
|
|
6
6
|
ad_api/api/attribution.py,sha256=vHmXP0wDqhEqaS1q3tJyERxJ1JwntqoEb73LVXNHxR0,5121
|
|
7
7
|
ad_api/api/audiences.py,sha256=TQPt4avswFdCodNfQGDGxcJ2mY2LP2BfYvjxP6oJ0qY,3491
|
|
8
|
-
ad_api/api/billing.py,sha256=
|
|
8
|
+
ad_api/api/billing.py,sha256=pmBQzejCM8YIsI51KTVunDTVTKMIaox0D2B4acH4w6Y,23526
|
|
9
9
|
ad_api/api/brand_metrics.py,sha256=IlOlVJ2t6cL5DA49RaM3M1AW_3KFEyal08e0ZcnLdVE,6036
|
|
10
10
|
ad_api/api/creative_assets.py,sha256=u0bCnioUFpGOQO5Z_MO0ErSLcAgSZB5GWM5wm2oW6L0,9687
|
|
11
11
|
ad_api/api/eligibility.py,sha256=xbHMNxpRqToQDlG8y7nhhSr55ZZIJ_ZA304rmWa7Jx0,3680
|
|
12
12
|
ad_api/api/exports.py,sha256=Y59C99axCAltMgu3gbfzdnoLKjNTsJ7s1z18yzcxzls,2788
|
|
13
13
|
ad_api/api/history.py,sha256=tB4XawmQNxDMolaubDUjuIHtrYXRFuhOr4WCB8OJ1t8,2568
|
|
14
14
|
ad_api/api/insights.py,sha256=b0m2_khfDGskbvn4sidsUpOvV-gr2bsjUup0kSo8HV8,2398
|
|
15
|
-
ad_api/api/invoices.py,sha256=
|
|
15
|
+
ad_api/api/invoices.py,sha256=k3QYOM1B82tx9QSm-x3cDsDYVJ8E6eosQHSHgcYGcbY,1959
|
|
16
16
|
ad_api/api/localization.py,sha256=HdkChAawloJ8zj5rCye9NVf7kLnQ7vW6aKsBLZ2W-gI,17158
|
|
17
17
|
ad_api/api/manager_accounts.py,sha256=tnmJxOGIKTuJ3i8wciwfs931REW0aeNKQiqCpBrTZ2Y,5107
|
|
18
18
|
ad_api/api/metadata.py,sha256=vWPbDGvEB72421fjSu4KrNkTdrIijHTPV8k36hceSbA,2406
|
|
19
19
|
ad_api/api/portfolios.py,sha256=Oe3LS2HsjMJSq1Id8cwOWrH2AiPMcBb7oTkFHjudnTI,7103
|
|
20
20
|
ad_api/api/portfolios_v3.py,sha256=qqIzXmhnb3g2QmTENsgzOayhvOObgI-rD7PTfftgDQg,6842
|
|
21
21
|
ad_api/api/profiles.py,sha256=mMSCUd5HdR_nFBDFngLY94tIfMCA4yGnjHz-PSMe0rE,7200
|
|
22
|
-
ad_api/api/recommendations.py,sha256=
|
|
22
|
+
ad_api/api/recommendations.py,sha256=_r4LsJkRTkiuOvzS7wrtR2ZmxA7gGe-T4jRDAqM6pRo,6198
|
|
23
23
|
ad_api/api/reports.py,sha256=gNmDHLULD2uaJgsMpIbCX9kabwhMXRr9WfZBtHUdsOY,6043
|
|
24
24
|
ad_api/api/stores.py,sha256=7W3RJKZyZOQ3nHzInvK9FDhWTXCH6Xe9a6dCBatEZ-o,2484
|
|
25
25
|
ad_api/api/stream.py,sha256=JpnF8SKniOAHiEnEq1RPrh6tNy-Q2-8GPBTmnlxEXqQ,2989
|
|
@@ -108,8 +108,8 @@ ad_api/base/exceptions.py,sha256=9D3M40ZIlLS0fA-aQh1BTWPOW-Nvf0tRhbA85jFnDJ4,438
|
|
|
108
108
|
ad_api/base/helpers.py,sha256=UK7Q13vZ0mNdF54xzfzoGDn2O_cd2yPrK2X4rOzC41c,2334
|
|
109
109
|
ad_api/base/marketplaces.py,sha256=44lvCcluXNpqTprWQ80e3weSQmQbJoWL-WDSOWVbCyQ,4657
|
|
110
110
|
ad_api/base/utils.py,sha256=_qnCBOvyJTLgaZjJzUWTi38GGLHkQszXELs79133Rb4,5618
|
|
111
|
-
python_amazon_ad_api-1.2.
|
|
112
|
-
python_amazon_ad_api-1.2.
|
|
113
|
-
python_amazon_ad_api-1.2.
|
|
114
|
-
python_amazon_ad_api-1.2.
|
|
115
|
-
python_amazon_ad_api-1.2.
|
|
111
|
+
python_amazon_ad_api-1.2.9.dist-info/licenses/LICENSE,sha256=h2rpqlmmLy-4l1tN6KpWAFxx1JEMYeEFrMrZUbx_B_o,1105
|
|
112
|
+
python_amazon_ad_api-1.2.9.dist-info/METADATA,sha256=gNxUotCSe2RmLZqPldHBTNHH9nCRge39UnuV5rxkQsw,21453
|
|
113
|
+
python_amazon_ad_api-1.2.9.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
114
|
+
python_amazon_ad_api-1.2.9.dist-info/top_level.txt,sha256=nN9twUos-8pkP514ZwpvRU9YL9L2XyQyHsMQFfudGTU,7
|
|
115
|
+
python_amazon_ad_api-1.2.9.dist-info/RECORD,,
|
|
File without changes
|
{python_amazon_ad_api-1.2.7.dist-info → python_amazon_ad_api-1.2.9.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|