- Re-reading a finished run is free, forever within retention.
GET …/result,…/events,…/rowsnever re-run and never re-bill. If your app re-opens yesterday’s answer, nothing is fetched from any merchant. - Refreshing gets fresh data for the same question at marginal cost — the run skips everything it already learned.
- Monitoring is a standing refresh on a cadence, with a webhook that carries the diff.
Refresh a session — same question, fresh data
A session already holds what a cold run spends most of its budget discovering: the parsed intent, the resolved merchants, the located catalog URLs, the per-source receipts. A refresh re-passes known sources only — no parse, no resolve, no locate, no triage:
Cost ≈ the passes alone. Many “refreshes” are actually satisfied by recency — with
max_age_s set, those are free by construction. The refresh is a new run in the same
session: it reserves and settles its own budget, and streams like any other run.
Refresh an extraction — same URL, with a diff
POST /v1/extractions/{id}/refresh creates a new extraction (fresh id,
refresh_of set) against the same url/entity/guidance:
- Prior result younger than
max_age_s? It returns immediately with the recorded rows at $0 —"served_from": "record", stated on the object. - Otherwise the pass re-runs, and the delivery carries a
diffagainst the refreshed-from result:
Monitors — a standing refresh
A monitor is exactly “refresh on a cadence, plus a webhook carrying the diff”:watchnames exactly one ofsession(refresh its known sources) orextraction(refresh the one URL).cadence_sminimum is 3600 — no sub-hourly monitors.- Each firing is a refresh run, billed like one, capped by
max_spend_usd_per_run. - The monitor object states
worst_case_monthly_usdbefore you create it — the cadence times the per-run cap, so standing spend is never a surprise.
monitor.changed, monitor.unchanged (opt-in — default is
change-only), and monitor.failed, carrying the diff, the run’s cost, and the receipt
id — see Webhooks for payloads and signing.
Failure is bounded: after 3 consecutive failed runs the monitor pauses itself and
sends a final monitor.failed with "paused": true. It never burns budget
indefinitely against a broken target.
Manage monitors with GET /v1/monitors, PATCH /v1/monitors/{id} (pause, resume,
retune cadence/cap/webhook), DELETE /v1/monitors/{id} (its runs remain readable),
and GET /v1/monitors/{id}/runs for the full firing history with diffs.
What refresh does not promise
A refresh re-passes a known source; it does not (yet) replay the source’s previously discovered acquisition route. Repeat-source cost is therefore in the same range as the original pass for stale sources — the savings today come from skipping parse/resolve/locate/triage and frommax_age_s serving recent data free. If refresh
economics change, that will appear in the changelog, not silently in
your ledger.