Colorado General Assembly Legislative Data API (v1 (draft))

Download OpenAPI specification:

DRAFT. Read-only JSON access to Colorado legislative data: bills, committees, legislators, calendars, ballot measures and initiatives. This is the same data that feeds the Colorado General Assembly website, delivered as a stable, structured API so that you do not need to scrape web pages.

This documentation was written from observed API behavior. Field meanings are as observed, not from an official data dictionary.

Getting started

  1. Get an API key. Keys are issued by Legislative Council Staff (LCS). Each key belongs to one organization and is assigned a usage tier.
  2. Send it in a header on every request: x-api-key: <your key>.
  3. Call an endpoint, for example:
curl -H "x-api-key: $API_KEY" \
  "https://api.coleg.gov/v1/bills/lm/2026-09-01T00:00:00Z/all"

Everything is GET. There are no write operations.

Efficient polling: use the "changed since" endpoints

Most data types offer a lm ("last modified") endpoint that returns only the IDs of records changed since a timestamp. Poll these instead of re-downloading everything, then fetch the full record only for IDs that changed.

Endpoint pattern Returns
/{entity}/lm/{since}/all or /{entity}/lm/{since}/{sessionId} IDs changed since {since}
/{entity}/{id} The full record for one ID

{since} is an ISO 8601 UTC timestamp such as 2026-09-01T00:00:00Z, or 0 for "everything". Store the time you last checked and pass it on the next poll. Schedules have no lm endpoint; fetch the current schedule directly.

Suggested cadence during session: calendar every 15 minutes, bills every 30 minutes, legislators and committees hourly, documents nightly. Outside session, far less often.

Freshness

Responses in Production are cached at the gateway for up to the times below, so polling more often than this returns the same data and only uses your quota.

Data Maximum cache age
Legislators / directory 6 hours
Committee info, ballots, initiatives, past committee meetings 24 hours
Bills, committee meeting lists 60 minutes
Schedules (calendars) 10 minutes

The lm "changed since" lists are effectively not cached, because each caller's timestamp differs.

Rate limits

Limits apply per API key according to the key's usage tier, and are set when your key is issued. A request over your limit returns HTTP 429 and never reaches the data source. Back off and retry.

Errors

You can receive three different kinds of failure. Check the error.source field to tell them apart.

What you see Meaning
JSON with "error": {"source": "gateway", ...} Rejected by the gateway before reaching the data: missing or invalid key (403), over your limit (429), unknown path (403 MISSING_AUTHENTICATION_TOKEN), or a gateway timeout (504)
JSON with "error": {"source": "cloudflare", ...} The data source rejected or failed the request (403 or 502)
HTTP 200 with an error inside the body The data source hit an internal problem but still answered 200. Treat a 200 whose body contains a top-level error string as a failure. An unknown ID returns {}

Always log the requestId from an error. LCS can use it when you report a problem.

Data notes

  • Dates are strings in MM/DD/YYYY form; timestamps look like 03/26/2026 09:36:14 AM. Times of day are not captured for bill history entries, so several actions on one day have no reliable order.
  • Flags such as active use "T" and "F" strings.
  • Some fields vary in type. session_laws_files is an empty string "" when there is none and an object when there is; schedule order can be a number or a string. Handle both.
  • Official links. Document URLs point to official leg.state.co.us pages. Please preserve them and attribute the source.
  • Not available: stable source IDs for bills, and cancellation or postponement status for hearings.

Environments

Base URL Notes
Production https://api.coleg.gov/v1 Live data
Test https://<api-id>.execute-api.us-west-2.amazonaws.com/test, provided with your test key For integration testing. Use the same paths as Production after the base URL (there is no /v1 segment in the Test URL). Data is test data and may differ or change without notice. Keys are issued separately for each environment

Bills

Bills, resolutions and memorials, with sponsors, history, votes and documents in one record.

Bills changed since a time (all sessions)

Returns the bill numbers modified since {since}. Fetch each with GET /bills/{billNumber}.

Authorizations:
ApiKey
path Parameters
since
required
string
Example: 2026-09-01T00:00:00Z

A UTC timestamp such as 2026-09-01T00:00:00Z, or 0 for everything.

Responses

Response samples

Content type
application/json
[
  • "HB26-1178",
  • "SB26-086",
  • "SB26-001"
]

Bills changed since a time, for one session

Same as above, limited to one session. Use 0 for {since} to list every bill in the session.

Authorizations:
ApiKey
path Parameters
since
required
string
Example: 2026-09-01T00:00:00Z

A UTC timestamp such as 2026-09-01T00:00:00Z, or 0 for everything.

sessionId
required
string
Example: 2026A

A session such as 2026A.

Responses

Response samples

Content type
application/json
[
  • "string"
]

One bill, with sponsors, history, votes and documents

The complete record for one bill. This single response carries almost everything most consumers need: status, sponsors, committee assignments, history, votes and every document group.

Status is bill_status plus summarized_history. progress_bar shows lifecycle position: when the last step's end is "T" the bill has concluded, and active is "F".

An unknown bill number returns {} with HTTP 200.

Authorizations:
ApiKey
path Parameters
billNumber
required
string
Example: HB26-1178

A bill number such as HB26-1178, SB26-086, HR26-1001 or SM26-001.

Responses

Response samples

Content type
application/json
{
  • "bill_num": "HB26-1178",
  • "lls_num": "26-0264",
  • "origin": "House",
  • "short_title": "string",
  • "full_bill_topic": "string",
  • "long_title": "string",
  • "special_type": "string",
  • "bill_category": "string",
  • "bill_sub_category": "string",
  • "bill_sub_sub_category": "string",
  • "is_budget_package": "Yes",
  • "subject": [
    ],
  • "bill_status": "Signed into Law",
  • "sponsors": [
    ],
  • "committees": [
    ],
  • "first_chamber_third_reading_date": "string",
  • "second_chamber_third_reading_date": "string",
  • "summarized_history": [
    ],
  • "progress_bar": [
    ],
  • "active": "T",
  • "session": "2026A",
  • "allow_testimony": "T",
  • "long_bill_files": [
    ],
  • "bill_files": [
    ],
  • "fiscal_note_files": [
    ],
  • "research_note_files": [
    ],
  • "budget_staff_analysis_files": [
    ],
  • "preamended_files": [
    ],
  • "committee_report_files": [
    ],
  • "updated_bill_summary_files": [
    ],
  • "demographic_note_files": [
    ],
  • "GHG_report_files": [
    ],
  • "amendment_files": [
    ],
  • "bill_summary": "string",
  • "session_laws_files": "",
  • "votes": [
    ]
}

Committees

Committee information and committee meeting summaries.

Committees changed since a time

Authorizations:
ApiKey
path Parameters
since
required
string
Example: 2026-09-01T00:00:00Z

A UTC timestamp such as 2026-09-01T00:00:00Z, or 0 for everything.

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Committees changed since a time, for one session

Authorizations:
ApiKey
path Parameters
since
required
string
Example: 2026-09-01T00:00:00Z

A UTC timestamp such as 2026-09-01T00:00:00Z, or 0 for everything.

sessionId
required
string
Example: 2026A

A session such as 2026A.

Responses

Response samples

Content type
application/json
[
  • {
    }
]

One committee, with members and meeting times

Authorizations:
ApiKey
path Parameters
committeeId
required
string
Example: S_TRA_2026A

A committee ID from the list endpoints. The format is {H|S|J|I|O}_{ABBREV}_{session}.

Responses

Response samples

Content type
application/json
{
  • "committee_id_session": "S_TRA_2026A",
  • "generic_id": "S_TRA",
  • "committee_type": "Committee of Reference",
  • "committee_name": "string",
  • "chamber": "string",
  • "committee_abbrev": "string",
  • "display_member_page": "string",
  • "committee_staff": [
    ],
  • "committee_staff_email": "string",
  • "committee_session": "string",
  • "committee_meetings": [
    ],
  • "alternate_meeting_day_language": "string",
  • "committee_members": [
    ],
  • "committee_description": "string",
  • "committee_subject": [
    ],
  • "twitter_handle": "string",
  • "granicus_id": 0,
  • "sliq_id": 0
}

Committee meetings changed since a time

Returns one entry per committee that has meetings, listing every meeting date and its meeting ID as parallel arrays. The committee names here come from a broader set than /committees/info; they include conference committees keyed by bill number.

Authorizations:
ApiKey
path Parameters
since
required
string
Example: 2026-09-01T00:00:00Z

A UTC timestamp such as 2026-09-01T00:00:00Z, or 0 for everything.

Responses

Response samples

Content type
application/json
[
  • {
    }
]

One committee meeting, with attendance, actions and votes

The full summary of a single meeting, including per-member votes with member IDs.

Authorizations:
ApiKey
path Parameters
meetingUid
required
string
Example: CC_HB26-1084_2026A_20260429_080744

A meeting ID from meeting_uids in the meeting list.

Responses

Response samples

Content type
application/json
{
  • "meeting_summary_url": "http://example.com",
  • "meeting_date": "04/29/2026",
  • "meeting_time": "08:07:44 AM",
  • "committee_id": [
    ],
  • "meeting_uid": "string",
  • "meeting_room": "string",
  • "event_url": "http://example.com",
  • "members": [
    ],
  • "committee_actions": [
    ],
  • "attachments": [
    ],
  • "bill_summaries": [
    ]
}

One committee meeting, by committee and meeting time

Returns the same record as /committees/summary/mId/{meetingUid}, addressed by committee and meeting time.

Authorizations:
ApiKey
path Parameters
committeeId
required
string
Example: CC_HB26-1084_2026A
meetingDateTime
required
string
Example: 2026-04-29T08:07:44Z

The meeting time from meeting_dates, ISO 8601 UTC.

Responses

Response samples

Content type
application/json
{
  • "meeting_summary_url": "http://example.com",
  • "meeting_date": "04/29/2026",
  • "meeting_time": "08:07:44 AM",
  • "committee_id": [
    ],
  • "meeting_uid": "string",
  • "meeting_room": "string",
  • "event_url": "http://example.com",
  • "members": [
    ],
  • "committee_actions": [
    ],
  • "attachments": [
    ],
  • "bill_summaries": [
    ]
}

Legislators

The legislator directory, current and historical.

The current legislator roster

Every current legislator with full detail in one response, including party (affiliation), district, chamber and leadership title (special_position). This is the easiest way to join a legislator ID from a bill's sponsors to a party and district: fetch it once and cache it.

Authorizations:
ApiKey

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Legislators changed since a time

Use 0 for {since} to list every legislator back to 2016.

Authorizations:
ApiKey
path Parameters
since
required
string
Example: 2026-09-01T00:00:00Z

A UTC timestamp such as 2026-09-01T00:00:00Z, or 0 for everything.

Responses

Response samples

Content type
application/json
[
  • {
    }
]

One legislator, with session history

Full details for the current or most recent session, plus all_sessions with the legislator's history across sessions.

Authorizations:
ApiKey
path Parameters
memberId
required
string
Example: LG005

Responses

Response samples

Content type
application/json
{
  • "member_id": "LG005",
  • "prefix": "string",
  • "suffix": "string",
  • "first_name": "string",
  • "middle_name": "string",
  • "last_name": "string",
  • "name_line": "string",
  • "display_name1": "string",
  • "display_name2": "string",
  • "special_position": "string",
  • "special_position_order": "string",
  • "affiliation": "Democrat",
  • "occupation": "string",
  • "chamber": "House",
  • "district": "string",
  • "counties": [
    ],
  • "phone": "string",
  • "email": "string",
  • "website": "string",
  • "photo_url": "http://example.com",
  • "session": "2026A",
  • "organisation_name": "string",
  • "administrative_area": "string",
  • "locality": "string",
  • "postal_code": "string",
  • "thoroughfare": "string",
  • "premise": "string",
  • "country": "string",
  • "all_sessions": [
    ]
}

Schedules

Published floor and committee calendars, plus journal and status-sheet documents.

A published calendar, or the journal / status-sheet document link

There is no changed-since endpoint for schedules; fetch them directly.

type = floor or committee returns the most recently published calendar for the chamber, with events. events can legitimately be empty (for example, no floor session scheduled). In an event's e_details, bill_or_text is "B" when hearing_item is a bill number and "T" when it is free text. Cancellation and postponement status is not provided.

type = journal or ss returns a link to a single PDF instead of events. journal is the cumulative journal for the current session; ss is the status sheet. The response is an array of DocumentLink, not a Calendar.

Authorizations:
ApiKey
path Parameters
chamber
required
string
Enum: "house" "senate"
type
required
string
Enum: "floor" "committee" "journal" "ss"

Responses

Response samples

Content type
application/json
Example
{
  • "calendar_pdf": "http://example.com",
  • "calendar_html": "http://example.com",
  • "publish_date_time": "8/5/2026 1:21:26 PM",
  • "calendar_date_time": "string",
  • "events": [
    ]
}

Ballot measures

Measures that have qualified for, or are being tracked toward, the ballot.

Every ballot measure, with full detail

Authorizations:
ApiKey

Responses

Response samples

Content type
application/json
{
  • "Ballots": [
    ]
}

Ballot measures changed since a time

Authorizations:
ApiKey
path Parameters
since
required
string
Example: 2026-09-01T00:00:00Z

A UTC timestamp such as 2026-09-01T00:00:00Z, or 0 for everything.

Responses

Response samples

Content type
application/json
[
  • "string"
]

One ballot measure

Authorizations:
ApiKey
path Parameters
key
required
string
Example: 2026-Initiative_195

A key from the list endpoints: {year}-{Initiative|Proposition|Amendment}_{number-or-letter}.

Responses

Response samples

Content type
application/json
{
  • "ballot_status": "Ballot Analysis Active",
  • "key": "2026-Initiative_195",
  • "old_key": "string",
  • "ballot_reference": "Initiative 195",
  • "ballot_title": "string",
  • "ballot_type": "Statutory",
  • "election_cycle": "2025-2026",
  • "election_year": "string",
  • "email": "string",
  • "research_staff": [
    ],
  • "fiscal_analyst": "string",
  • "ballot_files": [
    ]
}

Initiatives

Petition-stage initiatives, earlier in the process than ballot measures.

Every initiative, with full detail

Authorizations:
ApiKey

Responses

Response samples

Content type
application/json
{
  • "initiatives": [
    ]
}

Initiatives changed since a time

Authorizations:
ApiKey
path Parameters
since
required
string
Example: 2026-09-01T00:00:00Z

A UTC timestamp such as 2026-09-01T00:00:00Z, or 0 for everything.

Responses

Response samples

Content type
application/json
[
  • "string"
]

One initiative

Initiatives and ballot measures track the same underlying measures at different stages (for example 2026-195 here and 2026-Initiative_195 under ballot measures). To follow a measure through its lifecycle, query both and match on year and number.

Authorizations:
ApiKey
path Parameters
key
required
string
Example: 2026-195

A key such as 2026-195 ({year}-{number}).

Responses

Response samples

Content type
application/json
{
  • "key": "2026-195",
  • "initiative_title": "string",
  • "election_cycle": "string",
  • "election_year": "string",
  • "number": "string",
  • "initiative_type": "Constitutional, Statutory",
  • "date_submitted": "12/23/2025",
  • "initiative_status": "string",
  • "initiative_status_current": "string",
  • "proponents": [
    ],
  • "initiative_files": []
}