Federal Register API in Python: Search Rules and Notices

Title card for the Vaquill AI guide: Federal Register API in Python: Search Rules and Notices

Ask the Federal Register API for page 51 of a large search and it answers "200 OK" with the documents from page 1. No error, no warning. A loop that pages until "nothing new comes back" never stops, and a loop that stops at a repeat quietly drops most of your data.

Short answer: the Federal Register has a free JSON API that needs no key. Call documents.json with filters, ask only for the fields you need, and take at most 1,000 results per page. Do not page deep on one query. The service stops counting at 10,000 results and, on small page sizes, stops serving new pages after page 50. Slice by publication date instead, and check that you collected exactly the number the response reports.

Written and checked on 12 October 2026. This is general information, not legal advice; check the cited statute or opinion before relying on it.

TL;DR

  • No key, JSON, one search endpoint. documents.json does most of the work. Use fields[] to return only what you need.
  • Filter by type, agency, date, CFR part, docket or RIN. The four document types are rules, proposed rules, notices and presidential documents.
  • The paging trap is real and undocumented. Use per_page=1000, slice by date, and assert that your total equals the reported count.
  • "Open for comment" is a filter you write yourself, on the comment deadline field, and that field is sometimes empty when the text has a date.
  • The site is an unofficial display. The official edition is the govinfo PDF, and every record links to it.
What would you check?
Question 1 of 4

You collect every final rule from one agency over ten years by requesting page after page until a page comes back empty. Your total is lower than the agency's own list, and some documents appear twice. What is the likeliest cause?

Official text, as of 12 October 2026

Source: the Office of the Federal Register's "About This Site" page on federalregister.gov, read today.

What it says: the legal status notice says the site "will remain an unofficial informational resource until the Administrative Committee of the Federal Register (ACFR) issues a regulation granting it official legal status." The page adds that "those relying on it for legal research should verify their results against an official edition of the daily Federal Register." Each document on the site links to the matching official PDF on govinfo.gov. Read the page: About This Site.

The example used below: document E9-20169, 74 FR 42740, published August 24, 2009. Its official PDF is at govinfo.gov.

What changed in 2025 and 2026: not verified in our October 2026 review for this API. The paging behaviour described below was observed on 12 October 2026 and is not in the documentation, so re-test it before you depend on it (one request, shown in the table).

What you are calling

The base address is https://www.federalregister.gov/api/v1/. The machine-readable description is an OpenAPI 3.0.0 file titled "FR API Documentation," version 1, at https://www.federalregister.gov/developers/documentation/api/v1.json. The interactive documentation page says: "FederalRegister.gov APIs do not require API keys; all you need is an HTTP client or browser."

PathWhat it returns
/documents/{number}.jsonOne document by document number
/documents/{n1},{n2}.jsonSeveral documents in one call
/documents.jsonSearch. The spec describes it as "all Federal Register documents published since 1994"
/documents/facets/{facet}Counts grouped by a facet such as agency
/public-inspection-documents/current.jsonDocuments filed for public inspection and not yet published
/agencies and /agencies/{slug}Agency details; the slug is the value you filter on

The spec also lists a table of contents by issue date, images and suggested searches. A search takes 27 parameters, 22 of them filters. The record can return any of 56 named fields. Document types are RULE, PRORULE (proposed rule), NOTICE and PRESDOCU (presidential document). For how those types relate, see rulemaking explained: proposed rules, final rules and comments. For how the Federal Register differs from the CFR, see what a regulation is and how it differs from a statute.

Request 1: one document by number

We ran this on 12 October 2026. The fields[] parameter keeps the answer short.

curl -s 'https://www.federalregister.gov/api/v1/documents/E9-20169.json?fields[]=citation&fields[]=type&fields[]=publication_date&fields[]=effective_on&fields[]=comments_close_on&fields[]=cfr_references&fields[]=regulation_id_numbers&fields[]=pdf_url'

The response, trimmed to those fields:

{
  "citation": "74 FR 42740",
  "type": "Rule",
  "publication_date": "2009-08-24",
  "effective_on": "2009-09-23",
  "comments_close_on": null,
  "cfr_references": [{"title": 45, "part": 160}, {"title": 45, "part": 164}],
  "regulation_id_numbers": ["0991-AB56"],
  "pdf_url": "https://www.govinfo.gov/content/pkg/FR-2009-08-24/pdf/E9-20169.pdf"
}

This is the Department of Health and Human Services interim final rule "Breach Notification for Unsecured Protected Health Information." Two documents at once also work: /documents/E9-20169,E9-20142.json returned this rule and the Federal Trade Commission's Health Breach Notification Rule (74 FR 42962, published August 25, 2009).

Document numbers come in more than one shape. This 2009 document is E9-20169. Others we saw in this run look like 2010-17210 and 2026-20818. Treat the number as an opaque string.

Request 2: search with filters

The filters that matter most:

  • conditions[term] runs a full-text search. Wrap a phrase in double quotes to keep it together.
  • conditions[type][] takes RULE, PRORULE, NOTICE or PRESDOCU.
  • conditions[agencies][] takes the agency slug, such as health-and-human-services-department.
  • conditions[publication_date][gte] and [lte] set a date range. [year] and [is] also exist.
  • conditions[cfr][title] with conditions[cfr][part] finds documents that affect a CFR part.
  • conditions[docket_id] and conditions[regulation_id_number] find a docket or a Unified Agenda entry.
  • order takes relevance, newest, oldest or executive_order_number.

Here is a script we ran on 12 October 2026. It finds HHS final rules from 2009 to 2013 that contain the phrase "breach notification":

import requests

BASE = "https://www.federalregister.gov/api/v1/documents.json"
params = {
    "conditions[term]": '"breach notification"',   # quotes keep the phrase together
    "conditions[type][]": "RULE",
    "conditions[agencies][]": "health-and-human-services-department",
    "conditions[publication_date][gte]": "2009-01-01",
    "conditions[publication_date][lte]": "2013-12-31",
    "order": "oldest",
    "per_page": 1000,
    "fields[]": ["document_number", "citation", "title", "publication_date"],
}
data = requests.get(BASE, params=params, timeout=60).json()
print(data["count"], "rules,", data["total_pages"], "page")
for d in data["results"][:3]:
    print(d["publication_date"], d["citation"], d["document_number"], d["title"][:60])

Output:

7 rules, 1 page
2009-04-27 74 FR 19006 E9-9512 Guidance Specifying the Technologies and Methodologies That 
2009-08-24 74 FR 42740 E9-20169 Breach Notification for Unsecured Protected Health Informati
2010-07-28 75 FR 44590 2010-17210 Health Information Technology: Initial Set of Standards, Imp

The quotes matter. The same query without them returned 25 rules. The response always has the same envelope: description, count, total_pages, next_page_url and results.

The facets endpoint answers "who wrote about this" without fetching documents. We asked for the agency counts for the quoted phrase in documents published in 2009 and got HHS 5, FTC 2, FCC 1, GSA 1 and HRSA 1:

curl -s 'https://www.federalregister.gov/api/v1/documents/facets/agency?conditions[term]="breach notification"&conditions[publication_date][year]=2009'

The paging trap, with the evidence

The documentation lists per_page with a default of 20 and a maximum of 1,000. It says nothing about how deep a query can go. We tested on 12 October 2026. None of this is documented, so treat it as an observation and re-run it.

RequestWhat came back
All documents, oldest first, per_page=200, pages 1, 50, 51count: 10000, total_pages: 50. Page 50 returned documents from April 1994. Page 51 returned the same first document as page 1 (93-30302, January 3, 1994), with HTTP 200.
June 2025 only, per_page=20count: 2102 but total_pages: 50. Page 50 was fine. Pages 51, 52 and 106 all repeated page 1 (2025-09447). Only the first 1,000 documents are reachable at this page size.
Same June 2025 slice, following each next_page_urlThe chain ended after 50 pages with 1,000 unique documents. No error, and 1,102 documents never arrived.
Same June 2025 slice, per_page=1000Three pages (1,000, 1,000 and 102), then an empty page 4. All 2,102 documents, no duplicates.
All documents, per_page=1000, page 11HTTP 400: "Pagination limit exceeded. No more than 10000 items can be requested at a time"
Whole calendar year 2025count: 10000. That is a ceiling, not the true number, since June alone has 2,102.
per_page=1Returned 20 results, although the spec gives a minimum of 1

The rules that follow are short.

  1. Use per_page=1000. At that size the page limit never bites below the 10,000 ceiling.
  2. Slice by publication date so each slice reports a count under 10,000. A count of exactly 10,000 means "too big, narrow it."
  3. Assert that the number you collected equals count. That one line catches both the ceiling and the 50-page stop.
  4. Never loop "until empty" or "until a page repeats." Neither signal is reliable here.

To re-test, request documents.json?order=oldest&per_page=200&page=51 and compare its first document number with page 1.

Find proposed rules that are still open for comment

The search filters cover publication and effective dates. The spec lists no filter on the comment deadline, so you fetch recent proposed rules and filter in Python on the comments_close_on field. The script below also keeps the dates text, for a reason shown right after the output. It ran on 12 October 2026:

import datetime as dt
import requests

BASE = "https://www.federalregister.gov/api/v1/documents.json"
HEADERS = {"User-Agent": "rule-monitor (you@example.com)"}


def search(params):
    """Fetch every result for one query, and fail loudly if any are missing."""
    first = requests.get(BASE, params={**params, "per_page": 1000},
                         headers=HEADERS, timeout=60).json()
    if first["count"] >= 10000:
        raise ValueError("10,000 is the ceiling: narrow the date range")
    rows, url = first["results"], first.get("next_page_url")
    while url:
        page = requests.get(url, headers=HEADERS, timeout=60).json()
        rows += page["results"]
        url = page.get("next_page_url")
    assert len(rows) == first["count"], (len(rows), first["count"])
    return rows


rows = search({
    "conditions[type][]": "PRORULE",
    "conditions[publication_date][gte]": "2026-08-01",
    "fields[]": ["citation", "title", "agency_names", "comments_close_on", "dates"],
})
today = dt.date.today().isoformat()
open_ = sorted((r for r in rows if (r["comments_close_on"] or "") >= today),
               key=lambda r: r["comments_close_on"])
no_date = [r for r in rows if not r["comments_close_on"]]

print(len(rows), "proposed rules;", len(open_), "open;", len(no_date), "with no deadline field")
for r in open_[:3]:
    print(r["comments_close_on"], r["citation"], r["agency_names"][0], "|", r["title"][:48])
print("no deadline field, but the DATES text mentions comments:")
for r in no_date:
    if "comment" in (r["dates"] or "").lower():
        print(r["citation"], "|", r["dates"][:80])

Output:

346 proposed rules; 184 open; 34 with no deadline field
2026-10-13 91 FR 57828 Agriculture Department | Modernization of Regulations Under 9 CFR Parts 1
2026-10-13 91 FR 57728 Nuclear Regulatory Commission | In Situ Recovery Monitoring and Decommissioning 
2026-10-13 91 FR 57532 Commerce Department | Reef Fish Fishery of the Gulf of America; 2027 R
no deadline field, but the DATES text mentions comments:
91 FR 61367 | Written or electronic comments and requests for a public hearing must be receive
91 FR 57832 | Written or electronic comments and requests for a public hearing must be receive
91 FR 56811 | Written or electronic comments and requests for a public hearing must be receive
91 FR 53803 | Written or electronic comments and requests for a public hearing must be receive

Read the last four lines closely. Four proposed rules with an empty deadline field had a comment date in their dates text, so a filter on the field alone would have missed them. The full strings give November 30, November 10, November 3 and October 19, 2026. Of the 34 records with no deadline field, the other 30 did not mention comments in the dates text (5 had no dates text at all), and we did not read each one.

The 2009 rule used earlier shows the same trap. Its comments_close_on is null, yet the DATES section of its text reads: "Comments on the provisions of this interim final rule are due on or before October 23, 2009." We read that in the document's full text. Treat the structured field as a convenience, and treat the document text as the source. To read or file the comments themselves, use the docket ID with the Regulations.gov API.

Public inspection: what is scheduled, not what is law

/public-inspection-documents/current.json lists documents filed for public inspection before they publish. On 12 October 2026 it returned 108 documents: 103 with a scheduled publication date of October 13 and 5 for October 14. The envelope has count, results, special_filings_updated_at and regular_filings_updated_at.

The Office of the Federal Register's explainer says the Federal Register Act requires it to file documents for public inspection "at least one business day before publication," citing 44 U.S.C. 1503 and 1507. It posts a new set around 8:45 a.m. Eastern. The page also says public inspection documents are "only tentatively scheduled for publication because agencies may withdraw documents from publication in the Federal Register." Only an official format of the published document "provides legal notice to the public and judicial notice to the courts under 44 U.S.C. 1507." So an alert built on this feed should say "scheduled," not "published." Read the full page: Understanding Public Inspection.

The cfr_references field lists the title and part of each CFR part a document affects. For E9-20169 that is 45 CFR parts 160 and 164. You can build the eCFR address from it, for example https://www.ecfr.gov/current/title-45/part-164. The regulation_id_numbers field holds the Regulation Identifier Number (RIN), 0991-AB56 here. The rule's own text tells commenters to identify their comments by that RIN. The docket_ids field lists agency docket numbers where the agency supplies them, and it is empty for this 2009 rule. For the CFR side, our guide to the CFR and its annual editions covers how the Code of Federal Regulations is built from documents like this one.

Limits, honestly

No rate limit appears on the API documentation page or the developer resources page we read. On 12 October 2026 we sent 25 requests for one document in a row. All returned 200, none carried a rate-limit header, and the responses were marked cache-control: no-store. That is an observation and not a promise. The website's HTML pages are a separate matter: after a burst of page fetches in the same session, they redirected us to a request-access page and returned HTTP 429, while the API kept answering 200. Fetch data from the API, not from the pages. Send a descriptive User-Agent with a contact address as in the script above, pause between calls, and cache what you have already fetched.

Which call to use

Loading diagram...

What developers say

The promise is old. In a Hacker News thread about the Federal Register API in August 2011, a commenter quoted the API page ("No API keys are needed; all you need is an HTTP client or browser.") and replied: "Thank you - I wish everybody did this." (nikcub, Hacker News, August 2011). A developer on the project answered in the same thread: "I'm one of the developers on the Federal Register 2.0 project." (andrewcarpenter, Hacker News, August 2011). The current documentation uses nearly the same sentence. For a longer set of developer reactions to the site, see our Federal Register API post.

Where a maintained feed fits

Polling a free endpoint is enough for a script or a one-off study. When you want alerts on change, a stable identifier and a link from a rule to the CFR section it touches, you are building a pipeline around the same data. Our Federal Register API post describes a maintained copy of agency rules, final and proposed, that starts in 1994. For the wider habit of tracking change, see regulatory monitoring: how to keep track of rule changes. The rest of the federal and state sources are mapped in US Law Data: The Complete Guide.

What goes wrong

  • Looping until a page is empty. Page 51 is not empty. It is page 1 again.
  • Trusting total_pages. It stopped at 50 for a search that needs 106 pages at 20 per page.
  • Reading a count of 10,000 as a real total. It is the ceiling.
  • Filtering on a blank comment deadline. Check the dates text first.
  • Calling a public inspection document "published." It is scheduled, and an agency can withdraw it.
  • Quoting the website as the official text. Link the PDF.

FAQ

Is there a Federal Register API?

Yes. It is free and returns JSON. The main endpoint is documents.json, with other paths for one document, several documents, counts by facet, public inspection and agencies.

Do I need an API key for the Federal Register API?

No. The documentation says: "FederalRegister.gov APIs do not require API keys; all you need is an HTTP client or browser." Other government APIs differ. The Regulations.gov and GovInfo APIs do need a key, and our GovInfo API guide shows how that works.

How do I use the Federal Register API in Python?

Use requests to call documents.json with conditions[...] parameters and fields[] for the fields you want. The scripts above are complete and ran as shown. Add per_page=1000 and slice large searches by publication date.

How many results can I get, and how do I page through them?

Up to 1,000 per page, and in our October 2026 tests a query stopped at 10,000 results. On smaller page sizes, pages after 50 repeated page 1. Slice by date and check that your total equals count.

How do I find rules that are open for comment?

Fetch proposed rules from a recent date range and keep those whose comments_close_on is today or later. Review records where that field is empty, because the date can sit only in the dates text.

How do I get the full text of a document?

The record has full_text_xml_url, raw_text_url, body_html_url and pdf_url fields. The PDF on govinfo is the official format. The others are renditions on the unofficial site.

Is there a rate limit?

None is published on the pages we read. Be polite anyway: identify yourself in the User-Agent, pause between requests and cache results.

For the US statutes, regulations and court rules these laws sit in, see the US primary law API.

Connect our US primary law database.
Every US statute, regulation, constitution, and executive order via REST, MCP or SQL. 5.3M+ sections, section-level citations, and links to the official source. Plus a free open dataset.
Updated October 12, 202618 min read

New legal AI guides, weekly.

Priyansh Khodiyar

Priyansh Khodiyar

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.