API Migration Guide

Migrate from the legacy KLISS API (v1 through v13 at /li/api/vN/) to the new API at /api/v1/. If you're seeing a Deprecation header on your API responses, you're in the right place.

Timeline

PhasePeriodWhat happens
ParallelNow – Aug 1, 2026Both APIs run side-by-side. Migrate at your own pace.
RedirectsAug 1 – Nov 1, 2026Legacy endpoints return 301 redirects where a 1:1 mapping exists.
SunsetAfter Nov 1, 2026Legacy endpoints return 410 Gone. The new API is the only option.

The five things that changed

#Legacy (v1–v13)New (v1)
1No authenticationOptional API key for higher rate limit (Authorization: Api-Key <key>)
2No rate limit30 req/min without key; 300 req/min with key
3Base URL: http://kslegislature.org/li/api/vN/Base URL: https://kslegislature.gov/api/v1/
4Pagination via next link (often "disabled")?limit=N&offset=N query parameters
5Biennium baked into URL path (/rev-1/)?biennium=b2025_26 query parameter (defaults to current)
Discoverability: the new API ships a machine-readable OpenAPI 3 schema plus interactive UIs at Swagger UI and Redoc. Use openapi-generator (or your language's equivalent) to autogenerate a typed SDK instead of hand-rolling HTTP calls — much faster than the legacy API's "read the example, hope the shape holds" workflow.

1. Getting an API key

The new API works without a key (throttled to 30 requests/minute). An API key raises this to 300 requests/minute.

  1. Visit /api/request-key/.
  2. Fill out: name, email, organization, and how you plan to use the API.
  3. Wait for approval — typically one business day.
  4. You'll receive the key by email with usage instructions.

Include it as an HTTP header on every request:

Authorization: Api-Key <your-key>

cURL example:

curl -H 'Authorization: Api-Key abc123...' \
     https://kslegislature.gov/api/v1/bill_status/HB2001/

Python example:

import requests

headers = {'Authorization': 'Api-Key abc123...'}
r = requests.get('https://kslegislature.gov/api/v1/bill_status/HB2001/',
                 headers=headers)
data = r.json()

2. The easy path: bill_status drop-in

If your code uses bill_status/ (any version), the new API has a purpose-built replacement that matches the v13 response shape. For many consumers this is a two-line change:

- url = 'http://kslegislature.org/li/api/v13/rev-1/bill_status/HB2001/'
- r = requests.get(url)
+ url = 'https://kslegislature.gov/api/v1/bill_status/HB2001/'
+ r = requests.get(url, headers={'Authorization': 'Api-Key <key>'})

The response carries the same fields: BILLNO, SHORTTITLE, LONGTITLE, SPONSOR_NAMES, STATUS, HISTORY (with action_code, chamber, journal_page_number, occurred_datetime, status, committee_names, amendment_report), and versions.

Note: The wrapper key is results (not content) for consistency with all other endpoints. No /rev-1/ prefix — the new API does not use revision numbers. It always returns current data; use ?biennium= for historical sessions.
Legacy path note: Versions 5 through 13 of the legacy API require /rev-1/ between the version number and the endpoint path (e.g., /li/api/v13/rev-1/bill_status/). Versions 1–4 do not use this segment. The new API has no revision concept at all.

3. Endpoint mapping (all resources)

Legacy pathNew path
/li/api/v1-v4/bill_status//api/v1/bill_status/
/li/api/v5-v13/rev-1/bill_status//api/v1/bill_status/
/li/api/v5-v13/rev-1/bill_status/<bill_no>//api/v1/bill_status/<bill_no>/
/li/api/v5+/rev-1/bill_listing//api/v1/measures/
/li/api/v5+/rev-1/calendar//api/v1/daily-calendars/
/li/api/v5+/rev-1/calendar/house//api/v1/daily-calendars/?chamber=house
/li/api/v5+/rev-1/calendar/senate//api/v1/daily-calendars/?chamber=senate
/li/api/v5+/rev-1/journal//api/v1/daily-journals/
/li/api/v5+/rev-1/journal/house//api/v1/daily-journals/?chamber=house
/li/api/v5+/rev-1/journal/senate//api/v1/daily-journals/?chamber=senate
/li/api/v5+/rev-1/ctte//api/v1/committees/
/li/api/v5+/rev-1/ctte/<kpid>//api/v1/committees/<kpid>/
/li/api/v6+/rev-1/members//api/v1/legislators/
/li/api/v6+/rev-1/members/house//api/v1/legislators/?chamber=house
/li/api/v6+/rev-1/members/senate//api/v1/legislators/?chamber=senate
/li/api/v6+/rev-1/members/<kpid>//api/v1/legislators/<kpid>/
/li/api/v6+/rev-1/chamber_status//api/v1/chamber_status/
/li/api/v7+/rev-1/appt//api/v1/appointments/
/li/api/v7+/rev-1/appt/<apptno>//api/v1/appointments/<apptno>/
/li/api/v8+/rev-1/events//api/v1/events/
(new)/api/v1/leadership/
(new)/api/v1/session-days/
(new)/api/v1/votes/ — roll-call votes with tallies and the originating journal entry; detail endpoint returns per-member yea/nay/absent
(new)/api/v1/testimony/ — submitted committee testimony with position (proponent/opponent/neutral) and download URLs
(new)/api/v1/fiscal-notes/, /api/v1/supplemental-notes/ — published notes by bill
(new)/api/v1/conference-committees/ — conference committee meeting schedule with bill assignments
(new)/api/v1/hearings/, /api/v1/hearings/<slug>/ — committee hearings list + detail (stream URL, bills, testimony, minutes)
(new)/api/v1/subjects/ — legislative subject index (list, by-topic, by-bill)
(new)/api/v1/governor-actions/ — bills classified by gubernatorial outcome (signed, vetoed, override, etc.); active + archive biennia
(new)/api/v1/statutes/, /api/v1/statutes/<section>/, /api/v1/statutes/<section>/affected-by/ — K.S.A. browse and bill-to-statute cross-reference
(new)/api/v1/measures/<bill>/statutes-affected/, /api/v1/measures/<bill>/text/ — statutes a bill amends; plain-text bill body
(new)/api/v1/legislators/<kpid>/sponsorships/, /api/v1/legislators/<kpid>/voting-record/ — per-legislator rollups
(new)/api/v1/search/ — full-text search across bills, statutes, and committee documents
(new)/api/v1/now/ — live activity snapshot for ticker-style polling (30–60s cadence)
(new)/api/v1/biennia/ — list of biennia served by this site (use to drive ?biennium= rather than hard-coding)

4. Response format changes

Legacy v1 through v4

Responses were bare JSON arrays or objects. The new API always wraps content with metadata:

{
  "count": 1480,
  "next": "https://kslegislature.gov/api/v1/measures/?limit=100&offset=100",
  "previous": null,
  "results": [ ... ]
}

Field name changes (v4 → v5+)

v5 of the legacy API renamed several keys. If your code still uses v1–v4 field names, update to the v5+ spelling (preserved in the new API):

Old (v1–v4)New (v5+, kept in new API)
bill_numberBILLNO
long_titleLONGTITLE
short_titleSHORTTITLE
sponsor_namesSPONSOR_NAMES
historyHISTORY
rs_numberRELATEDRS
status (bill-level)STATUS

5. Pagination

The legacy API used a next link that was often set to "disabled". The new API uses standard limit/offset pagination:

GET /api/v1/measures/?limit=100&offset=0

Loop until next is null to fetch all records:

def fetch_all(url, headers):
    results = []
    while url:
        r = requests.get(url, headers=headers)
        data = r.json()
        results.extend(data['results'])
        url = data['next']
    return results

6. Biennium scoping

Legacy URLs encoded the biennium in the path (/li_2022/). The new API uses a query parameter that defaults to the current active biennium:

/api/v1/bill_status/                      # current biennium
/api/v1/bill_status/?biennium=b2023_24   # historical biennium
/api/v1/measures/?biennium=b2023_24      # works on every endpoint

7. RSS & Atom feeds

RSS feeds moved from /li/feeds/rss/ to /feeds/rss/. No authentication required.

Legacy pathNew path
/li/feeds/rss/events//feeds/rss/events/
/li/feeds/rss/journal//feeds/rss/journal/
/li/feeds/rss/calendar//feeds/rss/calendar/
/li/feeds/rss/ctte/<kpid>//feeds/rss/ctte/<kpid>/
/li/feeds/rss/members/<kpid>//feeds/rss/members/<kpid>/
/li/feeds/rss/bills//feeds/rss/bills/
(new)/feeds/rss/measure/HB2001/

Atom equivalents: replace /rss/ with /atom/ in any URL above. See /feeds/rsshelp/ for a full list with subscribe links.

8. Errors you may encounter

HTTP codeMeaningFix
401Invalid API keyCheck Authorization header; must start with Api-Key
403Key deactivatedContact us to reactivate
404Resource not found or wrong bienniumDouble-check the ID; try ?biennium=b2023_24 for older records
429Rate limit exceededBack off; honor the Retry-After header

9. Deprecation headers on legacy responses

Every legacy API response now carries these headers:

Deprecation: true
Sunset: Sat, 01 Aug 2026 00:00:00 GMT
Link: <https://kslegislature.gov/api/docs/>; rel="successor-version",
      <https://kslegislature.gov/api/docs/migration/>; rel="help"

If your HTTP client can log response headers, you can confirm you're still hitting the legacy API.

10. Getting help

If your use case isn't covered or you hit a bug during migration:

  • Email [email protected]
  • Reference your API key label (first 12 characters) when reporting issues
  • Include the exact URL you called and the response body you received