From israel-shopping
Fallback for `fetch-listing` when the no-auth scraper is broken. Calls the official AliExpress Affiliate API (HMAC-SHA256 signed against `api-sg.aliexpress.com/sync`) — counterintuitively returns LESS buyer-relevant data than the scraper (no shipping fees, no reviews, no specs, no lead time) because the API is designed for affiliate-marketing publishers, not buyer-side analysis. Use only when the scraper fails (DOM rotation, anti-bot, rate-limit) or for a quick affiliate-catalogue search without spinning up Puppeteer. Two modes — `detail <productId>` and `search <query>`. Output normalised to drop affiliate-specific fields (commission rates, tracked promotion links). Trigger phrases — "scraper is broken fall back to the api", "use the affiliate api", "scrape failed try the api".
How this skill is triggered — by the user, by Claude, or both
Slash command
/israel-shopping:fetch-listing-apiThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Use as a fallback to `fetch-listing`, not a replacement.** Counterintuitive but accurate: the no-auth scraper returns more buyer-relevant data than the official API. Reach for this skill only when the scraper breaks.
Use as a fallback to fetch-listing, not a replacement. Counterintuitive but accurate: the no-auth scraper returns more buyer-relevant data than the official API. Reach for this skill only when the scraper breaks.
Signing flow validated against a live approved Affiliate app. search and detail both round-trip successfully. The script ports the exact algorithm from the official Python SDK (iop-sdk-python-20220609).
The AliExpress Affiliate API is built for affiliate-marketing publishers — its job is to drive conversions and track commission, not to support buyer-side analysis. Several fields a buyer cares about are simply not in the response:
| Field | fetch-listing (scraper) | fetch-listing-api (this skill) |
|---|---|---|
| Title, price, image | ✅ | ✅ |
| Shipping fee (to IL) | ✅ | ❌ |
| Shipping lead time | ✅ | ❌ |
| Reviews / review snippets | ✅ | ❌ |
| Specs / variants | ✅ | ❌ |
| Top-rated store flag | ✅ | ❌ (only shop_id) |
| Affiliate-catalogue only | ❌ | ✅ (limitation) |
The API also only returns products from sellers who opted in to the affiliate program — some publicly visible listings will return current_record_count: 0.
fetch-listing is failing (DOM rotation, anti-bot challenge, persistent rate-limit)For everything else, prefer fetch-listing.
| Method | Purpose |
|---|---|
aliexpress.affiliate.productdetail.get | Detail for one or more product IDs |
aliexpress.affiliate.product.query | Search the affiliate catalogue |
Gateway: https://api-sg.aliexpress.com/sync
Per the canonical plugin-data-storage convention, credentials live at:
${CLAUDE_USER_DATA:-${XDG_DATA_HOME:-$HOME/.local/share}/claude-plugins}/israel-shopping/config.json
with 0600 perms. Schema:
{
"aliexpress_affiliate": {
"app_key": "...",
"app_secret": "...",
"gateway": "https://api-sg.aliexpress.com/sync",
"sdk_version": "iop-sdk-python-20220609"
}
}
The plugin repo never contains credentials. The skill resolves the path at runtime and refuses to operate if the file is missing or malformed.
chmod 600.The Affiliate detail/query endpoints in this skill do not require an OAuth access_token — only the app-level signature.
node scripts/ali-api.mjs detail <productId>[,<productId>...]
node scripts/ali-api.mjs search <query> [page_size]
USD_ILS=<rate> env var overrides the live FX lookup if needed.
1005009077622412 — Iron Wood Bedside Table Storage Rack ...
url: https://www.aliexpress.com/item/1005009077622412.html
price: $12.18 (was $16.46, 26% off)
rating: 4.5
shop: Jiexin Technology Store (https://www.aliexpress.com/store/1104400512)
fx: 1 USD = ₪2.9798 (frankfurter@2026-04-24)
item in ILS: ₪36.29 incl. VAT: ₪36.29 band: under-$75 (no VAT)
(note: shipping fee is not exposed by the affiliate API; landed cost = item only)
query: "wooden bedside organizer glasses phone" results: 5/6
<productId> — <title>
$<sale> (was $<original>) <rating>
<clean product url>
...
Mirrors iop.base.sign(secret, api, parameters) from the Python SDK:
key1value1key2value2... with no separator./, prepend the method name to the concat string. (Affiliate methods like aliexpress.affiliate.productdetail.get do not contain /, so no prefix.)HMAC-SHA256(secret, concat).hexdigest().upper() → sign parameter.System parameters always included before signing:
app_keysign_method = sha256timestamp = str(int(time.time())) + '000' (Unix seconds × 1000, as a string)partner_id = SDK version identifier (iop-sdk-python-20220609)method = the API method namesimplify = falseformat = jsonThe raw API returns affiliate-specific fields not relevant to purchasing decisions. The script normalises and drops:
commission_rate, hot_product_commission_ratepromotion_link (tracked affiliate URL — replaced with the clean product URL)sku_idapp_sale_price, app_sale_price_currency, target_app_sale_price*sale_price, sale_price_currency (CNY-denominated, redundant with USD-denominated target_*)lastest_volume, tax_ratesecond_level_category_id, first_level_category_idproduct_small_image_urls (kept only product_main_image_url)The full raw response is still available if needed — the normalisation happens only in the printed summary.
fetch-listing for that.access_token.config.json resolved from canonical path; app_key + app_secret non-empty.search with a generic query returns ≥1 result and HTTP 200.detail for a known affiliate-enabled product ID returns current_record_count ≥ 1.fx-cache.json in the plugin data dir.Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub danielrosehill/claude-code-plugins --plugin israel-shopping