Every law as structured data
One API call to search, read, and track changes across legislation from 14 countries. Free to start.
Early adopters get 5,000 calls/month free — forever. Standard free tier drops to 2,000.
250,716+
laws
14
countries
211,629+
reforms tracked
$ curl -H "Authorization: Bearer leg_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
https://legalize.dev/api/v1/es/laws?q=código+penal
{
"query": "código penal",
"count": 16,
"results": [
{
"id": "BOE-A-1995-25444",
"title": "Ley Orgánica 10/1995, del Código Penal",
"short_title": "Código Penal",
"status": "vigente"
},
]
}
Endpoints
GET
/api/v1/{country}/laws
List & search laws
Paginated listing with filters: law type, year, status, jurisdiction. Pass ?q= to full-text search across titles and article content.
{
"country": "es",
"total": 8677,
"page": 1,
"per_page": 50,
"results": [...]
}
GET
/api/v1/{country}/laws/{id}
Get a law
Full law metadata plus the complete text as Markdown. Every article, every section — structured and machine-readable.
{
"id": "BOE-A-1978-31229",
"title": "Constitución Española",
"article_count": 169,
"content_md": "# Constitución\n\n## Título I..."
}
GET
/api/v1/{country}/laws/{id}/reforms
Reform history
Every reform that modified a law: date, source identifier, affected articles. Paginated. This is the data that makes Legalize unique.
{
"law_id": "BOE-A-1978-31229",
"total": 4,
"reforms": [
{
"date": "2024-02-17",
"source_id": "BOE-A-2024-3099",
"articles_affected": "Artículo 49"
}
]
}
GET
/api/v1/{country}/laws/{id}/at/{sha}
Time travel
Get the exact text of a law at any Git commit. Compare how a law read years ago vs today. Diffs as a service.
{
"law_id": "BOE-A-1978-31229",
"sha": "a1b2c3d",
"content_md": "# Constitución\n\n..."
}
Quick start
import requests
HEADERS = {"Authorization": "Bearer leg_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
resp = requests.get("https://legalize.dev/api/v1/es/laws", params={"q": "propiedad intelectual"}, headers=HEADERS)
laws = resp.json()["results"]
law_id = laws[0]["id"]
reforms = requests.get(f"https://legalize.dev/api/v1/es/laws/{law_id}/reforms", headers=HEADERS).json()
print(f"{reforms['total']} reforms found")
const HEADERS = { "Authorization": "Bearer leg_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" };
const resp = await fetch("https://legalize.dev/api/v1/es/laws?q=propiedad+intelectual", { headers: HEADERS });
const { results } = await resp.json();
const reforms = await fetch(`https://legalize.dev/api/v1/es/laws/${results[0].id}/reforms`, { headers: HEADERS })
.then(r => r.json());
console.log(`${reforms.total} reforms found`);
export KEY="leg_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
curl -H "Authorization: Bearer $KEY" \
"https://legalize.dev/api/v1/es/laws?q=propiedad+intelectual"
curl -H "Authorization: Bearer $KEY" \
"https://legalize.dev/api/v1/es/laws/BOE-A-1996-8930/reforms"
curl -H "Authorization: Bearer $KEY" \
"https://legalize.dev/api/v1/es/laws/BOE-A-1996-8930/commits"
Built with its users
This API is shaped by the people who use it. Missing an endpoint? Need a data format? Have an idea?
Tell us — every message is read by the founder.
Error handling
All errors return JSON with error and message fields.
Rate-limited responses (429) include a Retry-After header in seconds.
Retry with exponential backoff.
On 429 or 5xx, wait and retry with increasing delays: 1s, 2s, 4s, 8s… up to 60s.
Add random jitter to avoid thundering herd. Example:
import time, random
def request_with_retry(url, headers, max_retries=4):
for attempt in range(max_retries):
resp = requests.get(url, headers=headers)
if resp.status_code not in (429, 500, 502, 503):
return resp
wait = min(2 ** attempt + random.random(), 60)
time.sleep(wait)
return resp
What will you build?
Compliance dashboards. Legal AI assistants. Reform trackers. Civic tech tools. Journalism investigations. Academic research. The data is here — the rest is up to you.
Get your free API key