Reference
RuleGrid API
A read-only JSON API over the short-term-rental regulation dataset. Every response carries its trust block — a last-verified date, source links, and a disclaimer. There is zero LLM on the serving path; responses are deterministic reads from the dataset.
Base URL
All endpoints are versioned under /v1, served from the apex domain.
https://rulegrid.dev/v1
Responses are application/json; charset=utf-8. All read endpoints allow cross-origin GET (Access-Control-Allow-Origin: *), so you can call them from a browser.
Authentication
Every endpoint except /v1/health requires an API key. Pass it as a Bearer token or the x-api-key header — either works.
Bearer
curl https://rulegrid.dev/v1/jurisdictions?state=FL \
-H "Authorization: Bearer rgk_live_0123456789abcdef0123456789abcdef"
x-api-key
curl https://rulegrid.dev/v1/jurisdictions?state=FL \
-H "x-api-key: rgk_live_0123456789abcdef0123456789abcdef"
Keys look like rgk_live_<32 hex> (or rgk_test_… in test mode). Your key is shown
exactly once when it is issued — store it securely; we only keep a hash and can't recover it.
No key returns 401 missing_key; an unknown, revoked, or inactive key returns 403 invalid_key.
Rate limits & quotas
Quotas are monthly, enforced in real time against usage. Metered endpoints count 1 call each; /v1/health is unmetered. Exceeding a monthly quota returns 429 quota_exceeded with a Retry-After header pointing to the month rollover.
| Plan | Included calls / month | Overage | Change feed |
|---|---|---|---|
| Free | 50 | Hard stop (429) | — |
| Host | 250 | Hard stop (429) | — |
| Pro | 2,500 | Hard stop (429) | Read |
| API | 15,000 | $0.02 / call, metered | Read + webhook |
Only the API plan bills overage (via Stripe metering); every other plan hard-stops at its quota. Overage metering is asynchronous and never blocks or delays a response.
Endpoints
GET /v1/lookup
Resolve the applicable jurisdiction stack for a location and return each layer's record plus a composed roll-up. Provide exactly one of:
| Parameter | Description |
|---|---|
address | Free-form US address or city, e.g. 123 Ocean Dr, Miami Beach, FL. Geocoded via the US Census geocoder. |
lat & lng | Decimal coordinates, e.g. lat=25.79&lng=-80.13. |
jurisdiction | A known jurisdiction id, e.g. us-fl-miami-beach — skips geocoding. |
Request
curl "https://rulegrid.dev/v1/lookup?address=123+Ocean+Dr,+Miami+Beach,+FL" \
-H "x-api-key: rgk_live_..."
Response · 200
{
"query": { "address": "123 Ocean Dr, Miami Beach, FL" },
"resolved": {
"state": "FL",
"county": "Miami-Dade",
"place": "Miami Beach",
"fips": { "state": "12", "county": "086", "place": "45025" },
"unincorporated": false
},
"stack": [
{ "jurisdiction_id": "us-fl", "level": "state", "name": "Florida",
"str_status": "allowed_with_registration", "verification": { "last_verified": "2026-06-28", "status": "verified", "confidence": "high" } },
{ "jurisdiction_id": "us-fl-miami-dade", "level": "county", "name": "Miami-Dade County",
"str_status": "allowed_with_registration", "verification": { "last_verified": "2026-06-25", "status": "verified", "confidence": "high" } },
{ "jurisdiction_id": "us-fl-miami-beach", "level": "city", "name": "Miami Beach",
"str_status": "restricted", "verification": { "last_verified": "2026-06-12", "status": "verified", "confidence": "high" } }
],
"composed": {
"str_status": "restricted",
"requirements": [
{ "layer": "state", "kind": "license", "name": "DBPR Vacation Rental License", "required": true },
{ "layer": "county", "kind": "tax_registration", "name": "Tourist Development Tax account", "required": true },
{ "layer": "city", "kind": "registration", "name": "Miami Beach STR registration", "required": true }
],
"taxes": [
{ "layer": "state", "name": "State Sales & Use Tax", "rate_pct": 6.0 },
{ "layer": "county", "name": "Tourist Development Tax", "rate_pct": 6.0, "platforms_remit": { "airbnb": false, "vrbo": false } }
]
},
"disclaimer": "Informational summary of public sources; not legal advice. Verify against the linked official sources."
}
Each record in stack is the full jurisdiction record (trimmed above for space). resolved.unincorporated is true when the address falls outside any incorporated place — in which case the stack is state → county only.
GET /v1/jurisdictions
List jurisdiction summaries. Filter with query params.
| Parameter | Description |
|---|---|
state | Two-letter state, e.g. FL. |
level | One of state, county, city. |
Request
curl "https://rulegrid.dev/v1/jurisdictions?state=FL&level=city" \
-H "x-api-key: rgk_live_..."
Response · 200
{
"count": 18,
"jurisdictions": [
{ "id": "us-fl-miami-beach", "name": "Miami Beach", "level": "city",
"str_status": "restricted", "last_verified": "2026-06-12" },
{ "id": "us-fl-kissimmee", "name": "Kissimmee", "level": "city",
"str_status": "allowed_with_registration", "last_verified": "2026-06-20" }
]
}
GET /v1/jurisdictions/:id
Fetch one full jurisdiction record by id — the complete normalized record, including requirements, restrictions, taxes, enforcement, sources, and the verification block.
Request
curl "https://rulegrid.dev/v1/jurisdictions/us-fl-miami-beach" \
-H "x-api-key: rgk_live_..."
Response · 200
{
"schema_version": "1.0",
"jurisdiction_id": "us-fl-miami-beach",
"level": "city",
"parent_id": "us-fl-miami-dade",
"name": "Miami Beach",
"state": "FL",
"str_status": "restricted",
"str_status_summary": "Short-term rentals are prohibited in most residential zones; permitted only in specified districts with city registration, resort tax registration, and a state license.",
"requirements": [
{ "kind": "registration", "layer": "city", "name": "Miami Beach STR Registration",
"required": true, "fee": { "amount": 571, "period": "annual", "notes": null },
"renewal": "annual", "url": "https://www.miamibeachfl.gov/...",
"evidence": "All short-term rental units must register annually with the City." }
],
"restrictions": {
"primary_residence_required": false, "min_stay_nights": null,
"max_nights_per_year": null, "zoning_restricted": true,
"zoning_notes": "Permitted only in listed districts; single-family zones excluded.",
"cap_on_licenses": false, "notes": [], "evidence": "..."
},
"taxes": [
{ "name": "Tourist Development Tax", "layer": "county", "rate_pct": 6.0,
"administered_by": "county", "platforms_remit": { "airbnb": false, "vrbo": false },
"registration_url": "https://...", "notes": "Self-administered county." }
],
"enforcement": {
"fines_summary": "First violation $20,000; escalating to $100,000 for repeats.",
"active_enforcement": "high", "notes": "Ban ruled illegal; appeal pending."
},
"sources": [
{ "source_id": "mb-str-page", "kind": "program_page",
"title": "City of Miami Beach — Short-Term Rentals",
"url": "https://www.miamibeachfl.gov/...", "monitored": true,
"last_checked": "2026-07-01", "last_content_change": "2026-03-14" }
],
"verification": {
"last_verified": "2026-06-12", "last_changed": "2026-03-14",
"status": "verified", "confidence": "high"
},
"disclaimer": "Informational summary of public sources; not legal advice. Verify against the linked official sources."
}
A missing id returns 404 not_found using the standard error envelope.
GET /v1/changes
The append-only change log — every field that moved between pipeline runs, newest first.
| Parameter | Description |
|---|---|
since | ISO-8601 timestamp or YYYY-MM-DD; returns changes detected at or after this time. |
state | Two-letter state filter, e.g. FL. |
jurisdiction | Restrict to one jurisdiction id. |
limit | Max rows to return (newest first). |
Request
curl "https://rulegrid.dev/v1/changes?since=2026-06-01&state=FL&limit=50" \
-H "x-api-key: rgk_live_..."
Response · 200
{
"count": 1,
"changes": [
{
"change_id": 4182,
"jurisdiction_id": "us-fl-miami-dade",
"detected_at": "2026-06-14T07:12:00Z",
"field_path": "taxes[county:Tourist Development Tax].rate_pct",
"old_value": "5.0",
"new_value": "6.0",
"source_url": "https://www.miamidade.gov/...",
"summary": "Miami-Dade Tourist Development Tax increased from 5% to 6%.",
"schema_version": "1.0"
}
]
}
GET /v1/health public · unmetered · no key
Dataset health. Requires no key and does not count against any quota — safe for uptime checks.
Request
curl "https://rulegrid.dev/v1/health"
Response · 200
{
"status": "ok",
"jurisdictions": 31,
"sources_monitored": 85,
"oldest_last_verified": "2026-05-30",
"quarantined": 0,
"schema_version": "1.0"
}
Errors
Errors use a consistent envelope and the matching HTTP status. Never parse the message string — branch on error.code.
{
"error": {
"code": "invalid_key",
"message": "The provided API key is missing, unknown, or revoked.",
"docs": "https://rulegrid.dev/docs#errors"
}
}
| HTTP | code | Meaning |
|---|---|---|
| 400 | bad_request | Missing or malformed parameters (e.g. no address/lat+lng/jurisdiction on lookup). |
| 401 | missing_key | No API key supplied. Provide one via Authorization: Bearer <key> or the x-api-key header. |
| 403 | invalid_key | API key unknown, revoked, or not active. |
| 404 | not_found | No jurisdiction matches the requested id (or method not allowed). |
| 422 | geocode_failed | The address could not be resolved to a US jurisdiction. |
| 429 | quota_exceeded | Monthly quota reached (non-API plans). See the Retry-After header for the reset time. |
| 500 | internal_error | Unexpected server error. Safe to retry with backoff. |
Accuracy & terms
RuleGrid is an informational summary of publicly available sources — not legal advice,
and no professional-advice relationship is created by using it. Every record links the official
sources it was compiled from and carries a last-verified date; always verify against those sources
before acting. Data is provided without warranty; where a record cannot be validated it is served
with a stale or needs_review status rather than silently changed. Do not
treat the API as a system of record for legal compliance. Full API Terms of Service govern use and
cap liability at fees paid.