curl --request GET \
--url https://api.vaquill.ai/api/v1/us/statutes/section/{act_id}/changes \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.vaquill.ai/api/v1/us/statutes/section/{act_id}/changes"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.vaquill.ai/api/v1/us/statutes/section/{act_id}/changes', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.vaquill.ai/api/v1/us/statutes/section/{act_id}/changes"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"actId": "CFR_T21_P314_S314_50",
"section": {
"actId": "CFR_T21_P314_S314_50",
"citation": "21 C.F.R. § 314.50",
"title": "Content and format of an NDA",
"corpusType": "CFR",
"state": "federal"
},
"changes": [
{
"id": 91,
"changeKind": "amended",
"detectedAt": "2026-08-07T04:10:00Z",
"citation": "21 CFR 314.50",
"displayCitation": "21 C.F.R. § 314.50",
"title": "Content and format of an NDA",
"hasDiff": true,
"corpusType": "cfr"
}
],
"total": 1,
"hasMore": false,
"cursor": 91,
"coverage": "Observed changes only: what a refresh of this source detected, from when change capture began for it through today, retained 24 months. This is not the section's legislative history, and an empty list means no captured change rather than never amended.",
"processingTimeMs": 18.4,
"creditsConsumed": 1
}{
"detail": "Insufficient API credits."
}{
"detail": "Insufficient API credits."
}{
"detail": "Insufficient API credits."
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}{
"detail": "Insufficient API credits."
}Get this section's change history
Every change our refreshes have observed to one section: when it was added, each time its text was replaced, and whether it has since been removed.
Cost: 1 credit. Not-found and failed lookups are not charged. An empty history for a section that exists IS the answer and is charged.
A section lookup tells you what the law says today. This tells you whether that is the same thing it said last quarter, which is the question behind every compliance diff, every “has anything moved since we last reviewed this”, and every point-in-time citation. Answering it previously required creating a board watch and waiting, because a watch could only ever show changes that postdated it; this reads the captured history directly.
What this is, and is not. These are OBSERVED changes: a refresh compared
the source against the copy we held and found it different. detectedAt is
when we saw it, an upper bound on when it took effect, never the effective date
itself. For the publisher’s own effective and amendment dates, read
amendmentHistory on GET /us/statutes/section/{act_id}. The two are
complements: the publisher tells you what it says changed, this tells you what
actually moved and when we could have told you.
Coverage is bounded by capture, not by the age of the law. Change capture
began long after the corpus itself did, it is per-source, and events are swept
at 24 months. An empty changes list therefore means no captured change, not
never amended. The coverage field on every response says so; surface it
rather than rendering an empty list as “unchanged”.
A removed section still answers. When the newest change is a removed, the
section is gone from the corpus and section comes back null. That is a
successful, charged response, not a 404 — learning that a provision was
repealed is the point.
Paging. hasMore is true when the page filled to limit. Walk backwards
through history with beforeId (the smallest id you hold) and forward into
new changes with sinceId (cursor from your last page).
Alerting on future changes is a different surface: subscribe to the
corpusType on this response via POST /boards/watches, optionally scoped to
this exact actId, and take before/after diff text from the watch’s own diff
endpoint.
curl --request GET \
--url https://api.vaquill.ai/api/v1/us/statutes/section/{act_id}/changes \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.vaquill.ai/api/v1/us/statutes/section/{act_id}/changes"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.vaquill.ai/api/v1/us/statutes/section/{act_id}/changes', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.vaquill.ai/api/v1/us/statutes/section/{act_id}/changes"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"actId": "CFR_T21_P314_S314_50",
"section": {
"actId": "CFR_T21_P314_S314_50",
"citation": "21 C.F.R. § 314.50",
"title": "Content and format of an NDA",
"corpusType": "CFR",
"state": "federal"
},
"changes": [
{
"id": 91,
"changeKind": "amended",
"detectedAt": "2026-08-07T04:10:00Z",
"citation": "21 CFR 314.50",
"displayCitation": "21 C.F.R. § 314.50",
"title": "Content and format of an NDA",
"hasDiff": true,
"corpusType": "cfr"
}
],
"total": 1,
"hasMore": false,
"cursor": 91,
"coverage": "Observed changes only: what a refresh of this source detected, from when change capture began for it through today, retained 24 months. This is not the section's legislative history, and an empty list means no captured change rather than never amended.",
"processingTimeMs": 18.4,
"creditsConsumed": 1
}{
"detail": "Insufficient API credits."
}{
"detail": "Insufficient API credits."
}{
"detail": "Insufficient API credits."
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}{
"detail": "Insufficient API credits."
}Authorizations
API key issued from the developer dashboard. Pass as Authorization: Bearer vq_key_...
Path Parameters
Section identifier. Encodes the citation's hierarchy: USC_T42_C21_S1983 is Title 42, Chapter 21, Section 1983, the section a lawyer writes as 42 U.S.C. § 1983. Take it from a /us/statutes/search result rather than assembling it: the title and section are derivable from a citation, but the CHAPTER is not, so hand-built ids usually 404.
3 - 200"CFR_T21_P314_S314_50"
Query Parameters
Max changes to return on this page.
1 <= x <= 20050
Return only changes with an id greater than this: the cursor for polling forward into new changes. Ids are a monotonic sequence, so this is exact, immune to clock skew, and cannot drop two changes that share a timestamp. Carry cursor forward.
x >= 0Return only changes with an id less than this: the cursor for walking BACK through history, which is what a newest-first reader needs. Pass the smallest id on your last page.
x >= 0Filter to these kinds. Repeat the parameter to pass several (?changeKind=amended&changeKind=removed). Omit for all three.
added, amended, removed desc (default) is newest first, the natural reading order for a history. Use asc to replay a section's life forward, or when catching up from a cursor.
asc, desc Response
The section's captured change history, newest first.
Response for GET /us/statutes/section/{act_id}/changes.
The section identifier you asked about, echoed back.
"CFR_T21_P314_S314_50"
What this history can and cannot tell you, in one sentence. Change capture began well after the corpus itself did and is swept on a retention window, so this endpoint reports the changes we OBSERVED in that window, never the section's full legislative history. Read it before treating an empty list as 'unchanged'.
"Observed changes only, from when capture began for this source through today, retained 24 months. Not a full legislative history."
The section as it stands today. NULL is meaningful and not an error: it means the section is no longer in the corpus, which is exactly the case when the newest change is a removed. The history below is still the answer.
Show child attributes
Show child attributes
Observed changes, newest first by default. Empty is a real answer, and it means NO CAPTURED CHANGE, not that the section has never been amended. See coverage.
Show child attributes
Show child attributes
Size of changes on this page, not a corpus-wide count: it is capped by limit.
3
True when the page filled to limit, so more may sit behind it. Page with beforeId (walking back) or sinceId (walking forward) rather than by raising limit.
Highest id on this page, or null when the page is empty. Carry it into sinceId to poll for what is new; keep the one you hold when a page comes back empty.
91
Server-side time for this request in milliseconds, excluding network transit. Useful for spotting a slow query; not billed on.
18.4
Credits actually charged for this call. Read it rather than assuming the list price: failed and refunded work bills 0.
1
Was this page helpful?

