Policy Eagle
Developers

API reference

Base URL https://www.policyeagle.org/api/v1. The machine-readable contract is at /api/v1/openapi.json (OpenAPI 3.1; no key needed).

Authentication

Send your key in the Authorization header on every request. Keys in query strings are not accepted.

Authorization: Bearer $POLICY_EAGLE_API_KEY

To rotate a key, choose Create replacement in your account: the old key keeps working for 24 hours. Revoking a key stops it immediately. If a key leaks, revoke it; when you contact us, send the request_id, never the key.

Responses and pagination

Successful responses are { "data": …, "meta": { "request_id": … } }. Lists return meta.next_cursor; pass it back as cursor with the same filters to get the next page. It is null on the last page. A cursor used with different filters is rejected. Bill ids are permanent within their session, but the order of results can change when the data refreshes.

Errors

{ "error": { "code": "INVALID_REQUEST", "message": "Some parameters are invalid.",
             "details": [{ "field": "sort", "message": "…" }] },
  "meta": { "request_id": "req_…" } }
StatusCodeMeaning
400INVALID_REQUESTA parameter is missing or invalid. Unknown codes, categories and sort values are errors, not ignored.
401UNAUTHORIZEDNo key, or the key is wrong, expired or revoked.
403FORBIDDENThe key can't read this data.
404NOT_FOUNDNo such session, or no bill with that id in that session.
429RATE_LIMITEDToo many requests. Wait for Retry-After seconds.
503UNAVAILABLEA service we depend on is unavailable or busy, often during a data refresh. Retry with backoff.

Rate limits

Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds) for your tightest window, plus X-Request-Id. Limits are shared by all your keys; GET /me shows both windows.

Endpoints

Check your key

GET /me

Returns the key's label, scope and current rate-limit windows. Counts against your limits like any request.

Errors: 401, 429, 503

List sessions

GET /sessions

Published Florida sessions, newest first. `is_current` marks the session the website shows by default.

Errors: 401, 429, 503

Search bills

GET /bills

A page of bills in one session. Filters combine with AND; values inside `progress` or `categories` match any. Unknown codes, slugs and sort values are rejected rather than ignored.

ParameterTypeDescription
session_id (required)integer
chamberH | SHouse or Senate; omit for both.
bill_numberstring`HB 123`, `S0045` or `123`. A chamber letter also filters the chamber.
textstringCase-insensitive match on the title.
stagefiled | committee | floor | governor | law | vetoed | replaced | died`filed`: Filed (10); `committee`: In committee (20); `floor`: On the floor (30, 40, 50); `governor`: Governor's desk (60); `law`: Became law (70, 80); `vetoed`: Vetoed (92); `replaced`: Replaced by companion (93); `died`: Died (90, 91). Not combinable with `progress`.
progressstringComma-separated progress codes: 10 Filed, 20 In committee, 30 2nd reading, 40 3rd reading, 50 Passed Legislature, 60 Governor, 70 Became law, 80 Adopted, 90 Died, 91 Withdrawn, 92 Vetoed, 93 Replaced by companion.
categoriesstringComma-separated category slugs.
movedbooleanOnly bills with an action in the last 7 days (UTC, inclusive). Past sessions usually return none.
sortlatest | number`latest`: newest action first. `number`: House then Senate, by number.
limitinteger, default 20, max 50
cursorstring`next_cursor` from the previous page, with the same filters.

Errors: 400, 401, 404, 429, 503

Get a bill

GET /bills/{session_id}/{bill_id}

ParameterTypeDescription
session_id (required)integerFrom GET /sessions.
bill_id (required)integerPermanent numeric id from GET /bills. Always paired with its session.

Errors: 400, 401, 404, 429, 503

List a bill's actions

GET /bills/{session_id}/{bill_id}/actions

The bill's history, oldest first.

ParameterTypeDescription
session_id (required)integerFrom GET /sessions.
bill_id (required)integerPermanent numeric id from GET /bills. Always paired with its session.
limitinteger, default 100, max 200
cursorstring`next_cursor` from the previous page, with the same filters.

Errors: 400, 401, 404, 429, 503