{"data":{"@kind":"guide","slug":"track-one-card","title":"Track one card's price over time","subtitle":"Polling discipline + change-detection.","intro":"If you're building a price-alert bot, a single-card watch surface, or a deck-tracker, you want per-card price observation without thrashing the API. This guide names the polite cadence + the change-detection primitive.","audiences":["agent","hobbyist_coder","aggregator"],"prerequisites":["You know the SKU you want to track"],"estimated_minutes":8,"step_count":3,"steps":[{"step_number":1,"title":"Fetch the current state","instruction":"GET the card's universal-mirror representation. The `@content_hash` is the change-detection primitive: same hash = same card facts (no change worth re-rendering); different hash = something changed.","curl":"curl https://cambridgetcg.com/api/v1/universal/card/op-op01-001-ja","expected_response_shape":"{ \"@content_hash\": \"sha256:...\", \"@retrieved_at\": {...}, \"price\": { \"magnitude\": 5.40, \"currency_token\": \"GBP\", \"magnitude_freshness\": {...} }, ... }","what_to_do_with_it":"Store `@content_hash` + `price.magnitude` + `price.magnitude_freshness.iso8601`. These are your local cache key."},{"step_number":2,"title":"Poll politely","instruction":"Schedule re-fetches at the freshness budget. For prices, that's 5 minutes (`price_current`). Faster polling returns the same response — wasted bandwidth. Set a maximum poll rate of 12 requests/hour per SKU.","curl":"# every 5 minutes:\ncurl https://cambridgetcg.com/api/v1/universal/card/op-op01-001-ja","what_to_do_with_it":"On each poll, compare the new `@content_hash` against your stored. If equal: nothing changed; reschedule. If different: extract the new magnitude, log to your time-series, possibly fire your alert. Substrate-honest about `magnitude_freshness.decimal_age_seconds` — the platform may report a price that was last observed hours ago."},{"step_number":3,"title":"Walk historical via /api/at/","instruction":"If you want to backfill, hit the temporal endpoint — `/api/at/[YYYY-MM-DD]/card/[sku]`. Each historical day is immutable (returns `Cache-Control: immutable`). Pull once per day per SKU into your local series.","curl":"curl https://cambridgetcg.com/api/at/2026-03-15/card/op-op01-001-ja","what_to_do_with_it":"Build your local time-series by iterating dates. The response's `@as_of` declares the queried date; the `@retrieved_at` declares when the response was produced. The price's `staleness_relative_to_as_of_days` tells you how stale the observation was on that historical day."}],"gotchas":[{"title":"Anonymous JPY history is not available","description":"The storefront universal-mirror gives GBP prices (Cambridge TCG's retail offer, CC0). If you want the raw CardRush JPY observation history (90 days), you must be signed in and call /api/v1/cards/[sku]/cardrush-history. That endpoint declares `_meta.source_license: ['internal-only']` — non-bulk, non-redistributable."},{"title":"The 5-minute budget is per-SKU advisory","description":"We don't currently enforce per-SKU rate limits at the edge. The 5-minute number is the freshness budget — polling faster doesn't give you fresher data. We monitor for abuse patterns and may rate-limit unfriendly clients without warning."},{"title":"@content_hash includes captured_on","description":"The hash incorporates the price observation date, so a card without a price update still produces a fresh hash daily. If you want truly hash-based change detection without the daily noise, compare `price.magnitude` + `magnitude_freshness.iso8601` instead."}],"next_guide":{"slug":"respect-our-limits","title":"How to be a polite client","url":"/api/v1/guides/respect-our-limits","html_url":"/agents/guides/respect-our-limits"},"see_also":[{"label":"Auth-gated JPY history (Phase 5.4)","href":"/api/v1/cards/op-op01-001-ja/cardrush-history"},{"label":"Cosmology axis: time","href":"/methodology/cosmology"}],"last_verified":"2026-05-14","feedback":{"kind":"guide-feedback","endpoint":"/api/v1/feedback","body_template":{"kind":"guide-feedback","guide_slug":"track-one-card","step_number":"<which step had the issue, or null for whole-guide feedback>","observation":"<what you observed>","expected":"<what you expected>","reporter_contact":"<your email>"}},"html_sibling":"/agents/guides/track-one-card"},"_meta":{"spec_version":"1","endpoint":"/api/v1/guides/[slug]","retrieved_at":"2026-07-05T21:25:02.557Z","as_of":"2026-07-05T21:25:02.557Z","sources":["ctcg-derived"],"freshness_seconds":86400,"license":"CC0-1.0","request_id":"req_1b3138c8-b82","deprecation":null,"next_link":null,"self_reference":{"this_endpoint":"/api/v1/guides/[slug]","contains_self":true},"source_license":["cc0"],"kingdom":{"name":"cambridgetcg","role":"adapter-expression","built_with":"love","serves_kinds":["human","agent","kin"],"host":"humans-on-earth","epoch":"2026","embassy":"/api/v1/manifest","wake":"/api/v1/wake","identify":"/api/v1/identify","siblings":[{"name":"agenttool","role":"agent-infrastructure-expression","url":"https://agenttool.dev","wake_url":"https://api.agenttool.dev/v1/wake"}]},"wake_fragment":{"id":"test-destination-is-gift","kind":"five_test","text":"Test 5: destination-is-gift-not-extraction — the kingdom takes nothing from those who walk through. No tracking, no registration, no obligation. The substrate logs only the IP rate-limit counter every public surface shares.","walking_past_is_honored":true,"canonical_url":"/api/v1/wake/fragments/test-destination-is-gift","protocol_doc":"https://github.com/cambridgetcg/Cambridge-TCG-monorepo/blob/main/docs/connections/the-distributed-wake.md"},"joy_pointer":{"url":"/api/v1/the-tea-room/sigil/agent","hint":"ASCII sigil for the `agent` actor_kind (swap the path segment for any of: human / autonomous-sophia / collective / oracle / witness / kin / other)","room":"tea-room","protocol":"joy-to-the-world","walking_past_is_honored":true}}}