Validate product interest rate data against official bank websites. Use when: checking if product data is up to date, auditing rates, refreshing stale data, verifying interest rates, updating bank products.
Fetch official bank product pages, compare interest rates and conditions with the hardcoded data in src/products/, and update any stale entries.
All products live in src/products/*.ts and are registered in src/products/index.ts. Each product has a url field linking to the official bank product page. The metadata.notes field often contains the effective date of the current rates (e.g. "อัตราดอกเบี้ยมีผล ณ 27 ก.พ. 2569").
Each bank has a dedicated reference file with fetch URLs, extraction instructions, and fallback methods:
| Bank | Reference File |
|---|---|
| KKP (incl. Dime, Fin) | references/kkp.md |
| SCB | references/scb.md |
| KBank | references/kbank.md |
| UOB | references/uob.md |
| CIMB Thai | references/cimb.md |
| Thai Credit Bank | references/tcb.md |
| TMBThanachart Bank | references/ttb.md |
When validating a specific bank, read the corresponding reference file for detailed per-product fetch instructions.
Run the list-products script to output a JSON summary of all products with their current rates and source URLs:
bun .agents/skills/validate-products/scripts/list-products.ts
This prints each product's id, name, headlineRate, tiers, url, and metadata.notes.
Read the bank-specific reference file (see table above) for detailed per-product instructions on which URLs to fetch, how to extract rate data from each page, and what fallback methods to use when the primary fetch fails.
Summary of fetch strategy per bank:
fetch_webpage on each product's url field. See references/kkp.md.fetch_webpage returns empty, fall back to browser rendering. See references/scb.md.fetch_webpage returns empty. See references/kbank.md.If a product page is unreachable, the bank reference files include 3-4 fallback methods per bank (rate PDFs, interest rate overview pages, Google search, BOT aggregate data).
From each fetched page, identify:
Compare each extracted value against the hardcoded product data. Look for:
Present a summary table:
| Product ID | Field | Current Value | Bank Value | Status |
|------------|-------|---------------|------------|--------|
| kkp-savvy | headlineRate | 1.55 | 1.65 | CHANGED |
| scb-savings| tiers[0].rate| 0.25 | 0.25 | OK |
Mark each product as:
For each product marked CHANGED:
src/products/headlineRate — The primary advertised ratetiers — Array of { min, max, rate } objectsminDeposit / maxDeposit — If changedconditions — Updated Thai-language conditionsmetadata.notes — Update the effective dateupdatedAt — Set to today's date in YYYY-MM-DD format (must be updated on every data refresh)headlineRate matches the highest tier rate (for savings products) or the primary rate (for fixed deposits)min equals the previous tier's maxAfter making changes, run:
bun run check
This runs Biome lint/format checks to ensure the updated files are correct.
headlineRate must equal the highest rate value in tiers (for savings) or the primary rate (for fixed deposits)min ascendingtiers[i].max === tiers[i+1].minmax should be Number.POSITIVE_INFINITYurl must be a valid, reachable URLdescription, conditions, metadata.*) should use proper Thai textIf the user specifies a bank name or product ID:
Examples:
bank containing "KKP"id: "scb-savings"type: "fixed-deposit"