Effectivity-at-date
Vietnamese legal documents change over time along two independent axes: when
CrawlPipe recorded a change (revision, system time) and when a provision was
actually legally valid (legal_effectivity, valid time). The at= parameter lets
you ask "what did the law say on this specific date" — including dates in the
past or future relative to today, and independent of when CrawlPipe ingested the
change. This is a Pro plan feature.
Document view at a date
GET /v1/legal/documents/{id}?include=units&at=2026-08-01 annotates the document
and each unit with its status on that date:
curl "https://api.crawlpipe.com/v1/legal/documents/vn:tt:2026:18:btc?include=units&at=2026-08-01" \
-H "Authorization: Bearer dp_live_a1b2c3d4e5f6…"import requests
resp = requests.get(
"https://api.crawlpipe.com/v1/legal/documents/vn:tt:2026:18:btc",
params={"include": "units", "at": "2026-08-01"},
headers={"Authorization": "Bearer dp_live_a1b2c3d4e5f6…"},
)
document = resp.json()["data"]["document"]const params = new URLSearchParams({ include: "units", at: "2026-08-01" });
const res = await fetch(
`https://api.crawlpipe.com/v1/legal/documents/vn:tt:2026:18:btc?${params}`,
{ headers: { Authorization: "Bearer dp_live_a1b2c3d4e5f6…" } },
);
const { data } = await res.json();The response adds a top-level status_at and, per unit, a status_at field:
{
"document": {
"units": [
{
"path": "c1.d1",
"content": "Thông tư này quy định…",
"status_at": "effective"
}
],
"status_at": { "date": "2026-08-01", "status": "effective" }
}
}natural_key (e.g. vn:tt:2026:18:btc), the record's UUID, or its normalized
doc_number all work as {id}.
Full timeline
GET /v1/legal/documents/{id}/effectivity (1 unit; the at param on this
endpoint also requires Pro) returns the whole history as a sequence of validity
windows, including future-dated amendments that haven't taken effect yet:
{
"effectivity": [
{ "unit_path": null, "status": "not_yet_effective", "valid_from": "2026-05-12", "valid_to": "2026-06-30", "caused_by": null },
{ "unit_path": null, "status": "effective", "valid_from": "2026-07-01", "valid_to": null, "caused_by": null },
{
"unit_path": "d3.k2",
"status": "amended",
"valid_from": "2026-09-01",
"valid_to": null,
"caused_by": { "record_id": "…", "doc_number": "45/2026/TT-BTC", "relation_type": "sua_doi_bo_sung" }
}
]
}A null unit_path describes the whole document; specific paths describe
amendments scoped to one khoản/điều. caused_by points at the amending
document so you can follow the chain.
Why this matters
A naive integration that always reads "current" text will silently serve
outdated or not-yet-effective language around an amendment's effective date.
Use at= to pin the exact date relevant to your use case — e.g. the invoice
date in an accounting sync, or "today" evaluated in Vietnam time — instead of
whatever happens to be current when you call the API.
Plan gating
at= on both endpoints returns 403 feature_not_in_plan
(details.required_plan: "pro") on Free and Builder. Without at=, both
endpoints work on every plan and simply return current-state data.