Rate Limits
Per-tier monthly quotas, per-minute rate limits, response headers, and the 429 envelope.
Florida Business API enforces two limits on every /api/v1/* request:
- Monthly quota — total requests allowed per calendar month, by plan.
- Per-minute rate limit (RPM) — a sliding-window burst limit, also by plan.
Whichever you hit first returns 429 rate_limited with a Retry-After header. Both buckets are backed by Upstash Redis with a 1-second timeout that fails open (we'd rather under-bill than 5xx your job).
Florida Business API is an independent data platform and is not affiliated with Sunbiz.org, the Florida Department of State, or the Florida Division of Corporations.
Tiers
| Plan | Monthly Quota (REST) | Monthly MCP Calls | RPM (burst) | REST | MCP | Webhooks |
|---|---|---|---|---|---|---|
| MCP Starter ($5/mo) | — | 1,000 | 30 | — | ✓ | — |
| Free | 1,000 | 0 | 30 | ✓ | — | — |
| Developer | 10,000 | 10,000 | 120 | ✓ | ✓ | — |
| Pro | 100,000 | 100,000 | 300 | ✓ | ✓ | ✓ |
| Growth | 500,000 | 100,000 | 600 | ✓ | ✓ | ✓ |
| Lead Feed | 1,000,000 | 250,000 | 1,200 | ✓ | ✓ | ✓ |
| Enterprise | "Unlimited" (2B cap) | "Unlimited" (2B) | 10,000 | ✓ | ✓ | ✓ |
The MCP Starter tier intentionally excludes REST — REST requests on a Starter key return 403 rest_disabled (see Errors). Every other tier enables both surfaces. "Unlimited" Enterprise is modeled as a 2,000,000,000-row cap so the Postgres INT column does not overflow; in practice the limit is the contract.
Response Headers
Every /api/v1/* response (including 429) includes both the legacy de-facto headers and the IETF draft RateLimit structured field — pick whichever your HTTP client supports:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Your plan's RPM cap. |
X-RateLimit-Remaining | Requests remaining in the current 60-second window. |
X-RateLimit-Reset | Unix seconds at which the window resets. |
RateLimit | RFC 9651 structured field: "default";r=<remaining>;t=<seconds_until_reset>. |
Retry-After | Only on 429. Seconds until you may retry. |
Example success headers:
HTTP/1.1 200 OK
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1719367200
RateLimit: "default";r=117;t=42
429 Envelope
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 17
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 17
RateLimit: "default";r=0;t=17
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded. Retry after 17 seconds.",
"request_id": "req_1234567890abcdef12345"
}
}
Handling 429s
The simplest correct strategy: sleep Retry-After seconds, then retry once.
while :; do
RESP=$(curl -s -w "\n%{http_code}" \
-H "Authorization: Bearer fbapi_live_..." \
"https://api.floridabusinessapi.com/v1/entities/search?name=ACME")
CODE=$(printf '%s\n' "$RESP" | tail -n1)
BODY=$(printf '%s\n' "$RESP" | sed '$d')
[ "$CODE" = "200" ] && { echo "$BODY"; break; }
[ "$CODE" = "429" ] && { sleep "${Retry_After:-30}"; continue; }
echo "fatal: $CODE — $BODY" >&2; exit 1
done
For long-running batch jobs, use exponential backoff capped at the X-RateLimit-Reset value — you will never wait longer than the window itself.
Monthly Quota vs. RPM
- Hitting RPM returns 429 and resets within ~60 seconds. Slow down and you can finish your job today.
- Hitting monthly quota also returns 429, but
Retry-Afterwill be the seconds until your next billing cycle. Upgrade or wait — there is no in-cycle escape hatch.
Check current consumption from the Account Usage endpoint.