Point-in-time law comes in two forms, and they carry very different guarantees. One is a published edition the government printed on a date, which you can cite. The other is a reconstruction assembled from observed changes, which you can't cite the same way.
Vaquill AI serves both, and labels which one answered. asOf=YYYY-MM-DD on a section body sets asOf.engine to stored_edition where the API holds the publisher's own printed editions, such as the 31 GPO annual editions of the CFR from 1996 to 2026 (the CFR_ANNUAL corpus), and to observed_change for the rest, including the current CFR and state codes. asOf.source then says what came back: published from an edition, or live, reconstructed or unavailable from the change history, with an isBounded flag whose meaning depends on the engine.
Reviewed and corrected on 12 October 2026. This is general information, not legal advice.
The distinction is the whole post. If you treat a reconstruction as a published record, you will ship something that quietly gives wrong answers about dates. On a test call on 12 October 2026, a current CFR section (CFR_T21_P314_S314_50) asked for as of 14 March 2019 came back with engine: "observed_change", source: "live" and isBounded: true. That means "no change was observed after your date", so today's text was returned. The same section in the annual-edition corpus (CFRANN_2017_T21_P314_S314_50) with the same date came back engine: "stored_edition", source: "published", resolvedEditionYear: 2018: GPO's own printing.
TL;DR
- Two engines answer a date, and
asOf.enginesays which.stored_editionmeans a published edition held verbatim: theCFR_ANNUALcorpus holds GPO's CFR editions, 1996 to 2026, 31 editions, 312,132 sections.observed_changemeans rebuilt from the before-side of the first observed change after your date, andasOf.sourcethen readsreconstructed(orlivewhen no later change was captured). - Ask for the right corpus. A current
CFRsection answers from observed changes. Use theCFR_ANNUALrecord for the printed edition. - Read
isBoundedbefore citing a reconstruction. True means no change affecting your date was observed, which isn't the same as none having happened. - Four further capabilities exist: amendment history per section, a
yearFrom/yearTocurrency filter, change events captured per refresh, and per-section diffs on a watched board. yearTois not an as-of filter. It filters on the last amendment year the publisher credits, so a section amended in 2025 disappears fromyearTo=2024even though it existed and was in force in 2024.- Our own census, dated 2026-08-30 and not re-measured in our October 2026 review: across 3,518,180 sections in four state-level corpora, 912,388 (25.9%) carry no amendment year, 548,762 assert a year with no stored publisher note behind it, and 155,589 hold a note that never parsed into a year.
- A missing amendment year has more than one cause. Publishers print different things, and a section can carry no credit line at all. Any vendor quoting one "amendment history coverage" percentage is quoting a number that mixes unrelated things.
- The pattern that works is snapshot and watch: store the text and its hash on the date you relied on it, subscribe to changes on the sections you care about, and go to the Statutes at Large corpus when you need law as enacted.
A dispute turns on the exact words of a state statute as they read on a contract date three years ago. The state publishes only its current code. Which source is the strongest for the old wording?
This post closes out our legal data infrastructure series.
Two of the four capabilities below have posts of their own: How We Know a Law Changed for change events, and Law Change Alerts API for the diffs and their delivery.
What point-in-time law actually means
True point-in-time retrieval is a specific thing. You hand the system a citation and a date, and it returns the exact words that section carried on that date.
To do that, a system has to store every version of every section with an effective-date range on each one. That requires the publisher to have published those versions in the first place. Many state publishers publish a current code and little else, so for those the versions don't exist to be stored.
Where historical versions do exist, they usually exist as a stream of amending acts rather than as reconstructed section texts. Rebuilding a 2019 state section from a 2026 code plus a pile of session laws is a legislative-drafting exercise, not a database query. A vendor that quietly implies otherwise is selling you a derivation and calling it a record.
The federal side is the exception, because GPO prints annual CFR editions. The US Code uses the stored-edition engine too, but with few editions held: on 12 October 2026 a request for 42 U.S.C. 1983 as of 14 March 2019 came back available: false, engine: "stored_edition", with the note that the earliest edition held was dated 2025-01-06. That is why the CFR annual editions give real point-in-time answers and state statutes can't: a printed record exists for one and not the other.
A short history: two texts for one law
Federal law has always come in two versions of itself, and that is the root of the point-in-time problem. When Congress passes a law, it is published as a session law in the Statutes at Large, in the order of enactment. That is the law as passed. Nobody can research by subject in it, so people compile the laws into codes. The first compilation of the United States Code appeared in 1926, as the Supreme Court recounts in its 1993 opinion in United States National Bank of Oregon v. Independent Insurance Agents of America. (That case, in which a section vanished from the Code and turned out never to have been repealed, is told in How We Know a Law Changed.)
The Office of the Law Revision Counsel, which prepares the Code for the House, explains why the two texts don't have equal standing. Some titles are "positive law," meaning Congress enacted the title itself. Title 10, Armed Forces, is the example it gives. The rest are editorial compilations. Title 42, Public Health and Welfare, is a bundle of separate laws such as the Public Health Service Act and the Social Security Act that editors have gathered and organized. The distinction is written into 1 U.S.C. 204: non-positive-law titles "establish prima facie" what the law is, while positive-law text "shall be legal evidence" of it. The OLRC puts the practical result plainly on its positive law codification page: "Statutory text appearing in a non-positive law title may be rebutted by showing that the wording in the underlying statute is different."
In plain English, "prima facie" means "accepted unless someone shows otherwise." For Title 42, the Code is a careful summary that the session law can overrule. For Title 10, the Code is the statute. A commenter on the Hacker News thread for a project that put the whole U.S. Code into Git objected that the project's readme had these two categories the wrong way round: "The other titles merely 'establish prima facie' what the law is, subordinate to a closer examination of the bills actually passed, which control." (cvoss, Hacker News, April 2026). The statute's own text, on govinfo, agrees with that reading.
Now add dates. The OLRC says a complete new printed edition of the Code arrives every six years, with five annual cumulative supplements in between, and that "there is necessarily a lag between the date a law is enacted and the date on which it appears in the printed version of the Code." Those printed editions are the closest thing the U.S. has to an official point-in-time record. The OLRC also keeps prior-year versions of the online Code back to 1994, built from the printed edition and its supplements, as its About page explains. Note what that means. The government can tell you what the Code said at a past print date. It doesn't promise to tell you what the underlying law said on an arbitrary day in between.
The UK shows what the harder version looks like. The legislation.gov.uk site lists a provision's versions by date, and each page also carries a notice that "Revised legislation carried on this site may not be fully up to date," followed by a list of changes and effects "yet to be applied" by its editorial team. Even with a dedicated team and dated versions, applying every amendment takes time. A state publisher that posts only a single current code has less to work with, which is why the two forms of point-in-time law below have such different guarantees.
The four things that do exist
1. Amendment history per section
Every section carries a block of history fields, each defined in the amendment history reference. The important one isn't a year we computed. For US Code sections it is sourceCredit, the Office of the Law Revision Counsel's credit line listing the acts that enacted and amended the section. Other corpora carry the publisher's own history text (history, and amendmentNote where a publisher stores it separately).
Search takes a fields parameter that prunes each result to what you asked for. actId and citation always come back, because a row without them can't be used or attributed. Passing a citation as the query returns that section first.
curl -s https://api.vaquill.ai/api/v1/us/statutes/search \
-H "Authorization: Bearer $VAQUILL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"42 U.S.C. 1983","corpusType":"USC","limit":1,
"fields":["sourceCredit","amendmentYears","amendmentsCount","lastAmendedYear","originalEnactmentDate","currentThrough","goodLawStatus"]}'
The curl call needs an API key, so it was not run directly. The same request through the MCP search tool on 12 October 2026 returned, for USC_T42_C21_S1983: sourceCredit listing R.S. § 1979, Pub. L. 96-170 (Dec. 29, 1979, 93 Stat. 1284) and Pub. L. 104-317 (Oct. 19, 1996, 110 Stat. 3853), amendmentYears [1996, 1979], amendmentsCount 2, lastAmendedYear 1996, currentThrough "2026-09-18" and goodLawStatus "good_law". Note that the credit line starts at a Revised Statutes section, so the first dated act in it is 1979, and the longer history sits in the publisher's text.
An unknown field name is rejected with 422, so a typo doesn't silently drop a field you needed. That matters more than it sounds: a silently missing history field looks exactly like a section with no history.
Each field answers a narrow question, and the second column matters less than the third.
| Field | Answers | Does not answer |
|---|---|---|
sourceCredit | For US Code sections, the credit line of acts that enacted and amended the section | Which subsection each act touched; it is null on a section that prints no credit |
amendmentNote | The publisher's amendment credit line, where a corpus stores it apart from history | Anything, on corpora where it is not populated |
amendmentYears | Distinct years parsed from the publisher's history note, newest first | Which subsection each year touched |
amendmentsCount | How many amendments the publisher recorded; not the length of amendmentYears | Whether an amendment was substantive or a renumbering |
lastAmendedYear | The most recent amendment year, when known | Whether the amendment is in force yet |
lastAmendedDate | A full date, where the publisher gives one | A date, for publishers that give only a year |
originalEnactmentDate | When the section was first enacted, where populated | What the section said then |
priorEffectiveDates | Earlier effective dates recorded for the section | The text of any of those earlier versions |
currentThrough | The date the publisher states the text is current through | What changed between that date and today |
goodLawStatus | A derived currency verdict: good_law, not_good_law, not_operative or unknown | Whether a court has limited it |
The last rows have their own status and currency reference. Read the right column top to bottom. Amendment history tells you when a section moved. It never tells you what it moved from.
2. The yearFrom and yearTo currency filter
POST /us/statutes/search takes yearFrom and yearTo. They are useful and they are the single most misread parameter on the surface.
curl -s https://api.vaquill.ai/api/v1/us/statutes/search \
-H "Authorization: Bearer $VAQUILL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"data breach notification deadline",
"corpusType":"STATE","state":"tx",
"yearFrom":2023,"limit":20}'
That call means: give me sections whose last credited amendment year is 2023 or later. It is a good way to find recently touched law.
It doesn't mean: give me the law as it stood in 2023. Two sharp edges follow from that, and both bite in production.
Edge one: yearTo excludes sections that existed. A section last amended in 2025 drops out of yearTo=2024, even though the section was on the books and in force throughout 2024. The filter is about when the text last changed, not about when the text was live. If you use yearTo as an as-of filter, you get a set that systematically omits the sections most likely to have changed under you.
Edge two: sections with no credit vanish once either bound is set. The filter can only compare a year it has. About a fifth of sections across the corpus carry no amendment credit at all, according to the search reference. Set yearFrom or yearTo and every one of those sections leaves the result set with no error and no warning.
3. Change events captured per refresh
The refresh re-pulls a source on its cadence, reconciles what came back against what is stored, and turns a difference in a section's stored text into a change event logged against that run.
GET /boards costs nothing and lists every watchable source, each row naming when it was last retrieved (lastRetrievedAt) and its cadence. That is how you check a real cadence rather than a marketing number, and the intervals are set out per source in what refresh cadence actually means.
curl -s "https://api.vaquill.ai/api/v1/boards?limit=250" \
-H "Authorization: Bearer $VAQUILL_API_KEY"
Two honest limits. A change event is a detected difference between two retrievals, which isn't the same thing as an official effective-date announcement, and a publisher can restate a page without changing the law. Treat an event as a signal to go look, never as a legal conclusion. How We Know a Law Changed catalogues the four false positive families.
The second limit is more structural: change events are forward-only. They start when the source starts being refreshed. There is no back catalog of events for a section you began watching yesterday.
4. Per-section diffs on a watched board
When a watch fires, you can fetch the diff for that change and see the per-section text difference between the two retrievals.
This is the closest thing to a version comparison in the whole surface, and it is worth being precise about its scope. It compares retrieval N against retrieval N+1 for one section on one board. It can't compare 2021 against 2024, because there was no retrieval pair spanning those dates and the intermediate texts were never stored as versions.
Which of the four answers your question
The mapping below includes the rows where the answer is nothing, because those are the rows people assume are covered.
| Question a user asks | What answers it |
|---|---|
| What does this section say today | Section retrieval |
| When did this section last change | lastAmendedYear, lastAmendedDate |
| How many times has it been amended | amendmentsCount, amendmentYears |
| Which acts amended it, in the publisher's words | sourceCredit, amendmentNote |
| When did this section first enter the code | originalEnactmentDate |
| What is this whole code current through | currentThrough, currencyNote |
| Which sections in Texas changed since 2023 | yearFrom on search |
| Did this section change since I last looked | A watch plus a change event |
| Exactly which words changed in that event | The per-section change diff |
| When was this source last retrieved, and on what cadence | GET /boards, lastRetrievedAt and cadence |
| What did this section say on 14 March 2019 | asOf on the section body: a published edition where one is held (the CFR_ANNUAL corpus), a flagged reconstruction otherwise |
| Show me every version of this section | The change history, one observed change at a time |
| Diff this section between 2020 and 2023 | The per-section change diff for each observed change |
| Which sections were in force on a past date | asOf, read one section at a time |
| Was this amendment substantive or a renumbering | Read sourceCredit, which carries the publisher's own wording |
The original data: our own amendment-history census
On 2026-08-30 we ran a full census rather than a sample. It covered 5,763,696 stored points across four state-level corpora. Points are retrieval passages, and long documents split into several, so the section-level number is what matters: 3,518,180 sections.
Of those sections:
| Finding | Sections | Share |
|---|---|---|
| No amendment year at all | 912,388 | 25.9% |
| A year asserted, with no stored publisher note behind it | 548,762 | 15.6% |
| A note stored, but no year ever parsed out of it | 155,589 | 4.4% |
Those three rows aren't three severities of the same problem. They have three different causes, and telling them apart is the part worth stealing.
Cause one: the note was never captured from the publisher's page. The history line exists in print and an extraction run didn't pick it up, usually because that publisher puts it somewhere structurally different from the section body.
Cause two: the note was captured but never parsed into a year. We hold the publisher's words and could not turn them into a number. Credit lines are inconsistent from one jurisdiction to the next, and a parser written against one state's format returns nothing on another's. The stored note is still correct and still readable by a human. This is the 155,589 row.
Cause three: something on the page that is not the history got read as if it were. This is the dangerous one, because it produces a confident year rather than a blank. A banner, a sidebar, a session identifier, or a notice about a pending change can all look like a date to a parser. A year with no note behind it is where this class hides, which is why we count that row separately instead of folding it into "has a year."
Why a missing year is usually the publisher's property
This next finding changes how you should read every coverage number in this category.
A missing amendment year is often a property of the publisher, not a scraping failure. Publishers print different things under a section: a full date, a year, a session-law volume and chapter, or, for a share of sections, no credit line at all (the search reference says about a fifth). Where there is no note to capture, no parser can produce one.
Delaware shows the pattern. Its code prints a history line that cites session laws by volume and chapter with no calendar year; under 13 Del. C. § 1301, for example, the last entries read "69 Del. Laws, c. 296, § 21; 70 Del. Laws, c. 186, § 1" (Delaware Code, Title 13, Chapter 13, read 12 October 2026). A year for that section has to be derived from a volume-to-year table. A census that counts only years printed beside a note would flag that derivation as unsupported even though the derivation is sound.
One state carries the whole argument. An unsupported year is not the same thing as a wrong year. A census that treats "no publisher note behind this year" as a defect will flag a sound derivation and a bad parse identically, and the two need opposite responses.
The three questions to ask instead of "what is your coverage percentage"
Any vendor, us included, can quote one amendment-history coverage number. That number mixes an extraction gap, a parsing gap, and a publisher that prints little or nothing, and those three have nothing to do with each other. Ask these instead.
- For the jurisdictions I care about, what share of sections carry an amendment year, and what share carry the publisher's own note behind that year? Two numbers, not one. The gap between them is the size of the trust problem.
- When you assert a year with no note, where did the year come from? A volume-to-year table is a defensible derivation. A parse of unlabeled page text isn't. Silence here is the answer.
- Show me one section in this state where you have no year, and tell me whether the publisher prints one. If the publisher prints one and they don't have it, that is a gap. If the publisher prints none, their number is measuring the publisher, and so is everyone else's.
What to build instead
If you need point-in-time behavior, you build it. There are three routes and most compliance teams need the first two together.
Route one: snapshot the text on the date you relied on it
The only record of what a section said on the day you made a decision is the copy you took that day. Take it, hash it, and keep it with the metadata that makes it defensible later.
import datetime
import hashlib
import os
import requests
BASE = "https://api.vaquill.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['VAQUILL_API_KEY']}"}
def snapshot(act_id: str) -> dict:
# Take act_id from a search or resolve response, never build it by hand.
body = requests.get(f"{BASE}/us/statutes/section/{act_id}/body",
headers=HEADERS, timeout=30,
params={"format": "plain"}).json()
meta = requests.get(f"{BASE}/us/statutes/section/{act_id}",
headers=HEADERS, timeout=30).json()["section"]
text = body["plain"]
# Normalize before hashing so whitespace churn is not a false positive.
normalized = " ".join(text.split())
digest = hashlib.sha256(normalized.encode("utf-8")).hexdigest()
return {
"actId": act_id,
"citation": meta["citation"],
"text": text, # keep the raw text, the hash alone is not enough
"sha256": digest,
"retrievedAt": datetime.datetime.now(datetime.timezone.utc).isoformat(),
"publisherUrl": meta.get("externalUrl"),
"currentThrough": meta.get("currentThrough"),
"lastAmendedYear": meta.get("lastAmendedYear"),
"sourceCredit": meta.get("sourceCredit"),
}
This sample needs an API key, so it was not run as written. The field names it reads (plain at the top level of the body response; citation, externalUrl, currentThrough, lastAmendedYear, sourceCredit inside the section object of the metadata response) match the responses the MCP tools returned for USC_T5_C7_S706 and USC_T42_C21_S1983 on 12 October 2026.
Four details in that function do the real work.
- Store the raw text, not only the hash. A hash proves a change happened. It can't reproduce what you read.
- Normalize before hashing. Publishers reflow whitespace constantly. Hash the raw bytes and you will get change alerts that are pure noise, and after the third one nobody reads them.
- Keep
currentThroughnext toretrievedAt. They are different facts.retrievedAtis when you fetched.currentThroughis what the publisher says the code is current through, and it is often much older. Design against the second, monitor the first. - Keep
externalUrl. It points at the publisher's own copy, which is what an auditor or an opposing counsel will actually open.
Route two: watch the sections you care about so you learn when the snapshot goes stale
A snapshot alone rots silently. Pair it with a watch on the board that covers that jurisdiction and corpus, and the two together give you the property you actually wanted from point-in-time: a dated text plus a guarantee you will be told when it stops being current.
The branch at the bottom is where most implementations go wrong. A change event means a retrieval differed, which includes a publisher reformatting a page. Re-hash before you page anyone. And never overwrite the old snapshot, because the chain of dated snapshots is the thing that answers "what did we rely on in March" two years from now.
Webhook delivery for these alerts exists today, along with endpoints to list changes, fetch a diff, list deliveries, and send a test. Boards expose their last clean retrieval and their cadence, so you can compare the timestamp against the cadence yourself. That matters here, because a snapshot paired with a dead watch is worse than no watch at all. The integration shape is in the law change webhooks post.
Route three: go to the enacting text
For federal law there is a genuine historical record, and it is a different corpus. Statutes at Large holds public and private laws as enacted, 1789 to 2026, served as more than 425,000 sections under corpusType=SESSION_LAW. Its board in GET /boards lists a monthly cadence.
An enacted text doesn't move. What Congress passed in 2016 still reads in 2026 exactly as it read in 2016, which is what makes it a real historical record rather than a reconstruction.
These items carry actStatus: "enacted" and goodLawStatus: "unknown" on purpose. That pairing is the corpus telling you the truth: it knows what was enacted and it is making no claim about whether that text survives in the code today. A real actId looks like SAL_PL116-136_DVA_TII_S1102, section 1102 of the CARES Act, the Paycheck Protection Program (returned by a SESSION_LAW search on 12 October 2026 with exactly that actStatus and goodLawStatus). Note that ids are stable and not guessable, so take them from a search or resolve response rather than building them by hand.
Use this route when the question is "what did this act say when it passed." Do not use it when the question is "what is the law today," because an enacted section may have been amended, repealed, or renumbered since.
FAQ
Can I query a US statute as it existed on a past date?
Yes, with a caveat that matters. asOf=YYYY-MM-DD on a section body reconstructs the earlier text from the before-side of the first change observed after your date, and flags isBounded when the answer rests on when capture began rather than on the law. That is a reconstruction, not a published record. Where the API holds printed editions the answer is stronger: the CFR_ANNUAL corpus holds 31 GPO annual editions of the CFR from 1996 to 2026 and serves them as stored_edition, published. For state statutes the answer comes from observed changes, so treat it as a reconstruction and check it against the official source.
What is the difference between point-in-time law and amendment history?
Point-in-time gives you the words a section carried on a date you name. Amendment history gives you the dates on which the words changed, in the publisher's own credit line. History tells you when a section moved and never what it moved from, which is why it is a currency signal rather than an archive.
Does yearTo return the law as it stood in that year?
No, and this is the most common misread on the surface. yearTo filters on the last amendment year the publisher credits, so a section amended in 2025 is excluded by yearTo=2024 even though it was in force all through 2024. Sections carrying no amendment credit also drop out entirely as soon as either bound is set.
Why do so many sections have no amendment year?
Three separate reasons, and they need different fixes. The publisher may print no credit line, or print one without a calendar year, in which case there is little or nothing to capture; the note may exist and not have been captured; or the note may have been captured and never parsed into a year. Our 2026-08-30 census (not re-measured in October 2026) found 912,388 of 3,518,180 state-corpora sections, 25.9 percent, with no year.
Is a missing amendment year a data quality defect?
Not necessarily. It can be a property of the publisher rather than a scraping failure. Delaware's code, for example, cites session laws by volume and chapter without a calendar year, so a year has to be derived from a volume-to-year table. An unsupported year and a wrong year are different problems with opposite responses.
How should I evaluate a vendor's amendment history coverage claim?
Do not accept a single percentage, because that number mixes an extraction gap, a parsing gap, and publishers who print nothing. Ask for two numbers per jurisdiction, the share of sections with a year and the share with the publisher's own note behind that year. Then ask where an unsupported year came from, and ask them to show you one section with no year in a state where the publisher prints one.
What is a change event, exactly?
A change event is a detected difference between two retrievals of the same section, logged against a refresh run and carrying a per-section diff. It isn't an official effective-date announcement, and a publisher can restate a page without changing the law. Treat it as a signal to look rather than a legal conclusion.
How do I build point-in-time behavior on top of an API that does not have it?
Snapshot the section text on the date you rely on it, store the raw text plus a SHA-256 of the whitespace-normalized text plus retrievedAt, currentThrough, and the publisher URL. Then create a watch on that source so you are told when the text changes, re-hash on every event to filter out reformatting, and write a new snapshot without deleting the old one. The result is forward-only, so start before you need it.
Which corpus gives me a real historical record of federal law?
Statutes at Large, served as corpusType=SESSION_LAW, holds public and private laws as enacted, 1789 to 2026. Those texts don't move, which is what makes them historical. They carry goodLawStatus: "unknown" deliberately, because an enacted text says nothing about whether it survives in today's code.
Does an amendment year tell me whether the change is in force?
No. lastAmendedYear is the year the publisher credits for the most recent amendment, which can precede or follow the effective date. Read effectiveDate and priorEffectiveDates where the publisher supplies them, and read currentThrough for what the whole code is current through, because a code compiled through January won't yet reflect a spring session.
New legal AI guides, weekly.
Further Reading
Why Legal Data Cannot Refresh Faster Than Its Publisher
Read postLegal Data Provenance: How to Tell Where a Statute Actually Came From
Read postEvaluating a Legal Data Vendor: The Security and Deployment Questions to Ask
Read postHybrid Search Over 20 Million Legal Passages: Why Semantic Alone Fails on Law
Read postParsing Legal Citations in Code: Bluebook Forms, State Variants, and the Ones You Must Refuse
Read postLegal Citation Resolution: Turning a Cite Into the Right Section, Every Time
Read post
Co-Founder & CTO
Priyansh leads engineering and AI at Vaquill AI: the pipelines that pull statutes, regulations and court rules from every US jurisdiction's official publisher, and the REST API, MCP server and open dataset that serve them.