Georgia Commons

API

Georgia's public documents, for your code

A read-only JSON API over the Official Code of Georgia Annotated, General Assembly bills, and Supreme Court of Georgia opinions. There is no key, no account, and no sign-up. Point a script at it and start reading.

Machine-readable https://georgiacommons.org/api.md · https://georgiacommons.org/index.md · MCP https://mcp.georgiacommons.org/mcp

Base URL

Base URL

https://api.georgiacommons.org/api
  • Public and read-only. Every route below is a GET, apart from the two POST routes that check a quotation. There is nothing to authenticate and no key to request.
  • One grammar across collections. Each collection answers the same shape at https://api.georgiacommons.org/api/{collection}, where the collection is code, bills, or opinions. Learn one and you know all three.
  • The same data everywhere. This API, the pages on georgiacommons.org, and the MCP server read the same stores. Nothing is a copy that can fall behind.
  • Ask the API what it holds. Coverage is never a claim typed into a page. /{collection}/meta reports what is actually loaded, computed when you ask: https://api.georgiacommons.org/api/code/meta.

Your first request

Statutes are addressed by citation. Ask for the Georgia security deposit statute, O.C.G.A. 44-7-34:

curl "https://api.georgiacommons.org/api/code/sections/44-7-34"

The response carries the section's identity, its status, what it is current through, the addresses of its page and its Markdown twin, and every stored version with its text. Abbreviated:

{
  "citation": "44-7-34",
  "catchline": "Return of security deposit; grounds for retention of part; ...",
  "title": 44,
  "chapter": "7",
  "status": "active",
  "current_through": "Including Acts of the 2025 Regular Session of the General Assembly",
  "canonical_url": "https://georgiacommons.org/code/44-7-34",
  "md_url": "https://georgiacommons.org/code/44-7-34.md",
  "versions": [ ... ],
  "previous": { ... },
  "next": { ... }
}

A bill and an opinion answer the same way at their own addresses: /api/bills/bills/2025-2026/hb136 and /api/opinions/cases/S26A0060. The full list is on the endpoints page.

Identifiers are the ones you already use

There are no internal ids to look up first. A document is addressed by the name it has in the world: a citation, a session and a bill number, a docket number.

CollectionAddressExample
Code/api/code/sections/{citation}44-7-34
Constitutions/api/code/constitution/{ga|us}/{slug}art-i-sec-i-para-i, amend-xiv
Bills/api/bills/bills/{session}/{number}2025-2026/hb136
Opinions/api/opinions/cases/{docket}S26A0060

Written forms that are not the canonical one still resolve. /{collection}/resolve?q= reports where a reference leads, and it accepts what people actually write: HB 136, H.B. 136, House Bill 136, a reporter citation such as 883 S.E.2d 746, a lower-case docket, or an upstream LegiScan or CourtListener id. Upstream ids also redirect permanently from the document routes, so an old link keeps working.

A 404 is written to be useful: it names the nearest sections, the chapter above, or the adjacent bill numbers, so a script that guessed wrong can correct itself without a second search.

Markdown and plain text, not just JSON

Every document has three forms. JSON is for programs that want fields. Markdown is for anything that wants to read the document, a language model included. Plain text is the source text alone, with nothing added.

The Markdown and plain-text forms are served from the site host, not the API host: add .md or /text to any page address, or send Accept: text/markdown to the page itself. Each twin opens with frontmatter naming the citation, the official source, the date, the corpus version, and the license, then the source text. Anything Georgia Commons wrote sits after the source text, under a heading that says so. The Code and the constitutions have nothing after the source text at all.

The API also serves Markdown directly, for callers that would rather stay on one host: /{collection}/index/markdown, /about/markdown, /search/markdown, and a /markdown route on every document.

Reading many documents, and checking a quote

/{collection}/items?ids= reads up to 20 documents in one call. The Code also accepts a range, 44-7-30..44-7-35, up to 40 sections. When a request exceeds the cap the response names the remainder in next_ids, so a loop can continue without bookkeeping.

POST /{collection}/verify answers one question: does this quotation appear, word for word, in the stored document? It normalizes the same way the ingestion quote filter does, and no model is involved.

curl -X POST "https://api.georgiacommons.org/api/code/verify" \
  -H "Content-Type: application/json" \
  -d '{"id": "44-7-34", "quote": "security deposit"}'
{
  "id": "44-7-34",
  "found": true,
  "occurrences": 7,
  "in": "text",
  "chars": 16,
  "canonical_url": "https://georgiacommons.org/code/44-7-34",
  "md_url": "https://georgiacommons.org/code/44-7-34.md",
  "corpus_version": "2025-supplement-3590ef6b4551"
}

Quotes shorter than 12 characters are refused with a 422: below that, a match means nothing.

Caching

Read routes carry an ETag and a Cache-Control. Send the tag back in If-None-Match and an unchanged document answers 304 with no body.

curl -s -D - -o /dev/null "https://api.georgiacommons.org/api/code/sections/44-7-34" | grep -i etag
curl -s -o /dev/null -w '%{http_code}\n' \
  -H 'If-None-Match: "<the etag you were given>"' \
  "https://api.georgiacommons.org/api/code/sections/44-7-34"
  • Send the tag back exactly. Comparison is string equality, quotes included. Weak tags (W/), comma-separated lists, and * are not handled.
  • The tag is deterministic. It is a hash of the response body, so the same corpus always produces the same tag. A tag you stored last week is still valid if nothing changed.
  • Freshness by kind. Documents are max-age=86400 with a week of stale-while-revalidate; lists and search are max-age=3600 with a day. verify is no-store.
  • No `If-Modified-Since`. Date-based revalidation is not implemented. Use the ETag.
  • Ask with a GET. curl -I sends a HEAD, and the ETag does not come back on one. Use curl -s -D - -o /dev/null as above.

Rate limits and errors

Reads are limited to 120 requests a minute and 2,000 an hour per caller, shared across all three collections. Over the limit is a 429 with a Retry-After header saying how long to wait. Honor it; there is no penalty for backing off and no benefit to retrying sooner.

If you need more than that for a one-off analysis, take the bulk download instead of walking the API, and write to the address on the about page if you need something the bundle does not cover.

StatusWhat it means
200Here it is.
301 or 308You used an upstream id or a form with a canonical address. Follow the redirect; it is permanent.
304Your If-None-Match tag still matches. Nothing changed.
404No such document. The body names the nearest ones and the unit above.
422The request was understood but not usable, for instance a quote under 12 characters.
429Over the rate limit. Wait for Retry-After seconds.

Two routes are not part of this API: the streaming question answering behind the chat panels on bill and opinion pages. They hold a server-side key, they are the site's own, and there is no way to obtain that key. Everything else on this page is open to anyone.

Bulk download

The whole Code, with both constitutions, is published as a downloadable bundle. https://api.georgiacommons.org/api/code/bulk returns a JSON listing of the release page, the checksum file, and each asset with its address.

curl "https://api.georgiacommons.org/api/code/bulk"
  • Five files. The Code, the Georgia constitution, and the United States constitution as gzipped JSON Lines, a manifest, and SHA256SUMS over the four. Verify the checksums before you load anything.
  • Reproducible. The gzip streams carry no timestamp, so the same corpus publishes the same bytes and a checksum is comparable across downloads.
  • CC0. The Code corpus is public law with no rights reserved.
  • Bills and opinions have no bundle yet. Enumerate them through /{collection}/sitemap-entries and read them with /items?ids=.

For AI agents

Georgia Commons is built to be read by assistants and agents as much as by people. If you are writing one, or pointing one here, these are the addresses that matter:

Crawling is welcome, including for training. robots.txt says so by name on both hosts, and it carries Content-Signal: search=yes, ai-input=yes, ai-train=yes.