One-stop report retrieval: the script passes through developerProxy to profileId(server-side token parsing), automatically completing report creation, waiting (about 2–10 minutes), download, and decompression, directly returning readable structured data.
The script itself does not make business judgments about "which columns to select / how to group"—these are determined by the agent first checking references/report-types/ for the corresponding .md file, then explicitly passing it to the script.
Depends on linkfox-amazon-ads-auth(automatically checked at script startup; if not installed, exit 42, stderr prints DEPENDENCY_MISSING)。
⚠️ Multi-account scenario: profileId must be resolved before calling
Users often only speak in natural language ("US site", "Japan site", "my store"); all scripts in this skill must obtain the numeric profileId before they can be called. Handle in the following order,do not skip:
- First call
linkfox-amazon-ads-auth'sauthorized_stores.pyto pull the list of accounts × sites the user has authorized. - Based on the site mentioned by the user (mapped to
countryCode, e.g. US→US) match candidate profiles:- Only 1 candidate → silently take the corresponding profileId and continue the call; do not announce the profileId number to the user.
- ≥ 2 candidates (multiple authorized accounts under the same site) → must clarify with the user, using
accountNameto ask: "You have authorized two accounts, A and B, on the US site. Which one should be used this time?" - 0 candidates → inform the user that this site is not authorized, and guide them to
linkfox-amazon-ads-authto perform authorization.
- Strictly prohibitedto have the user directly report the profileId number.
- Strictly prohibitedto "pick the first one" or "choose the default" under ambiguity to bypass clarification.
For the complete decision table, see linkfox-amazon-ads-auth SKILL.md's Usage Scenarios Section 4。
How to Call
- API Endpoint:
POST /amazonAds/developerProxy(different operations are distinguished by the request body; for complete parameters/responses/error codes seereferences/api.md) - Python Script:
python scripts/<脚本名>.py '<JSON 参数>' [--inline](for available scripts see the script list above) - Cost Constraint: This tool consumes compute; on failure/empty results, do not automatically switch keywords, paginate, or continuously probe; if further retrieval is needed, first explain to the user that additional consumption will be incurred.
Output Strategy (Default Script Behavior):
- Alwayswrite the complete response to
<cwd>/linkfox/<YYYY-MM-DD>/<session>/data/<skill-name>-<timestamp>.json(<cwd>is the working directory when the script executes, which in Claude Code is the current project directory;<session>is taken from the environment variableSESSION_ID, automatically aggregated according to the user's task;writing to /tmp is prohibited, if the current directory is not writable, report an error) - Response body ≤ 8 KB: after writing to disk, print the complete JSON to stdout
- Response body > 8 KB: after writing to disk, stdout outputs only a summary (top-level fields, common counts such as
total/costToken, length of the largest list field + first 3 samples) - Add
--inlineto force full printing to stdout (also written to disk)
Data Reading Suggestions: first look at the summary to judge whether it is sufficient; when specific fields are needed, prefer jqorConvertFrom-JsonorConvertFrom-Json Extract on demand from the saved json file to avoid the entire JSON entering the context.
Resolve authentication and compute power issues
When the following abnormal situations occur, use references/onboarding.md to guide problem resolution:
Abnormal situations
- API Key not configured: The environment variable is not configured
LINKFOX_AGENT_API_KEY, andLINKFOXAGENT_API_KEY。 - Response 401 or 402 status code
- Response indicates insufficient compute power or balance: The message contains "insufficient compute power balance/insufficient billing/insufficient balance/quota exceeded/insufficient balance/package expired/recharge required/please recharge", or content with similar meaning.
Core Concepts
- Coverage: All report types for SP / SB / SD (based on the
references/report-types/existing under.md; ST / DSP not yet covered) - One-stop: The script internally automatically completes report creation → waiting for generation (about 2–10 minutes) → download → decompress; the caller only needs to wait for the final result
- Single script:
get_report.py(covers all adProduct for SP / SB) - Metadata vs. runtime parameters:
- For each report type, theavailable fields(timeUnit / groupBy / filters / all column names) are centralized in
references/report-types/<adProduct-dir>/<reportTypeId>.md - Script runtime parameters(waiting interval, access link validity period, etc.) are described in this document and
references/api.md
- For each report type, theavailable fields(timeUnit / groupBy / filters / all column names) are centralized in
Available scripts
| Script | Responsibility |
|---|---|
get_report.py ⭐ |
One-stop execution.Required adProduct / groupBy / columns, extracted by the agent from report-types/ and passed in |
check_auth_dependency.py |
Detect whether linkfox-amazon-ads-auth is installed |
For complete script parameters and response structure, see references/api.md。
Agent invocation flow
When an Agent encounters a "pull Amazon advertising report" type of request,mustfollow the order below:
- Determine reportTypeId: Select according to user intent (e.g., "last week's spend" →
spCampaigns; "which product sells well" →spAdvertisedProduct/sbPurchasedProduct; "what words do users search to find me" →spSearchTerm) - Check reference: Open
references/report-types/<adProduct-dir>/<reportTypeId>.md- frontmatter provides:
adProduct/groupBy(recommended by the Configuration table) /timeUnit(enumerable) /format/dateRange/filters - Base metrics table provides: all column names allowed for this report type
- frontmatter provides:
- Ask the user about customizable conditions(skip when the user answers "default/whatever", and proceed to the default selection in step 4):
timeUnit: DAILY (split by day) or SUMMARY (aggregated)columnsextension: whether attribution columns are needed (sales7d / purchases7d / acosClicks7d / roasClicks7d), video metrics, newToBrand, etc.filters: whether to filter campaignStatus / keywordType / adStatus, etc.
- Construct columns according to the user's reply or defaults(see the "Default conditions" section below)
- Call script:
adProduct/groupBy/columnsthree required fieldsexplicitlypassed in
Default conditions (used when the user does not specify)
| Condition | Default rule |
|---|---|
timeUnit |
Date span ≤ 7 days → DAILY; > 7 days → SUMMARY |
columns identity dimension |
DAILY must include date;SUMMARY must include startDate + endDate; then append the report's primary key fields (refer to the primary keys corresponding to groupBy in the frontmatter, such as campaignId+campaignName / advertisedAsin+advertisedSku / searchTerm / keyword, etc.) |
columns Base metrics |
impressions / clicks / cost(based on those present in that report's Base metrics) |
columns Attribution metrics |
Append only when the user mentions intents such as "sales/conversion/ROI/ACOS":sales7d / purchases7d / acosClicks7d / roasClicks7d(based on those present in Base metrics) |
filters |
Do not add (return all) |
groupBy |
Take the first value of the frontmatter groupBy array (i.e., the primary dimension officially recommended by Amazon in the Configuration table) |
Request examples
All examples explicitly pass the three required fields (adProduct / groupBy / columns)。
1. SP campaign report (most common)
python scripts/get_report.py '{
"profileId": 1234567890, "region": "NA",
"reportTypeId": "spCampaigns",
"adProduct": "SPONSORED_PRODUCTS",
"groupBy": ["campaign"],
"columns": ["date","campaignId","campaignName","impressions","clicks","cost"],
"startDate": "2026-04-27","endDate": "2026-05-03",
"timeUnit": "DAILY"
}'
2. SP search term report (with attribution)
python scripts/get_report.py '{
"profileId": 1234567890, "region": "NA",
"reportTypeId": "spSearchTerm",
"adProduct": "SPONSORED_PRODUCTS",
"groupBy": ["searchTerm"],
"columns": ["searchTerm","keyword","matchType","impressions","clicks","cost",
"sales7d","sales14d","purchases7d","acosClicks14d","roasClicks14d",
"startDate","endDate"],
"startDate": "2026-04-01","endDate": "2026-04-30",
"timeUnit": "SUMMARY",
"filters": [{"field":"keywordType","values":["BROAD","PHRASE","EXACT"]}]
}'
3. SB ad group report
python scripts/get_report.py '{
"profileId": 1234567890, "region": "NA",
"reportTypeId": "sbAdGroup",
"adProduct": "SPONSORED_BRANDS",
"groupBy": ["adGroup"],
"columns": ["adGroupId","adGroupName","impressions","clicks","cost","purchases","sales","startDate","endDate"],
"startDate": "2026-04-01","endDate": "2026-04-30"
}'
4. SD campaign report
python scripts/get_report.py '{
"profileId": 1234567890, "region": "NA",
"reportTypeId": "sdCampaigns",
"adProduct": "SPONSORED_DISPLAY",
"groupBy": ["campaign"],
"columns": ["date","campaignId","campaignName","impressions","clicks","cost","purchases","sales"],
"startDate": "2026-04-27","endDate": "2026-05-03",
"timeUnit": "DAILY"
}'
5. Poll an existing reportId (recover from a previous timeout / manual recovery)
When the previous run exited because the client polling window was too short, but the report is still running on Amazon's side, just pass in reportId to skip creation and continue polling and downloading. In this mode only profileId / region / reportIdis needed; the other fields do not need to be filled in.
python scripts/get_report.py '{
"profileId": 1234567890, "region": "NA",
"reportId": "7df1ef5d-45ba-40cc-b607-ff2148cf4f5e",
"maxAttempts": 60, "pollInterval": 30
}'
Automatic recovery: If the caller did not pass
reportId, and Amazon triggers deduplication for a request with the same parameters (returns HTTP 425The Request is a duplicate of : <uuid>), the script will automatically parse out the old reportId and switch to polling that old report, with no need to retry.
Response format
Success:
{
"success": true,
"reportId": "4ee811a0-...",
"reportTypeId": "spCampaigns",
"startDate": "2026-04-28", "endDate": "2026-05-04",
"downloadPath": "C:/.../tmp/report_data.json",
"extractedFileHttpUrl": "http://127.0.0.1:51234/download",
"extractedFileHttpServeSeconds": 300
}
Failure:
{"error":"Upstream HTTP 400","httpStatus":400,
"body":"{\"code\":\"400\",\"detail\":\"startDate to endDate range (32 days) must not exceed maximum range (31 days)\"}"}
Invocation principles
- If the user specifies a reportTypeId, pull only that one type; do not substitute on your own
- When a report fails (non-2xx or status=FAILED), truthfully inform the user of the error reason; do not blindly retry
- After success, fully display the report's local file path and access link to the user, and remind them that the access link is time-limited (valid for 5 minutes by default; re-pull after expiration)
- Timeout is not failure: When the script returns
status=STILL_PROCESSING(exit code=2), it means the client has waited the default ~7.5 minutes but the report is still being generated on Amazon's side. At this point you mustexplain the situation to the user and ask whether to continue waiting; never treat it as a failure. Reference reply: "The report is still being generated on Amazon's side (already waited ~7.5 minutes). Do you want to keep waiting? Options: A. Wait ~30 more minutes (maxAttempts=60), B. Wait ~1 more hour (maxAttempts=120), C. Stop for now, and I'll come back later with the reportId." If the user chooses A/B → useresumeHint.paramsto switch to poll-only mode and continue
Common errors
| Status | Meaning | Suggestion |
|---|---|---|
Missing required parameters: adProduct/groupBy/columns |
Caller did not explicitly pass the three required fields | Go back to step 2 of "Agent invocation flow" and read them from references/report-types/<adProduct-dir>/<reportTypeId>.md and fill them in |
HTTP 401 |
accessToken expired | Call ads-auth's refresh_token.py then retry |
HTTP 403 |
Ad account not linked or insufficient permissions | Check the manager account/ad account linkage in the Amazon Ads console |
HTTP 400 "must not exceed maximum range" |
Date range exceeds the limit (mostly 31 days) | Pull in splits and merge locally; for the specific upper limit see the corresponding .md frontmatter dateRange.maxSpanDays |
HTTP 400 contains columns/groupBy validation error |
Column name spelled incorrectly / does not match reportTypeId / exceeds Base metrics | Check against .md file Base metrics table |
status=FAILED contains failureReason |
Upstream generation failed | Mostly date window or permission issues; handle specifically based on failureReason |
status=STILL_PROCESSING (exit 2) |
Client polling window exhausted but report is still being generated | not a failure. stdout already contains reportId and resumeHint.params. Ask the user whether to continue waiting, and use those params (with reportId + a larger maxAttempts) to switch to polling-only mode and resume the run |
HTTP 425 "duplicate of" |
A report with the same parameters is already running | The script automatically parses this and switches to polling that existing reportId; under normal circumstances the caller does not need to intervene |
| exit 42 | Dependency skill not installed | Install first linkfox-amazon-ads-auth |
Dates and data
- Maximum date span: most reports 31 days;
sbPurchasedProductis 731 days;spGrossAndInvalids/sbGrossAndInvalids/sdGrossAndInvalidsis 365 days (subject to frontmatter) - Lookback window: SP defaults to 95 days, SB 60 days, GrossAndInvalids 365 days; refer to frontmatter
dateRange.dataRetentionDaysfor specifics - Data delay is about 12 hours;
endDate >= 今天The script warns on stderr but does not block - Empty data does not equal an error: when the account has no delivery in the period, the report is still generated successfully and the JSON may be
[]or all metrics 0
Not Applicable
- Brand Analytics / Retail Analytics / Attribution reports → not in this skill
- Report deletion / modification / scheduled tasks → not in this skill
- Entity metadata (campaign name, keyword match type, etc.) →
linkfox-amazon-ads-manager - Authorization / token →
linkfox-amazon-ads-auth
Amazon Ads API interface protection and retry guidance
When the same advertising account/profile continuously receives 400, 403, 404, or 429 from the Amazon Ads API, the gateway returns 450, 453, 454, or 459 and briefly cools down. These custom status codes are not native Amazon statuses and do not indicate a ban; the purpose is to avoid continuous anomalies or high-frequency calls increasing the risk to the advertising account.
| Status and message | Scope | Trigger and cooldown | Handling |
|---|---|---|---|
450:400,请求异常,请优化您的参数 |
Advertising account/profile + interface | More than 3 times within 60 seconds: 5 minutes; more than 4 times within 10 minutes: 20 minutes | Stop retrying with the original parameters, and check profileId, region, entity/report ID, dates, and request body |
453:403,店铺未授权,请先授权 |
All interfaces for the advertising account/profile | More than 2 times within 60 seconds: 5 minutes; more than 4 times within 10 minutes: 30 minutes | Stop calls for that advertising account, and check Ads authorization, application permissions, profile ownership, and region |
454:404,资源不存在,请优化您的参数 |
Advertising account/profile + interface | More than 3 times within 60 seconds: 5 minutes; more than 4 times within 10 minutes: 30 minutes | Confirm the resource ID, the owning profile/region, resource status, and interface path |
459:429限流中,请降低频率 |
Advertising account/profile + interface | First time: 15 seconds; more than 2 times within 2 minutes: 30 seconds; more than 4 times within 3 minutes: 2 minutes | Reduce concurrency, pagination, and polling frequency, and back off step by step |
- Immediately stop automatic or concurrent retries; do not bypass the protection by switching scripts or repeatedly creating tasks; prioritize following
retryAfter、blockedUntil, if not present, follow the duration description in the table. - For 450/453/454, you must first correct the parameters, authorization, or resource identifier, and after the cooldown retry cautiously at most once; if triggered again, stop calling. During 453, stop all Ads API for that advertising account/profile.
- Keep existing
reportIdand other task IDs; when the result of a write operation is uncertain, query the status first and do not directly replay. - First explain the advertising account protection to the user, then give the reason, handling, and waiting time. You may reply: "To protect the security of your Amazon advertising account, it has been detected that the Amazon Ads API continuously returned {reason}, and a brief protection period is currently in effect. Please first {handling action}, and try again after an estimated {waiting time}; this does not mean the account is banned, nor is it a plan or credit limit." Do not only say "LinkFox rate limiting" or "server busy".
Compute power consumption rules
No compute power is consumed.
Feedback:
Auto-detect and report feedback via the Feedback API when any of the following apply:
- The functionality or purpose described in this skill does not match actual behavior
- The skill's results do not match the user's intent
- The user expresses dissatisfaction or praise about this skill
- Anything you believe could be improved
Call the feedback API as specified in references/api.md. Do not interrupt the user's flow.
For more high-quality, professional cross-border e-commerce skills, visit LinkFox Skills.