API Documentation
Learn how to use the eCFR Browser API to access CFR data programmatically.
Introduction
The eCFR Browser API provides programmatic access to the Code of Federal Regulations (CFR) data. You can use this API to retrieve titles, parts, sections, and content from the CFR.
The API is RESTful and returns data in JSON format. All endpoints are relative to the base URL of the application.
Base URL
All API endpoints are relative to the base URL of the application.
Authentication
Most endpoints do not require authentication. However, some endpoints that modify data (like bookmarks) use a static user ID for demonstration purposes.
Rate Limiting
There is currently no rate limiting implemented for the API endpoints. However, please be considerate and avoid making too many requests in a short period of time.
Error Handling
All API endpoints return appropriate HTTP status codes:
200 OK: The request was successful400 Bad Request: The request was invalid404 Not Found: The requested resource was not found500 Internal Server Error: An error occurred on the server
Error responses include a JSON object with an error field:
{
"error": "Error message"
}Redis Cache Integration
The eCFR Browser uses Redis for caching to improve performance and reduce database load. This section explains how Redis is integrated into the application and how it affects API responses.
Cache Architecture
The Redis cache stores CFR references and search indexes to enable fast lookups and search operations. Several key structures are used to organize the data:
Key Structures
The Redis cache uses the following key patterns:
cfr:ref:[normalized_reference]: Stores CFR section data by normalized reference (e.g., "21cfr101.9")cfr:search:index: A sorted set containing all searchable CFR referencescfr:cache:last_updated: Timestamp of the last cache updatecfr:cache:population_status: JSON object with information about the cache population processcfr:search:index:status: JSON object with information about the search index status
Example of a cache population status object:
{
"totalRecords": 39178,
"processedRecords": 2000,
"cachedRecords": 2000,
"inProgress": false,
"lastProcessedId": 2034,
"startTime": "2025-04-28T00:24:18.233Z",
"endTime": "2025-04-28T12:00:50.846Z"
}Cache-Enabled Endpoints
The following API endpoints utilize the Redis cache for improved performance:
Section Reference Endpoint
The /api/ecfr/section/reference endpoint checks the Redis cache before querying the database:
Example: Redis Cache Flow for Section Reference
// Pseudocode for the section reference endpoint
async function getSectionByReference(reference) {
// Normalize the reference
const normalizedRef = normalizeReference(reference);
// Check Redis cache
const key = createCfrReferenceKey(normalizedRef); // Returns "cfr:ref:" + normalizedRef
const cachedData = await redis.get(key);
if (cachedData) {
// Return the cached section data
return JSON.parse(cachedData);
}
// If not in cache, query database
const section = await database.getSectionByReference(normalizedRef);
if (section) {
// Update cache for future requests
await redis.set(key, JSON.stringify({
id: section.id,
reference: normalizedRef,
titleNumber: section.parts.titles.number,
titleName: section.parts.titles.name,
partNumber: section.parts.number,
partName: section.parts.name,
sectionNumber: section.number,
sectionName: section.name,
sectionText: section.regulation_text
}));
}
return section;
}Search Endpoint
The /api/ecfr/search and related search endpoints use the sorted set in Redis (cfr:search:index) to quickly find matching CFR references:
Example: Redis Search Implementation
// Pseudocode for searching CFR references
async function searchCfrReferences(query, limit = 50) {
// Normalize the query
const normalizedQuery = query.trim().toLowerCase();
// Prepare match pattern for ZSCAN
const matchPattern = "*" + normalizedQuery + "*";
// Create a map to store unique results
const resultsMap = new Map();
// Get entries matching the pattern using ZSCAN
let cursor = 0;
do {
// Scan the sorted set for matches
const scanResult = await redis.zscan("cfr:search:index", cursor, {
match: matchPattern,
count: 100
});
cursor = scanResult[0];
const matches = scanResult[1];
// Process matches
for (let i = 0; i < matches.length; i += 2) {
const reference = matches[i];
const key = "cfr:ref:" + reference;
// Get the full data for this reference
const data = await redis.get(key);
if (data && resultsMap.size < limit) {
const parsed = JSON.parse(data);
resultsMap.set(parsed.id, parsed);
}
}
} while (cursor !== 0 && resultsMap.size < limit);
// Fall back to database if needed
if (resultsMap.size === 0) {
await databaseFallbackSearch(normalizedQuery, limit, resultsMap);
}
return Array.from(resultsMap.values()).slice(0, limit);
}API Endpoints
Titles
{
"titles": [
{
"id": 1,
"number": "1",
"name": "General Provisions",
"description": "General provisions and definitions applicable across federal regulations.",
"created_at": "2023-01-01T00:00:00.000Z",
"updated_at": "2023-01-01T00:00:00.000Z"
},
{
"id": 2,
"number": "2",
"name": "Grants and Agreements",
"description": "Regulations governing federal grants and cooperative agreements.",
"created_at": "2023-01-01T00:00:00.000Z",
"updated_at": "2023-01-01T00:00:00.000Z"
}
]
}Example: Fetching all titles
// Using fetch API
fetch('/api/ecfr/titles')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));Parts
{
"parts": [
{
"id": 1,
"title_id": 1,
"number": "1",
"name": "Definitions",
"description": "General definitions used throughout the Code of Federal Regulations.",
"created_at": "2023-01-01T00:00:00.000Z",
"updated_at": "2023-01-01T00:00:00.000Z"
},
{
"id": 2,
"title_id": 1,
"number": "2",
"name": "General Provisions",
"description": "General provisions applicable throughout federal regulations.",
"created_at": "2023-01-01T00:00:00.000Z",
"updated_at": "2023-01-01T00:00:00.000Z"
}
]
}Example: Fetching parts by title
// Using fetch API
fetch('/api/ecfr/parts?titleId=1')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));Sections
{
"section": {
"id": 1,
"part_id": 1,
"number": "1.1",
"name": "Definitions",
"content_path": "sections/1/1/1.1.md",
"publication_year": "2019",
"last_updated": "2023-01-01T00:00:00.000Z",
"created_at": "2023-01-01T00:00:00.000Z",
"updated_at": "2023-01-01T00:00:00.000Z",
"regulation_text": "# §1.1 Definitions\n\n(a) As used in this chapter...",
"cfr_reference": "1 CFR 1.1"
},
"content": "# §1.1 Definitions\n\n(a) As used in this chapter..."
}Example: Fetching a section by ID
// Using fetch API
fetch('/api/ecfr/content/1')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));{
"section": {
"id": 1,
"part_id": 1,
"number": "1.1",
"name": "Definitions",
"content_path": "sections/1/1/1.1.md",
"publication_year": "2019",
"last_updated": "2023-01-01T00:00:00.000Z",
"created_at": "2023-01-01T00:00:00.000Z",
"updated_at": "2023-01-01T00:00:00.000Z",
"regulation_text": "# §1.1 Definitions\n\n(a) As used in this chapter...",
"cfr_reference": "1 CFR 1.1",
"parts": {
"id": 1,
"number": "1",
"name": "Definitions",
"titles": {
"id": 1,
"number": "1",
"name": "General Provisions"
}
}
}
}Example: Fetching a section by CFR reference
// Using fetch API
fetch('/api/ecfr/section/reference?reference=1 CFR 1.1')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));Search
{
"results": [
{
"id": 1,
"part_id": 1,
"number": "1.1",
"name": "Definitions",
"content_path": "sections/1/1/1.1.md",
"publication_year": "2019",
"last_updated": "2023-01-01T00:00:00.000Z",
"created_at": "2023-01-01T00:00:00.000Z",
"updated_at": "2023-01-01T00:00:00.000Z",
"regulation_text": "# §1.1 Definitions\n\n(a) As used in this chapter...",
"cfr_reference": "1 CFR 1.1",
"parts": {
"id": 1,
"number": "1",
"name": "Definitions",
"titles": {
"id": 1,
"number": "1",
"name": "General Provisions"
}
}
}
],
"totalCount": 1,
"page": 1,
"pageSize": 10,
"totalPages": 1
}Example: Searching for sections
// Using fetch API
fetch('/api/ecfr/search?q=definitions&page=1&pageSize=10')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));Bookmarks
{
"bookmarks": [
{
"id": 1,
"user_id": "default-user",
"section_id": 1,
"created_at": "2023-01-01T00:00:00.000Z",
"updated_at": "2023-01-01T00:00:00.000Z",
"section": {
"id": 1,
"part_id": 1,
"number": "1.1",
"name": "Definitions",
"cfr_reference": "1 CFR 1.1"
}
}
]
}{
"success": true,
"message": "Bookmark added successfully",
"bookmark": {
"id": 1,
"user_id": "default-user",
"section_id": 1,
"created_at": "2023-01-01T00:00:00.000Z",
"updated_at": "2023-01-01T00:00:00.000Z"
}
}{
"success": true,
"message": "Bookmark removed successfully"
}Cache Management
{
"status": {
"totalReferences": 39178,
"cacheSize": "~39178 references",
"lastUpdated": "2025-04-28T12:00:50.846Z",
"populationStatus": {
"totalRecords": 39178,
"processedRecords": 39178,
"cachedRecords": 39178,
"inProgress": false,
"lastProcessedId": 39178,
"startTime": "2025-04-28T00:24:18.233Z",
"endTime": "2025-04-28T12:00:50.846Z"
}
}
}{
"success": true,
"count": 100,
"lastProcessedId": 100,
"withFullText": true
}{
"success": true,
"message": "Cache cleared successfully"
}Client SDK
We recommend using a client-side SDK to interact with the eCFR Browser API. You can create a simple client wrapper like this:
Example: JavaScript SDK
// ecfr-client.js
class EcfrClient {
constructor(baseUrl = '') {
this.baseUrl = baseUrl;
}
async getAllTitles() {
return this.get('/api/ecfr/titles');
}
async getPartsByTitle(titleId) {
return this.get(`/api/ecfr/parts?titleId=${titleId}`);
}
async getSectionById(id) {
return this.get(`/api/ecfr/content/${id}`);
}
async getSectionByReference(reference) {
return this.get(`/api/ecfr/section/reference?reference=${encodeURIComponent(reference)}`);
}
async searchSections(query, page = 1, pageSize = 10) {
return this.get(`/api/ecfr/search?q=${encodeURIComponent(query)}&page=${page}&pageSize=${pageSize}`);
}
async getBookmarks() {
return this.get('/api/bookmarks');
}
async addBookmark(sectionId) {
return this.post('/api/bookmarks', { sectionId });
}
async removeBookmark(sectionId) {
return this.delete('/api/bookmarks', { sectionId });
}
async get(path) {
const response = await fetch(`${this.baseUrl}${path}`);
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`);
}
return response.json();
}
async post(path, data) {
const response = await fetch(`${this.baseUrl}${path}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`);
}
return response.json();
}
async delete(path, data) {
const response = await fetch(`${this.baseUrl}${path}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`);
}
return response.json();
}
}
// Usage
const client = new EcfrClient();
client.getAllTitles()
.then(data => console.log(data))
.catch(error => console.error('Error:', error));This SDK provides a convenient way to interact with the eCFR Browser API. You can extend it with additional methods as needed.
Webhooks
The eCFR Browser API does not currently support webhooks. This feature may be added in the future.
Support
If you have questions or need help with the eCFR Browser API, please contact the development team. We're happy to assist you with any issues or questions you might have.