Skip to main content
Refresh and monitors are not yet available — planned. POST /v1/sessions/{id}/refresh, POST /v1/extractions/{id}/refresh, and the whole /v1/monitors surface are specced but not yet served: these routes answer 501 not_implemented. The re-reading story below (result, events, rows — free, forever within retention) is live today; the refresh and monitor sections are the contract those surfaces ship against. The changelog announces when they go live.
  • Re-reading a finished run is free, forever within retention. GET …/result, …/events, …/rows never 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 diff against the refreshed-from result:
Chains are first-class: refreshing a refresh diffs against the latest delivery.

Monitors — a standing refresh

A monitor is exactly “refresh on a cadence, plus a webhook carrying the diff”:
  • watch names exactly one of session (refresh its known sources) or extraction (refresh the one URL).
  • cadence_s minimum 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_usd before you create it — the cadence times the per-run cap, so standing spend is never a surprise.
The webhook events are 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 from max_age_s serving recent data free. If refresh economics change, that will appear in the changelog, not silently in your ledger.