Skip to content

API reference

Generated from the package docstrings.

Client

CSpanClient

CSpanClient(api_key: str | None = None, *, base_url: str = BASE_URL, timeout: float = 30.0, output_format: str = 'json', max_retries: int = 3, backoff_factor: float = 0.5, session: Session | None = None)

Client for the C-SPAN Archives API. Requires an API key.

The key may be passed directly or read from the CSPAN_API_KEY environment variable. Choose an output format once (output_format) or per call (format=): "json" (default), "records", "csv", "dataframe".

The client retries transient failures (HTTP 429 and 5xx) with exponential backoff, honoring the Retry-After header.

Example

from cspan import CSpanClient client = CSpanClient() # reads CSPAN_API_KEY client.mentions("artificial intelligence", mindate="2024-01-01") client.people(last="Pelosi", format="csv") for row in client.iter_records(client.bills, query="budget"): ... ... # auto-follows the cursor

bills

bills(query: str, *, cursor: str | None = None, format: str | None = None) -> Any

GET /bills — search Congressional bill information.

Parameters:

Name Type Description Default
query str

word or phrase to search for (required).

required
cursor str | None

continuation cursor from a previous call, for pagination.

None
format str | None

output format for this call (overrides output_format).

None

mentions

mentions(query: str, *, limit: int | None = None, cursor: str | None = None, personid: int | str | None = None, date: str | None = None, maxdate: str | None = None, mindate: str | None = None, page: int | None = None, videotype: str | None = None, format: str | None = None) -> Any

GET /mentions — search C-SPAN programming for spoken words/phrases.

Parameters:

Name Type Description Default
query str

word or phrase to search for (required).

required
limit int | None

number of results to return (default 20).

None
cursor str | None

continuation cursor for pagination.

None
personid int | str | None

only results spoken by this person ID (see :meth:people).

None
date str | None

only results spoken on this date (yyyy-mm-dd).

None
maxdate str | None

only results on or before this date (yyyy-mm-dd).

None
mindate str | None

only results on or after this date (yyyy-mm-dd).

None
page int | None

page number of results (default 1).

None
videotype str | None

only results of this video type (e.g. Speech, Debate).

None
format str | None

output format for this call (overrides output_format).

None

people

people(query: str | None = None, *, first: str | None = None, last: str | None = None, cursor: str | None = None, format: str | None = None) -> Any

GET /people — search the C-SPAN database for people.

Parameters:

Name Type Description Default
query str | None

name or title to match (optional).

None
first str | None

first name to match (optional).

None
last str | None

last name to match (optional).

None
cursor str | None

continuation cursor for pagination.

None
format str | None

output format for this call (overrides output_format).

None

person

person(person_id: int | str, *, format: str | None = None) -> Any

GET /people/{personId} — fetch one person by internal or public ID.

programs_search(query: str, *, cursor: str | None = None, sort: str | None = None, format: str | None = None) -> Any

GET /programs/search — program search interface.

Parameters:

Name Type Description Default
query str

Lucene query string. Valid fields include abstract, category, date, format, isbn, location, person, personid, series, sponsor, subject, tag, text. (Note: that format is a query field inside query; the format keyword below selects this call's output format.)

required
cursor str | None

continuation cursor for pagination.

None
sort str | None

popular or date with a direction, e.g. "date desc".

None
format str | None

output format for this call (overrides output_format).

None

program

program(video_id: int | str, *, format: str | None = None) -> Any

GET /programs/{videoId} — fetch one program by internal or public ID.

iter_records

iter_records(endpoint, *, max_items: int | None = None, **kwargs) -> Iterator[dict]

Yield result rows across pages, auto-following the cursor.

endpoint is one of the cursor-based search methods (:meth:bills, :meth:mentions, :meth:people, :meth:programs_search). The output format is forced to JSON internally so the cursor can be read; each row is yielded as a dict.

Parameters:

Name Type Description Default
max_items int | None

stop after yielding this many rows (default: all).

Example

for row in client.iter_records(client.bills, query="budget", max_items=200): ... ...

None

speeches_on_bill

speeches_on_bill(*, title: str | None = None, number: str | int | None = None, congress: int | None = None, videotypes: tuple[str, ...] = ('Speech', 'Debate'), mindate: str | None = None, maxdate: str | None = None, max_items: int | None = None) -> dict[str, Any]

Find every senator who spoke about a bill, grouped with their speeches.

Because the API has no structured bill-to-speech link, this searches the spoken-word transcript (:meth:mentions) for the bill's title and number, keeps only floor videotypes (default Speech/Debate), then keeps speakers whose person title contains "Senator".

Provide a title and/or number (more variants searched = better recall) and a congress (used to scope the date window unless mindate/maxdate are given explicitly).

max_items caps the rows fetched for each title/number variant and video type combination (a quota guard), not the total.

Returns:

Type Description
dict[str, Any]

{"bill": {...}, "videotypes": [...], "senators": [ {"personid", "name", "title", "speeches": [<mention rows>]}, ...]}, senators sorted by speech count (descending), then name.

Example

client.speeches_on_bill( ... title="Inflation Reduction Act", number="H.R. 5376", congress=117 ... )

save

save(endpoint, dest, *, format: str = 'csv', paginate: bool = True, max_items: int | None = None, filename: str | None = None, **params) -> str

Fetch from endpoint and write the results to a file. Returns the path.

Parameters:

Name Type Description Default
endpoint

a search method (:meth:bills, :meth:mentions, :meth:people, :meth:programs_search) or its name as a string.

required
dest

a file path, or a directory (an existing directory, or a path ending in a separator) in which a file named <endpoint>.<ext> is created.

required
format str

csv, json, jsonl, xlsx, or parquet. xlsx/parquet require pandas (and openpyxl / pyarrow).

'csv'
paginate bool

if True (default), follow the cursor and write all result rows; if False, write only the first page.

True
max_items int | None

cap the number of rows when paginate is True.

None
filename str | None

override the auto-generated filename (used with a directory dest).

None
params

query parameters forwarded to the endpoint (e.g. query=..., sort=...).

Example

client.save(client.bills, "out/", query="budget", format="csv") 'out/bills.csv'

{}

close

close() -> None

Close the underlying HTTP session.

Formats

to_records

to_records(data: Any) -> list[dict]

Best-effort extraction of result rows as a list[dict].

  • A list is treated as the rows directly.
  • A dict is searched for its first list-of-dicts value (the result set).
  • A dict holding nothing but pagination metadata is an empty result set.
  • Otherwise the dict itself is returned as a single row (e.g. the flat payload of /programs/{videoId}).

to_csv

to_csv(data: Any) -> str

Convert a JSON response to a CSV string (header + one row per record).

to_jsonl

to_jsonl(data: Any) -> str

Convert a JSON response to JSON Lines (one JSON record per line).

to_dataframe

to_dataframe(data: Any)

Convert a JSON response to a pandas DataFrame (requires pandas).

SUPPORTED_FORMATS module-attribute

SUPPORTED_FORMATS = ('json', 'records', 'csv', 'dataframe')

SAVE_FORMATS module-attribute

SAVE_FORMATS = tuple(WRITERS)

Exceptions

CSpanError                  # base — catch this to catch everything
├── ValidationError         # invalid input, raised before any request
└── APIError                # the API returned an error response
    ├── AuthenticationError # missing/invalid API key (HTTP 401/403)
    ├── NotFoundError       # resource does not exist (HTTP 404)
    └── RateLimitError      # quota/throttle exceeded (HTTP 429)

CSpanError

Bases: Exception

ValidationError

Bases: CSpanError, ValueError

APIError

APIError(message: str, *, status_code: int | None = None, response: object = None)

Bases: CSpanError

Attributes:

Name Type Description
status_code

HTTP status code, if available.

response

the underlying :class:requests.Response, if available.

AuthenticationError

AuthenticationError(message: str, *, status_code: int | None = None, response: object = None)

Bases: APIError

NotFoundError

NotFoundError(message: str, *, status_code: int | None = None, response: object = None)

Bases: APIError

RateLimitError

RateLimitError(message: str, *, retry_after: float | None = None, status_code: int | None = None, response: object = None)

Bases: APIError

Attributes:

Name Type Description
retry_after

seconds to wait before retrying, parsed from the Retry-After header when present.

Constants

BASE_URL module-attribute

BASE_URL = 'https://api.c-spanarchives.org/2.0'

ENV_API_KEY module-attribute

ENV_API_KEY = 'CSPAN_API_KEY'