API reference¶
Client¶
- class closecity.Client(api_key: str | None = None, *, base_url: str = 'https://api.close.city', timeout: float = 30.0, output: str = 'spatial', http_client: httpx.Client | None = None, transport: httpx.BaseTransport | None = None)[source]¶
Client for the Close API.
api_keyis optional (the catalog and health routes are free), but every data route needs one (ack_live_key), created at https://account.close.city. Usable as a context manager.outputsets how results come back, and defaults to"spatial":"spatial"returns ageopandas.GeoDataFramefor routes with geometry (points, isochrone and block polygons) and a plainpandas.DataFramefor the rest;"tabular"returns a plainpandas.DataFramefor every route and never downloads block boundaries (the cheap path when you only want the numbers);
Set it on the client (
close.output = "raw") or per call (close.blocks_query(..., output = "tabular")).- last_updated() Reply[source]¶
Publication timestamp of the newest published data (free). Always a raw
Reply.
- modes(*, output: str | None = None)[source]¶
The travel modes and their numeric ids (free). A DataFrame of
mode_id, mode, description, or a rawReplywhenoutput="raw".
- destination_types(*, output: str | None = None)[source]¶
The destination-type taxonomy with leaf expansions (free). A DataFrame of
dest_type_id, name, label, is_leaf, leaf_ids, or a rawReplywhenoutput="raw". Filtering by a parent type expands to itsleaf_ids.
- vintage(*, output: str | None = None)[source]¶
The active version of each dataset component (free). A DataFrame of
component, version, effective_date, or a rawReply.
- places(q: str, *, limit: int | None = None, output: str | None = None)[source]¶
Search census places by name (free). Each match carries the place’s GEOID and WGS84 centroid. Feed a centre into
blocks_query(center=...), or a GEOID intoplace_blocks(...).qis a name substring;limitcaps the matches (1 to 20). A points GeoDataFrame (or a plain DataFrame underoutput="tabular", a rawReplyunderoutput="raw").
- block_summary(geoid: str, *, mode=None, type=None, if_none_match: str | None = None, output: str | None = None)[source]¶
Fastest travel time to each destination category from a census block, by mode.
geoidis a 15-digit block GEOID;mode/typeare optional filters (scalar or list). Supportsif_none_match(ETag/304). A DataFrame (the origin GEOID broadcast to ageoidcolumn), or a rawReply.
- block_pois(geoid: str, *, mode=None, type=None, dest_id=None, max_minutes=None, limit=None, output: str | None = None)[source]¶
Every nearby POI and its travel time from a block, one row per (POI, mode). A GeoDataFrame of points (a plain DataFrame under
output="tabular", aPaginatorunderoutput="raw").
- point_summary(lat: float, lon: float, *, mode=None, type=None, if_none_match: str | None = None, output: str | None = None)[source]¶
Like
block_summary, but from the census block containing a lat/lon. The resolved block GEOID is echoed asresolved_blockand broadcast to ageoidcolumn. A DataFrame, or a rawReply.
- point_pois(lat: float, lon: float, *, mode=None, type=None, dest_id=None, max_minutes=None, limit=None, output: str | None = None)[source]¶
Like
block_pois, but from the block containing a lat/lon. A GeoDataFrame of points (a plain DataFrame underoutput="tabular", aPaginatorunderoutput="raw").
- pois_search(*, lat=None, lon=None, radius_m=None, bbox=None, type=None, q=None, limit=None, output: str | None = None)[source]¶
Search POIs by bounding box (
bbox) or radius (lat+lon+radius_m). A GeoDataFrame of points (a plain DataFrame underoutput="tabular", aPaginatorunderoutput="raw").
- poi(dest_id: int, *, if_none_match: str | None = None, output: str | None = None)[source]¶
Name, location, address, types, and whitelisted attributes for one POI. A one-row points GeoDataFrame (a plain DataFrame under
output="tabular", aReplyunderoutput="raw").
- poi_catchment(dest_id: int, *, mode=None, block=None, max_minutes=None, limit=None, output: str | None = None)[source]¶
Every census block that can reach a POI, one row per (block, mode). A GeoDataFrame of block polygons (a plain DataFrame under
output="tabular", aPaginatorunderoutput="raw").
- blocks_query(*, polygon: dict | None = None, center: dict | None = None, radius_m: float | None = None, type: Sequence[int] | None = None, mode: Sequence[str] | None = None, include_population: bool | None = None, limit: int | None = None, output: str | None = None)[source]¶
Blocks within a GeoJSON
polygonor acenter+radius_m. Rows carry the numericmode_id(joinmodes()to label it). A GeoDataFrame of block polygons (a plain DataFrame underoutput="tabular", aPaginatorunderoutput="raw").
- place_blocks(geoid: str, *, mode=None, type=None, include_population=None, limit=None, output: str | None = None)[source]¶
Per-block travel times for every census block in a place (city or town), by place GEOID. Rows carry the numeric
mode_id(joinmodes()to label it). A GeoDataFrame of block polygons (a plain DataFrame underoutput="tabular", aPaginatorunderoutput="raw").
- isochrone(*, block=None, lon=None, lat=None, mode=None, direction=None, minutes=None, contours=None, format=None, v=None, if_none_match: str | None = None, output: str | None = None)[source]¶
Travel-time contours from a
block(GEOID) orlon+lat. Passminutes(single) orcontours(up to 4 ascending levels, a list or a comma string). Inspatialmodeformat="geojson"gives contour polygons andformat="blocks"gives block polygons;tabulargives the matching rows;rawgives aReply.
Replies and pagination¶
- class closecity.Reply(data: Any, status: int, tokens_charged: int | None = None, tokens_remaining: int | None = None, etag: str | None = None, request_id: str | None = None, not_modified: bool = False)[source]¶
One API response, with the metering + caching metadata exposed.
datais the parsed JSON body (adictfor every route). For a304revalidationnot_modifiedis True anddatais None.tokens_charged/tokens_remainingare None on free and member-unmetered responses.- to_geopandas(**kwargs)[source]¶
Convert this reply to a
geopandas.GeoDataFrame.Points for POI replies, polygons for isochrone
format=geojson. Block replies need ablock_geometry=GeoDataFrame orfetch=True(which downloads TIGER blocks withpygris). Seeclosecity.spatial.to_geopandas().
- class closecity.Paginator(_client: Client, _method: str, _path: str, _params: dict[str, ~typing.Any]=<factory>, _json: dict[str, ~typing.Any] | None=None, _cursor_in: str = 'params')[source]¶
Lazily follows
next_cursoracross pages.Iterate it directly to get every record; use
pages()for per-pageReplyobjects (each carrying its own token/ETag metadata); usepage()to fetch a single page.- to_geopandas(**kwargs)[source]¶
Collect every page and convert the rows to a
geopandas.GeoDataFrame. Seeclosecity.spatial.to_geopandas().
Output conversion¶
- closecity.to_pandas(source: Any, *, key: str | None = None) DataFrame[source]¶
Convert a Close API reply into a
pandas.DataFrame.sourceis aReply, aPaginator(all pages are collected), or a raw response body.keynames the record array explicitly; when omitted it is detected from the body. Metering and envelope metadata land ondf.attrs.
- closecity.to_geopandas(source: Any, *, block_geometry: Any = None, geoid_col: str = 'GEOID20', crs: Any = 'EPSG:4326', fetch: bool = False)[source]¶
Convert a Close API reply into a
geopandas.GeoDataFrame.sourceis aReply, aPaginator(all pages are collected), or a raw response body. The geometry kind is detected from the payload; see the module docstring.block_geometry/geoid_col/fetchonly apply to block replies. Metering and envelope metadata land on.attrs.
Errors¶
Exceptions mapped from the API’s RFC 9457 problem+json responses.
Every error the API returns has a stable type URI whose final path segment is
the slug (e.g. tokens-exhausted). We map on that slug, falling back to the
HTTP status, so callers can catch a precise class or the CloseAPIError base.
- exception closecity.errors.CloseError[source]¶
Bases:
ExceptionBase class for every error raised by this client.
- exception closecity.errors.CloseAPIError(*, status: int, slug: str, title: str, detail: str | None = None, request_id: str | None = None, retry_after: float | None = None, extras: dict[str, Any] | None = None)[source]¶
Bases:
CloseErrorAn error response from the API (a problem+json body).
Attributes mirror the problem document:
slug(the stable machine key),title,status,detail, plusrequest_id(fromX-Request-Id, quote it in support requests),retry_afterwhen present, andextrasfor any additional problem members (e.g. validationerrors).
- exception closecity.errors.BadRequestError(*, status: int, slug: str, title: str, detail: str | None = None, request_id: str | None = None, retry_after: float | None = None, extras: dict[str, Any] | None = None)[source]¶
Bases:
CloseAPIError400: invalid parameters, cursor, geometry, bbox, etc.
- exception closecity.errors.AuthenticationError(*, status: int, slug: str, title: str, detail: str | None = None, request_id: str | None = None, retry_after: float | None = None, extras: dict[str, Any] | None = None)[source]¶
Bases:
CloseAPIError401: missing or invalid API key.
- exception closecity.errors.PermissionDeniedError(*, status: int, slug: str, title: str, detail: str | None = None, request_id: str | None = None, retry_after: float | None = None, extras: dict[str, Any] | None = None)[source]¶
Bases:
CloseAPIError403: the key’s account is disabled (or membership is required).
- exception closecity.errors.NotFoundError(*, status: int, slug: str, title: str, detail: str | None = None, request_id: str | None = None, retry_after: float | None = None, extras: dict[str, Any] | None = None)[source]¶
Bases:
CloseAPIError404: the block, POI, place, or point is not in the published data.
- exception closecity.errors.RateLimitedError(*, status: int, slug: str, title: str, detail: str | None = None, request_id: str | None = None, retry_after: float | None = None, extras: dict[str, Any] | None = None)[source]¶
Bases:
CloseAPIError429 rate-limited: too many requests; see
retry_after.
- exception closecity.errors.TokensExhaustedError(*, status: int, slug: str, title: str, detail: str | None = None, request_id: str | None = None, retry_after: float | None = None, extras: dict[str, Any] | None = None)[source]¶
Bases:
CloseAPIError429 tokens-exhausted: the account’s token balance is zero.
Bases:
CloseAPIError503: a backend is briefly unavailable; the request was not charged.