faq LIVE
short answers from the real code — every one re-derived from the deployed functions before a word was written.
how do i get an api key?
POST /api/keys — self-service, no signup flow behind it today. It returns a raw key; only the hashed record is stored server-side. /api/keys only ever issues the free tier (functions/lib/api-keys.js: /api/keys only ever issues `free`).
Send the key on every call as the x-api-key header (line 80 of api-keys.js) or as ?key= (line 82). Check your own usage anytime at GET /api/keys/usage, which reports quota: { used, limit, remaining, resets_at } and rate: { per_minute }.
Tier facts, straight from the TIERS table: free = 25 intel calls/day, 10 req/min; anon (no key) = 5/day, 2/min per IP. pro (1000/day, 60/min) is reserved: true — no issuance path exists yet, so it ships with the payments track. Full detail: api keys.
what do "retrieved_at" and "data_as_of" mean?
Every record carries its own freshness stamp. retrieved_at is set by the pipeline: the moment the data was pulled from its source. data_as_of is declared by the adapter itself: how fresh the underlying source record is — and it is honestly null when the adapter can't know.
That split is deliberate: retrieved_at tells you when we fetched; data_as_of tells you when the record was true at the source. A null data_as_of is not a bug — it is the page refusing to invent a date. Full detail: data freshness.
what does a "degraded" signal status mean?
It means the signal works but its honesty conditions changed — a source went stale, a feed partial, a rate limit started throttling. The statuses are generated from the build's own docs/ADAPTER-QUEUE.md: live, degraded (with the exact reason), or pending (not built). Degraded is a staleness signal: treat those records as older than their retrieved_at suggests and re-check the freshness page before acting on them.
how do recipe pricing and credits work?
Recipes are deterministic, billable plans. calls = parcels × signals, computed by compileRecipe in functions/lib/v1-recipes.js before any data is touched. Save and estimate are unbilled; only runs bill, and only for completed evaluations — a failed evaluation is itemized with billed: false and consumes nothing.
The estimate binds the charge: for the same recipe version + parcel set, calls_estimated must equal calls_consumed. If they ever differ, the difference is credited — the billing block carries credit_calls = max(0, calls_estimated − calls_completed) and credit_usd at the modeled price. The estimate response tells you the price basis: price_per_call_usd = 0.003, explicitly modeled — no real charges exist today.
Cost figures, re-derived: the v1 supply-layer free tier is FREE_TIER_MONTHLY_CALLS = 1000 calls/month (hard cap, $0); runs above 1,000 calls require an estimate_id (no blind execution); the large-run gate answers 400 bad_params without it. Full detail: v1 recipes and usage & billing.
is this on-market or off-market data?
Off-market only — never listing data. The signals are built from public records (assessor data, county parcel rolls, public filings) to surface parcels and motivated sellers before a listing exists. The docs hub's honest-status promise applies: if a signal has no free source, the docs say so instead of fabricating results. Results are any parcel the public data supports — not on-market inventory.
what happens when a signal isn't built yet?
The api tells you honestly instead of guessing. Three cases, straight from functions/lib/v1-recipes.js contract §1.4:
- In the 228-signal catalog but no working v1 adapter →
404 signal_not_built('Signal X is in the 228-signal catalog but has no working v1 adapter yet.'). - Not in the catalog at all →
400 unknown_signal. - The 228 count itself is a planning count, never a working-API count — the registry's own status note says so.
Every signal's live/degraded/pending status is on the api reference, regenerated from the build's own records.
where do mcp and agent tools fit?
MCP is the agent path into the same engine. JSON-RPC 2.0 at POST /api/mcp: one tool per registered signal adapter — 271 today — each named by kebab-case slug (e.g. well-depth-drill-cost). Three methods: server/discover, tools/list, tools/call.
Same gates as REST: tools/call counts as one intel call against the same daily quota and same x-api-key auth; server/discover and tools/list are free. Protocol revision 2026-07-28, stateless — no initialize handshake. Full detail: mcp.
do i get charged for anything today?
No. There are no real charges anywhere in the build — every dollar figure in the docs ($0.003/call, the $29/$99/$349 plans in the model) is pricing math, not a price anyone has been charged. What is enforced: the quota gates. Anonymous = 5 intel calls/day per IP; a free key = 25/day; v1 free tier = 1,000 calls/month hard cap. When you exceed a cap you get an honest daily_quota_exceeded (429) with resets_at, never a bill.
rate limits, in short
Two layers (functions/lib/rate-limit.js and functions/lib/api-keys.js): a 100 req/min sliding-window edge limit per client IP, plus per-endpoint token buckets and per-tier per_min caps (anon 2, free 10, pro 60). Denied requests don't consume quota. The Retry-After header and the exact 429 shapes are on the rate limits page.
planned but not shipped DRAFT
- key rotation + revocation DRAFT — no
POST /api/keys/rotate, noDELETE /api/keysexist today. If a key is compromised, mint a new one atPOST /api/keysand stop using the old one. - webhooks DRAFT — parcel-watch push events are a planned design with
SPIKE_THRESHOLD = 20re-derived from the drafts, not live endpoints. - typed javascript + python sdk clients DRAFT — no published packages, no
@shinnslistnpm scope, nollms.txtin the repo. Today the client surface is MCP tools + the chat page's snippet generators.
next: docs hub · getting started · api reference · still stuck? the chat answers from the same live data.