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".
npx claudepluginhub danielrosehill/claude-code-plugins --plugin israel-shoppingThis skill uses the workspace's default tool permissions.
**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.
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
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.