THE RECORD, FOR MACHINES
Every value carries its source. That holds when a program reads it too.
OPEN ENDPOINTS NEED NO ACCOUNT
The specimen endpoints below are open and unauthenticated, so anything — a PIM, a script, an agent doing procurement research — can read a complete worked record without an account and cite where each value came from.
WHAT EVERY FIELD CARRIES
value · source · captured · basis (observed or derived) · band (established, probable, unresolved). Unresolved means no source met the threshold — it is reported, never guessed, and never billed. No language model writes, infers or fills any of it.
OPEN — NO ACCOUNT
GET/apiThis surface, machine-readable. Start here.
GET/api/specimen/{id}A published specimen: input verbatim, every captured stage, status.
GET/api/specimen/{id}/exports/enrichedThe row as it comes back — your columns, then four per stage.
GET/api/specimen/{id}/exports/ledgerOne line per answer: stage, value, source, captured, basis, band.
GET/api/verify/{root}Resolve a capture receipt. It matches or it does not.
POST/api/probeRun every service against a sample, free. No run created.
POST/api/quoteThe authoritative price for a scope. Pricing is never taken from the request.
POST/api/uploads/inspectRead a file: column guesses and the quality report.
POST/api/runs/freeOne part number, every stage a source can carry, no account and no card.
SIGNING IN
POST/api/auth/signup{ email, password, company }. Sets the session cookie.
POST/api/auth/login{ email, password }. One message for a wrong address and a wrong password.
POST/api/auth/logoutClears the cookie. There is nothing else holding the session open.
YOUR OWN RECORDS
POST/api/runsCreate a run. Pass { against: <priorRunId> } to re-verify what changed.
GET/api/runs/listEvery run on this account, newest first.
GET/api/runs/{id}Status and per-stage progress.
GET/api/runs/{id}/rows?filter=ALL · ESTABLISHED · PROBABLE · UNRESOLVED · CHANGED
GET/api/runs/{id}/rows/{sku}/evidenceFull source list per stage for one row.
POST/api/runs/{id}/submissionsSend a source for a row we could not establish.
GET/api/runs/{id}/exports/{format}xlsx · ledger · unresolved. aces returns 501 naming what it lacks.
POST/api/watchesWatch a book: cadence, triggers, webhook. Returns the signing secret once.
GET/api/watches/{id}The watch and every check it has run.
POST/api/watches/{id}/checkRun a check now.
GET/api/watches/run-dueWhat is due. POST the same path to run it — this is the scheduler's endpoint.
A record belongs to the account that ran it. Asking for one you do not own returns 404 — not 403, which would confirm it exists. The one exception is a share link: /share/<token> carries its own authority and needs no account, because the person approving a file usually has none.
A LIVE WORKED EXAMPLE
The published specimens could not be read just now, so the worked example is not listed. That is ours, not a statement that none are published — the endpoints above are unchanged.
Every response carries dataset: "illustrative-seed" in this build. The part numbers, prices, accounts and receipts are placeholders, and anything reading this surface should treat that field as authoritative about what it is looking at.