Change History
https://d1y2lf8k3vrkfu.cloudfront.net/openapi/en-us/dest/Changehistory_prod_3p.json
Provides information about changes made to campaigns, ad groups, ads and the rest of the entity tree.
Specification: https://d1y2lf8k3vrkfu.cloudfront.net/openapi/en-us/dest/Changehistory_prod_3p.json Documentation: https://advertising.amazon.com/API/docs/en-us/change-history/
- class ad_api.api.History(account: str = 'default', marketplace: Marketplaces = Marketplaces.EU, credentials: Dict[str, str] | None = None, proxies: Dict[str, str] | None = None, verify: bool = True, timeout: int | None = None, debug: bool = False, access_token: str | None = None, verify_additional_credentials: bool = True)
Note
The contract is version 3.0 and carries no beta marker: no
x-beta, nox-amz-*, no deprecation notice. The page is listed as stable because of that.### Endpoint map
:header-rows: 1 Path
Method
Media type
Answer
POST /historyget_historyvnd.historyresponse.v1.0200POST /historywithversion="1.1"get_historyvnd.historyresponse.v1.1200The second row is the same route.
THEMEis the only event type that needs version 1.1; at 1.0 the service answers400and names it.### Event types
:header-rows: 1 Type
Version needed
AD1.0
AD_GROUP1.0
CAMPAIGN1.0
KEYWORD1.0
NEGATIVE_KEYWORD1.0
PRODUCT_TARGETING1.0
THEME1.1
### Request body
:header-rows: 1 Field
Type
Meaning
fromDateinteger
Required. Epoch in milliseconds. At most 90 days back, counted from the moment of the request.
toDateinteger
Required. Epoch in milliseconds.
eventTypesobject
Required. One or more of the types above, each carrying an object, usually
{}or{"filters": [...]}.countinteger
Page size. Default 100, minimum 50, maximum 200.
nextTokenstring
Token from a previous answer. Mutually exclusive with
pageOffset.pageOffsetinteger
Alternative to
nextToken, up to 10000.sortobject
{"direction": "ASC"|"DESC", "key": "DATE"}.The names are camelCase. A body written with
from_dateanswers400and namesfromDateas a required field.### Answer
:header-rows: 1 Field
Type
Meaning
eventsarray
The changes found, empty when there were none.
pageSizeinteger
The page size the service applied, taken from
count.pageOffsetinteger
Where this page starts.
maxPageNumberinteger
The last page number reachable.
totalRecordsinteger
How many changes the account has in the window.
An empty
eventswithtotalRecordsat0means the account saw no change in that window. The call worked; there was nothing to report.### Two things that cost time
The window moves. Ninety days is counted from the service clock at the moment of the request. A window computed once at the top of a script and reused drifts past the edge and answers
400 fromDate is more than 90 days ago. In testing, 717 milliseconds of drift was enough. Compute it per call and leave a day of slack.The route throttles. Seven calls within twelve seconds answered
429 Too Many Requests. Space them out.### Example python
from datetime import datetime, timedelta, timezone from ad_api.api import History def get_history(): now = datetime.now(timezone.utc) frm = now - timedelta(days=7) # 90 max, leave slack body = { "fromDate": int(frm.timestamp() * 1000), "toDate": int(now.timestamp() * 1000), "eventTypes": {"CAMPAIGN": {"filters": ["STATUS"]}}, "count": 50, "sort": {"direction": "DESC", "key": "DATE"}, } res = History(account='my_account', debug=False).get_history(body=body) p = res.payload print(f"{p['totalRecords']} cambios") for event in p["events"]: print(event) if __name__ == '__main__': get_history()
### Example with THEME
THEMEneeds version 1.1. The method takes it as a string, because the versions are1.0and1.1.from datetime import datetime, timedelta, timezone from ad_api.api import History now = datetime.now(timezone.utc) frm = now - timedelta(days=7) body = { "fromDate": int(frm.timestamp() * 1000), "toDate": int(now.timestamp() * 1000), "eventTypes": {"THEME": {"filters": ["STATUS"]}}, } res = History(account='my_account', debug=False).get_history( body=body, version="1.1")
### Example query.json
Download
jsonthe file to use:{ "fromDate": 1626739199000, "toDate": 1632095999000, "pageOffset": 10, "count": 60, "sort": { "key": "DATE", "direction": "DESC" }, "eventTypes": { "CAMPAIGN": { "filters": [ "BUDGET_AMOUNT" ], "eventTypeIds": [ "137359064782313" ] } } }
- get_history(version: str = '1.0', **kwargs) ApiResponse
Returns the changes made to campaigns, ad groups, ads and the rest of the entity tree, within a time range. Only events belonging to the authenticated advertiser come back.
Keyword Args
version(string): theAcceptversion,"1.0"by default. Pass"1.1"to query theTHEMEevent type, which the service refuses at 1.0. The other six types work at either. [optional]
Request Body (required)
fromDate(integer): epoch in milliseconds, not seconds.toDate(integer): epoch in milliseconds.eventTypes(object): one or more ofAD,AD_GROUP,CAMPAIGN,KEYWORD,NEGATIVE_KEYWORD,PRODUCT_TARGETINGandTHEME. Each carries an object, usually{}or{"filters": [...]}.count(integer): page size. Default 100, minimum 50, maximum 200.nextToken(string): token from a previous answer. Mutually exclusive withpageOffset.pageOffset(integer): alternative tonextToken, up to 10000.sort(object):{"direction": "ASC"|"DESC", "key": "DATE"}.
The field names are camelCase and the service rejects anything else: a body written with
from_dateanswers400namingfromDateas a required field. The dates are counted back from the moment of the request, so a window computed once and reused drifts out of range: the service measures 90 days from its own clock, and a few seconds of drift past the edge answers400 fromDate is more than 90 days ago.This route throttles. Seven calls within twelve seconds answered
429.- Returns
ApiResponse with
events,pageSize,pageOffset,maxPageNumberandtotalRecords. An emptyeventswithtotalRecordsat0means the account saw no change in the window, not that the call failed.