LDA Gov

A Ruby client for the LDA.gov Lobbying Disclosure Act API. Access lobbying filings, contributions, registrants, clients, lobbyists, and reference data.

No API key required for basic access (15 req/min anonymous). Optional API key available at lda.gov/api for higher rate limits.

Installation

Add to your Gemfile:

gem 'lda_gov'

Then bundle install, or install directly:

gem install lda_gov

Quick Start

require 'lda_gov'

# Search recent lobbying filings
filings = LDA.filings.list(filing_year: 2024)
filings.each { |f| puts f['filing_uuid'] }

Usage

Filings

# List filings with filters
filings = LDA.filings.list(filing_year: 2024, filing_period: 'Q1')

# Find a specific filing
filing = LDA.filings.find('some-filing-uuid')

# Quarterly filings
LDA.filings.quarterly(year: 2024, quarter: 1)

# Filter by registrant and client
LDA.filings.by_registrant_and_client(
  registrant_name: 'Acme Lobbying',
  client_name: 'Big Corp'
)

# Filter by filing type (quarterly reports, registrations, etc.)
LDA.filings.list(filing_year: 2024, filing_type: 'Q1')

Contributions

contributions = LDA.contributions.list
contribution = LDA.contributions.find(123)

Registrants

registrants = LDA.registrants.list
registrant = LDA.registrants.find(456)

Clients

clients = LDA.clients.list
client = LDA.clients.find(789)

Lobbyists

lobbyists = LDA.lobbyists.list
lobbyist = LDA.lobbyists.find(101)

Constants (Reference Data)

LDA.constants.filing_types
LDA.constants.lobbying_issues
LDA.constants.government_entities
LDA.constants.states
LDA.constants.countries
LDA.constants.contribution_types

Pagination

Iterate page by page with each_page:

LDA.filings.each_page(filing_year: 2024) do |page|
  page.each { |filing| process(filing) }
end

Fetch all results at once:

all_filings = LDA.filings.all_filings(filing_year: 2024)
all_filings.size  # => total count

# Available on all resources
LDA.contributions.all_contributions
LDA.registrants.all_registrants
LDA.clients.all_clients
LDA.lobbyists.all_lobbyists

Configuration

LDA.configure do |config|
  config.api_key = ENV['LDA_API_KEY']       # Optional — enables higher rate limits
  config.timeout = 60                        # Request timeout in seconds (default: 30)
  config.retries   = 5                        # Max retries on 429/5xx (default: 3)
  config.max_pages = 800                      # Max pages per paginate call (default: 1000)
  config.logger    = Logger.new($stdout)      # Optional request logging
end

Rails Initializer

# config/initializers/lda_gov.rb
LDA.configure do |config|
  config.api_key = ENV['LDA_API_KEY']
  config.timeout = 30
  config.retries = 3
  config.logger  = Rails.logger if Rails.env.development?
end

Per-Instance Client

For different configurations in the same process:

client = LDA::Client.new(custom_config)
client.filings.list(filing_year: 2024)
client.contributions.list

Response Object

All API calls return an LDA::Response:

response = LDA.filings.list(filing_year: 2024)

response.results             # Array of result hashes
response.each { |r| ... }   # Enumerable — supports map, select, first, etc.
response.size                # Results on this page
response.empty?              # No results?
response.count               # Total matching records (from API envelope)
response.total_count         # Alias for count
response.next_page?          # More pages available?
response.next_page_number    # Page number from next URL
response.success?            # HTTP 2xx?

response['key']              # Direct hash access
response.dig('nested', 'key')
response.raw                 # Raw parsed JSON body
response.to_h                # Always returns a Hash
response.to_json             # JSON string

Error Handling

begin
  LDA.filings.find('INVALID')
rescue LDA::BadRequestError => e
  puts "Bad request: #{e.status} — #{e.body}"
rescue LDA::NotFoundError => e
  puts "Not found: #{e.status}"
rescue LDA::UnauthorizedError => e
  puts "Unauthorized: #{e.body}"
rescue LDA::RateLimitError
  puts 'Rate limited — retries exhausted'
rescue LDA::ServerError => e
  puts "Server error: #{e.status}"
rescue LDA::ConnectionError => e
  puts "Network issue: #{e.message}"
end

Error hierarchy:

LDA::Error

All ClientError and ServerError subclasses expose .status and .body.

API Limitations

The LDA.gov API does not support server-side filtering by lobbying issue code. Passing a lobbying_issue parameter to the filings endpoint has no effect — the API returns all filings regardless.

Supported filters (confirmed working server-side):

  • filing_year — calendar year
  • filing_type — filing type code (Q1Q4, RR, RA, 1T, 1TY, etc.)
  • filing_period — filing period (first_quarter, second_quarter, etc.)
  • registrant_name — registrant name search
  • client_name — client name search

To filter by issue code, iterate over filings and check lobbying_activities on each filing:

LDA.filings.each_page(filing_year: 2024, filing_type: 'Q1') do |page|
  page.each do |filing|
    issues = filing['lobbying_activities']&.map { |a| a['general_issue_code'] } || []
    next unless issues.include?('DEF')

    process(filing)
  end
end

Development

git clone https://github.com/xjackk/lda_gov.git
cd lda_gov
bundle install

bundle exec rspec       # Run tests
bundle exec rubocop     # Lint

Requirements

  • Ruby >= 3.1
  • Faraday ~> 2.0

Support

ko-fi

License

MIT License. See LICENSE.txt.