---
title: API
collection: site
id: api
description: A read-only JSON API over the Georgia Code, General Assembly bills, and Supreme Court opinions. No key, no account, no sign-up.
canonical_url: https://georgiacommons.org/api
md_url: https://georgiacommons.org/api.md
publisher: Georgia Commons, an independent project of Georgia Civic Data. Not the State of Georgia. Not legal advice.
index: https://georgiacommons.org/index.md
for_assistants: https://georgiacommons.org/for-assistants
mcp: https://mcp.georgiacommons.org/mcp
---

# 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.

## 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](https://georgiacommons.org/), and the [MCP server](https://georgiacommons.org/mcp) 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:

```bash
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:

```json
{
  "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](https://georgiacommons.org/api/endpoints).

## 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.

| Collection | Address | Example |
| --- | --- | --- |
| 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. One exception, in bills: a bill that amends current law prints deletions struck through and additions underlined, and the text keeps those marks as <del> and <ins> tags around the words, the way the printed page shows them.

- **JSON:** https://api.georgiacommons.org/api/code/sections/44-7-34
- **Markdown:** https://georgiacommons.org/code/44-7-34.md
- **Plain text:** https://georgiacommons.org/code/44-7-34/text

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.

## Search

Each collection has a full-text index over the document text, its headings, and, for bills and opinions, the labeled summaries. `?q=` takes words; `&in=headings` restricts the match to headings and titles.

```bash
curl "https://api.georgiacommons.org/api/code/search?q=security+deposit&limit=5"
```

The response separates `direct` from `hits`. A bare citation, bill number, or docket among the words is a lookup, and it comes back in `direct`. `hits` holds the ranked full-text matches. `terms` and `dropped` report which of your words were searched and which were dropped as stopwords, which is usually enough to explain a surprising result.

**Search matches the words of the document. Ask in the words the document would use, not the words of the question.** A statute about a child says "minor"; an opinion about a car crash says "motor vehicle".

## 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.

```bash
curl -X POST "https://api.georgiacommons.org/api/code/verify" \
  -H "Content-Type: application/json" \
  -d '{"id": "44-7-34", "quote": "security deposit"}'
```

```json
{
  "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.

```bash
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](https://georgiacommons.org/api#bulk) instead of walking the API, and write to the address on the [about page](https://georgiacommons.org/about) if you need something the bundle does not cover.

| Status | What it means |
| --- | --- |
| `200` | Here it is. |
| `301` or `308` | You used an upstream id or a form with a canonical address. Follow the redirect; it is permanent. |
| `304` | Your `If-None-Match` tag still matches. Nothing changed. |
| `404` | No such document. The body names the nearest ones and the unit above. |
| `422` | The request was understood but not usable, for instance a quote under 12 characters. |
| `429` | Over 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.

```bash
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:

- **MCP server.** One connector for the whole site, streamable HTTP, no key: https://mcp.georgiacommons.org/mcp. The [MCP page](https://georgiacommons.org/mcp) has the per-client steps.
- **Site map for machines.** https://georgiacommons.org/index.md, one block per collection with every address it answers.
- **llms.txt.** https://georgiacommons.org/llms.txt, in the llms.txt convention, with worked examples of every address form.
- **For assistants.** https://georgiacommons.org/for-assistants, the one-screen reference for an agent's operator: the URL grammar and one worked example per collection.
- **OpenAPI schema.** https://api.georgiacommons.org/openapi.json describes every route this API serves. There is no hosted Swagger or ReDoc page; paste the schema into the viewer you prefer. The two chat routes appear in it and answer 403 without the site's key.

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`.

Georgia Commons, an independent project of Georgia Civic Data. Not the State of Georgia. Not legal advice.
