The API is metered in tokens: one per returned row, minimum one per request, and 10 per isochrone contour. Tokens are rows, so spending well is mostly about not asking for rows you will throw away.
Free queries
Metadata queries are free and keyless: $modes(),
$destination_types(), $vintage(),
$places(), $isochrone_meta(),
$last_updated(), and $health(). Do your
lookups before you spend a token.
Revalidation is free too. Keep a reply’s etag and pass
it back as if_none_match; an unchanged response returns a
free 304. Read output = "raw" when you want
the etag:
close$output <- "raw"
first <- close$block_summary(geoid = "440070008001068", mode = "walk")
again <- close$block_summary(
geoid = "440070008001068",
mode = "walk",
if_none_match = first$etag
)
again$not_modified # TRUE, and nothing was charged
#> [1] TRUEThe big levers
The rows a query returns multiply out as modes times types times blocks:
-
Pass
mode. Omitting it returns all three modes, so three times the rows. -
Filter by
type. The POI and areal routes take a destinationtype, so ask the server for only the category you want rather than fetching everything and filtering in R. Look the id up in$destination_types(). -
Request leaf types, not parents. A parent type
expands to its leaves, so a single leaf id is a fraction of the rows of
a parent like
parks. -
Shrink the area. Cost grows with the square of
radius_m, so halving the radius is roughly a quarter of the tokens. -
Use
max_minutes. It drops rows you would filter out anyway.
Isochrones are the cheap reach primitive
An isochrone is 10 tokens per contour regardless of area, and
format = "blocks" returns every reachable block with its
minutes. A whole walkshed for 10 tokens, where a catchment or block
query charges per block:
shed <- close$isochrone(
block = "440070008001068",
minutes = 30,
mode = "walk",
format = "blocks"
)Watch what you spend
Every metered reply carries the token counts. In the frame output
modes they are attached as attributes; in output = "raw"
they are on the reply. Here the type filter asks only for
supermarkets, so you pay for a handful of rows, not every POI in the
radius:
close$output <- "tabular"
types <- close$destination_types()
supermarket_dest_type <- types[types$label == "grocery_stores", ]$dest_type_id
supermarkets <- close$pois_search(
lat = 41.823,
lon = -71.412,
radius_m = 1200,
type = supermarket_dest_type
)
attr(supermarkets, "tokens_charged")
#> [1] 2
attr(supermarkets, "tokens_remaining")
#> [1] 999268406When you only want the numbers, output = "tabular" skips
the block-boundary download entirely. The block boundaries the spatial
mode joins are cached locally, so re-running a script costs time, not
tokens; pass a block_geometry frame you already have to
skip even that.
