OpenStates provides comprehensive legislative data for all 50 states through standardized CSV files. This guide demonstrates how to access, enhance, and analyze this data using New Mexico as an example.

Data

Create an account. Download data locally.

Viz file structure schema details

File structure

NM_2025_csv_3LAtJwe7Zs1ldDHVVcwMRa/
├── README
└── NM/
    └── 2025/
        ├── NM_2025_bill_actions.csv
        ├── NM_2025_bill_document_links.csv
        ├── NM_2025_bill_documents.csv
        ├── NM_2025_bill_sources.csv
        ├── NM_2025_bill_sponsorships.csv
        ├── NM_2025_bill_version_links.csv
        ├── NM_2025_bill_versions.csv
        ├── NM_2025_bills.csv
        ├── NM_2025_organizations.csv
        ├── NM_2025_vote_counts.csv
        ├── NM_2025_vote_people.csv
        ├── NM_2025_vote_sources.csv
        └── NM_2025_votes.csv

Table Structure

1. organizations

Purpose: Legislative bodies, committees, and other organizations

Field Description
id Unique identifier (OCD format)
name Organization name
classification Type (legislature, executive, committee, etc.)
parent_id Self-referencing for hierarchical structure
jurisdiction_id Associated jurisdiction

2. bills

Purpose: Main legislative bills with metadata

Field Description
id Unique identifier (OCD format)
identifier Bill number (e.g., ‘HB 267’)
title Bill title
classification Bill type (bill, memorial, resolution, etc.)
subject Array of subject categories
session_identifier Legislative session (e.g., 2025)
jurisdiction State (New Mexico)

3. bill_actions

Purpose: Track bill progress through legislative process

Field Description
id Unique identifier
bill_id Reference to bills table
organization_id Organization taking action
description Action description
date Action date
classification Action type (introduction, referral, passage, etc.)
order Chronological order

4. bill_sponsorships

Purpose: Sponsors and co-sponsors of bills

Field Description
id Unique identifier
name Sponsor name
entity_type Person or organization
person_id Identifier for person (nullable)
organization_id Reference to organization
bill_id Reference to bills table
primary Boolean for primary sponsor

5. bill_versions

Purpose: Different versions of bills throughout the process

Field Description
id Unique identifier
bill_id Reference to bills table
note Version description
date Version date
classification Version type

6. bill_documents

Purpose: Documents related to bills

Field Description
id Unique identifier
bill_id Reference to bills table
note Document description
date Document date
classification Document type

7. bill_sources

Purpose: Source URLs for bill information

Field Description
id Unique identifier
bill_id Reference to bills table
url Source URL
note Description

10. votes

Purpose: Vote events on bills

Field Description
id Unique identifier (OCD format)
identifier Vote identifier
motion_text Motion description
motion_classification Vote type
start_date Vote date
result Vote outcome (pass, fail, etc.)
organization_id Voting body
bill_id Associated bill
jurisdiction State
session_identifier Session

11. vote_counts

Purpose: Aggregate vote counts by option

Field Description
id Unique identifier
vote_event_id Reference to votes table
option Vote option (yes, no, abstain, etc.)
value Count of votes

12. vote_people

Purpose: Individual vote records

Field Description
id Unique identifier
vote_event_id Reference to votes table
option Individual’s vote
voter_name Voter’s name
voter_id Voter’s unique identifier (nullable)

13. vote_sources

Purpose: Source URLs for vote information

Field Description
id Unique identifier
vote_event_id Reference to votes table
url Source URL
note Description

Key Relationships

Primary Relationships

  1. billsbill_actions (one-to-many)
  2. billsbill_sponsorships (one-to-many)
  3. billsbill_versions (one-to-many)
  4. billsbill_documents (one-to-many)
  5. billsvotes (one-to-many)
  6. organizationsbills (one-to-many via sponsorships)
  7. votesvote_people (one-to-many)
  8. votesvote_counts (one-to-many)

Legislators

Per a given congress, or year, OS folks generate a legislators file …

Romero, GA == Representative G. Andrés Romero - (D) · District: 10 – ocd-person/5cf6976d-e616-4579-a194-ec3c37260ebd

Romero, A. == Representative Andrea Romero - (D). Romero. District: 46 – ocd-person/ed0ba54a-4fc3-4c50-aa0d-f74b1f0e86f6

Garcia, M. == Representative Martha Garcia - (D) · District: 6 – ocd-person/fb0443f9-b6d7-4b3b-a87e-0d8b143ed64b

García, MP == Representative Miguel P. García - (D) · District: 14 – ocd-person/3363aa83-2490-4631-b04b-9a52fdbad14b

LOPEZ and MUNOZ in the Senate – all caps + daicritics – ?? –

LOPEZ == ocd-person/ecc60fc8-8598-4650-8a55-6e91d24e991e MUNOZ == ocd-person/b4c20aea-b56c-4a19-a89a-788c53d995d7

2. legislators

Purpose: Individual legislators with personal and contact information Key Fields: - id: Unique identifier (OCD format) - name: Full name of legislator - current_party: Political party affiliation - current_district: Legislative district number - current_chamber: Chamber (upper/lower) - given_name: First name - family_name: Last name - gender: Gender identification - email: Contact email address - biography: Legislative biography - birth_date: Date of birth - death_date: Date of death (if applicable) - image: URL to official photo - links: URLs to legislator pages - sources: Source URLs for information - capitol_address: Capitol office address - capitol_voice: Capitol office phone - capitol_fax: Capitol office fax - district_address: District office address - district_voice: District office phone - district_fax: District office fax - twitter: Twitter handle - youtube: YouTube handle - instagram: Instagram handle - facebook: Facebook handle - wikidata: Wikidata identifier

Committee Membership

Committee membership information is not made available in csv – instead, this info is maintained on GitHub… collated here.

library(dplyr)
library(httr)
library(yaml)

# Step 1: Use GitHub API to get file list
api_url <- "https://api.github.com/repos/openstates/people/contents/data/nm/committees"
res <- GET(api_url)
stop_for_status(res)

# Step 2: Extract raw download URLs
files <- content(res)
yaml_urls <- vapply(files, function(x) x$download_url, character(1))

# Step 3: Read YAML content into R
yaml_objects <- lapply(yaml_urls, function(url) {
  r <- GET(url)
  stop_for_status(r)
  txt <- content(r, as = "text", encoding = "UTF-8")
  yaml::yaml.load(txt)
})
library(data.table)

# Example: extract from one record
extract_committee_members <- function(x) {
  if (!length(x$members)) return(NULL)
  
  data.table(
    committee_id = x$id,
    committee_name = x$name,
    committee_classification = x$classification,
    chamber = x$chamber,
    member_name = vapply(x$members, function(m) m$name, character(1)),
    member_role = vapply(x$members, function(m) m$role, character(1)),
    person_id = vapply(x$members, function(m) m$person_id, character(1))
  )
}

# Apply across all objects
dt_members <- rbindlist(
  lapply(yaml_objects, extract_committee_members),
  use.names = TRUE,
  fill = TRUE
)
dt_members |> 
  DT::datatable(
    rownames = FALSE,
    options = list(
      scrollX = TRUE,
      autoWidth = TRUE,
      columnDefs = list(list(width = "100%", targets = "_all"))
    ),
    width = "100%"
  )
your_project/
├── openstates_data/
│   ├── NM_2025_bills.csv
│   ├── NM_2025_votes.csv
│   └── [other CSV files]
├── committee_data.csv