{"openapi":"3.1.0","info":{"title":"Close API","description":"Travel times from every US census block to nearby points of interest, by\nwalking, biking, and public transit. This is the data behind close.city.\n\nMetering: 1 token = 1 returned data row, minimum 1 token per request;\nisochrones charge 10 tokens per contour level instead. 304 responses are free.\nTravel times to points of interest are capped at 30 minutes, matching the\npublic map; isochrone contours go to 60.\n","contact":{"name":"Close","url":"https://close.city/"},"version":"1.3.0"},"paths":{"/v1/health":{"get":{"tags":["service"],"summary":"Liveness check","description":"Unauthenticated liveness probe. Touches no database and is never metered.","operationId":"health_v1_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/v1/meta/modes":{"get":{"tags":["metadata"],"summary":"List travel modes","description":"The travel modes and their numeric ids. Free and container-cached.","operationId":"meta_modes_v1_meta_modes_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModesResponse"}}}}}}},"/v1/meta/destination-types":{"get":{"tags":["metadata"],"summary":"Destination-type taxonomy","description":"The destination-type taxonomy. Parent types carry the leaf ids they\nexpand to when used as a travel-time `type` filter. Free and cached.","operationId":"meta_destination_types_v1_meta_destination_types_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DestinationTypesResponse"}}}}}}},"/v1/meta/vintage":{"get":{"tags":["metadata"],"summary":"Dataset component versions","description":"The active version and effective date of each dataset component\n(road network, transit, POIs, blocks, parks). Free and cached.","operationId":"meta_vintage_v1_meta_vintage_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VintageResponse"}}}}}}},"/v1/last-updated":{"get":{"tags":["metadata"],"summary":"Newest data timestamp","description":"Publication timestamp of the most recent public dataset component. Free\n(no API key required).","operationId":"last_updated_v1_last_updated_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LastUpdatedResponse"}}}}}}},"/v1/plans":{"get":{"tags":["metadata"],"summary":"Plans and pricing","description":"Machine-readable pricing: the free tier's one-time signup grant, the\nClose+ membership, and token packs, with sign-up pointers for API clients\nand agents. Free, keyless, and static (no database).","operationId":"plans_v1_plans_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlansResponse"}}}}}}},"/v1/places":{"get":{"tags":["places"],"summary":"Search census places by name","description":"Resolve a city/town name to its census place GEOID and WGS84 centroid.\nFree (no API key). Matches are ranked prefix-first, then by population. Feed\n`lon`/`lat` into `/v1/blocks/query` (center + radius_m), or `geoid` into\n`/v1/places/{geoid}/blocks`.","operationId":"places_v1_places_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":2,"maxLength":80,"description":"Name substring, e.g. 'Providence'","title":"Q"},"description":"Name substring, e.g. 'Providence'"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlacesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/blocks/{geoid}/summary":{"get":{"tags":["origin block"],"summary":"Per-category travel times","description":"Fastest travel time from this block to each destination category, by\nmode. These are the same per-category minimums close.city shows.","operationId":"blocks_summary_v1_blocks__geoid__summary_get","parameters":[{"name":"geoid","in":"path","required":true,"schema":{"type":"string","pattern":"^\\d{15}$","description":"15-digit census block GEOID","examples":["360610001001000"],"title":"Geoid"},"description":"15-digit census block GEOID"},{"name":"mode","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Mode"}},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"title":"Type"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockSummaryResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Resource not found (block-not-found, poi-not-found, place-not-found, point-not-covered, no-isochrone-data, direction-not-available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"304":{"description":"Not modified (If-None-Match matched the ETag); no body, no tokens charged"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/blocks/{geoid}/pois":{"get":{"tags":["origin block"],"summary":"Per-POI travel times","description":"Every nearby point of interest and its travel time from this block,\none row per (POI, mode). Keyset-paginated by (mode, dest_id).","operationId":"blocks_pois_v1_blocks__geoid__pois_get","parameters":[{"name":"geoid","in":"path","required":true,"schema":{"type":"string","pattern":"^\\d{15}$","description":"15-digit census block GEOID","examples":["360610001001000"],"title":"Geoid"},"description":"15-digit census block GEOID"},{"name":"mode","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Mode"}},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"title":"Type"}},{"name":"dest_id","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"title":"Dest Id"}},{"name":"max_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":30,"minimum":0},{"type":"null"}],"title":"Max Minutes"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockPoisResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Resource not found (block-not-found, poi-not-found, place-not-found, point-not-covered, no-isochrone-data, direction-not-available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"304":{"description":"Not modified (If-None-Match matched the ETag); no body, no tokens charged"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/point/summary":{"get":{"tags":["origin coordinate"],"summary":"Per-category travel times at a point","description":"Fastest travel time to each destination category by mode, from the census\nblock containing this lat/lon. Same shape as `/v1/blocks/{geoid}/summary`,\nwith the resolved block GEOID echoed as `resolved_block`.","operationId":"point_summary_v1_point_summary_get","parameters":[{"name":"lat","in":"query","required":true,"schema":{"type":"number","maximum":90,"minimum":-90,"description":"Latitude (WGS84)","title":"Lat"},"description":"Latitude (WGS84)"},{"name":"lon","in":"query","required":true,"schema":{"type":"number","maximum":180,"minimum":-180,"description":"Longitude (WGS84)","title":"Lon"},"description":"Longitude (WGS84)"},{"name":"mode","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Mode"}},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"title":"Type"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PointSummaryResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Resource not found (block-not-found, poi-not-found, place-not-found, point-not-covered, no-isochrone-data, direction-not-available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"304":{"description":"Not modified (If-None-Match matched the ETag); no body, no tokens charged"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]},"post":{"tags":["batch"],"summary":"Per-category travel times at many points","description":"Fastest travel time to each destination category by mode, from the census\nblock containing each of many lat/lon points. This is the batch form of\n`GET /v1/point/summary`, a POST on the same path. Each row carries its\n`origin_lat` and `origin_lon`, and `origins` maps each point to its resolved\nblock with population and land area.","operationId":"point_summary_batch_v1_point_summary_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PointSummaryBatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchPointSummaryResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/point/pois":{"get":{"tags":["origin coordinate"],"summary":"Per-POI travel times at a point","description":"Every nearby POI and its travel time from the census block containing this\nlat/lon, one row per (POI, mode). Keyset-paginated by (mode, dest_id).","operationId":"point_pois_v1_point_pois_get","parameters":[{"name":"lat","in":"query","required":true,"schema":{"type":"number","maximum":90,"minimum":-90,"description":"Latitude (WGS84)","title":"Lat"},"description":"Latitude (WGS84)"},{"name":"lon","in":"query","required":true,"schema":{"type":"number","maximum":180,"minimum":-180,"description":"Longitude (WGS84)","title":"Lon"},"description":"Longitude (WGS84)"},{"name":"mode","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Mode"}},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"title":"Type"}},{"name":"dest_id","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"title":"Dest Id"}},{"name":"max_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":30,"minimum":0},{"type":"null"}],"title":"Max Minutes"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PointPoisResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Resource not found (block-not-found, poi-not-found, place-not-found, point-not-covered, no-isochrone-data, direction-not-available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"304":{"description":"Not modified (If-None-Match matched the ETag); no body, no tokens charged"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]},"post":{"tags":["batch"],"summary":"Per-POI travel times at many points","description":"Every nearby POI and its travel time from the census block containing each\nof many lat/lon points, one row per (origin point, POI, mode). Each row\ncarries its `origin_lat`/`origin_lon`; `origins` maps each point to its\nresolved block.","operationId":"point_pois_batch_v1_point_pois_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PointPoisBatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchPointPoisResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/pois/{dest_id}/catchment":{"get":{"tags":["destination POI"],"summary":"Blocks that can reach a POI","description":"Every census block within reach of this POI and its travel time, one row\nper (block, mode). Keyset-paginated by (mode, block).","operationId":"poi_catchment_v1_pois__dest_id__catchment_get","parameters":[{"name":"dest_id","in":"path","required":true,"schema":{"type":"integer","description":"Stable destination id","examples":[4181],"title":"Dest Id"},"description":"Stable destination id"},{"name":"mode","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Mode"}},{"name":"block","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"title":"Block"}},{"name":"max_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":30,"minimum":0},{"type":"null"}],"title":"Max Minutes"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatchmentResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Resource not found (block-not-found, poi-not-found, place-not-found, point-not-covered, no-isochrone-data, direction-not-available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"304":{"description":"Not modified (If-None-Match matched the ETag); no body, no tokens charged"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/pois":{"get":{"tags":["destination POI"],"summary":"Search POIs by location","description":"Find POIs within a bounding box or a radius of a point. Provide either\n`bbox`, or `lat`+`lon`+`radius_m`.","operationId":"poi_search_v1_pois_get","parameters":[{"name":"lat","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":90,"minimum":-90},{"type":"null"}],"title":"Lat"}},{"name":"lon","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":180,"minimum":-180},{"type":"null"}],"title":"Lon"}},{"name":"radius_m","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":50000,"exclusiveMinimum":0},{"type":"null"}],"title":"Radius M"}},{"name":"bbox","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"min_lon,min_lat,max_lon,max_lat","title":"Bbox"},"description":"min_lon,min_lat,max_lon,max_lat"},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"title":"Type"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Name substring","title":"Q"},"description":"Name substring"},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PoiSearchResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"304":{"description":"Not modified (If-None-Match matched the ETag); no body, no tokens charged"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/pois/{dest_id}":{"get":{"tags":["destination POI"],"summary":"POI detail","description":"Name, location, address, types, and whitelisted attributes for one POI.","operationId":"poi_detail_v1_pois__dest_id__get","parameters":[{"name":"dest_id","in":"path","required":true,"schema":{"type":"integer","description":"Stable destination id","examples":[4181],"title":"Dest Id"},"description":"Stable destination id"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PoiDetail"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Resource not found (block-not-found, poi-not-found, place-not-found, point-not-covered, no-isochrone-data, direction-not-available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"304":{"description":"Not modified (If-None-Match matched the ETag); no body, no tokens charged"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/blocks/query":{"post":{"tags":["areal"],"summary":"Blocks within a polygon or radius","description":"Per-block travel times for every block intersecting a GeoJSON polygon, or\na radius around a point. One row per (block, category, mode).","operationId":"blocks_query_v1_blocks_query_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlocksQuery"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArealBlocksResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/places/{geoid}/blocks":{"get":{"tags":["areal"],"summary":"Blocks within a census place","description":"Per-block travel times for every census block in a place (city/town).","operationId":"place_blocks_v1_places__geoid__blocks_get","parameters":[{"name":"geoid","in":"path","required":true,"schema":{"type":"string","description":"Census place GEOID","title":"Geoid"},"description":"Census place GEOID"},{"name":"mode","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Mode"}},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"title":"Type"}},{"name":"include_population","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Population"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArealBlocksResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Resource not found (block-not-found, poi-not-found, place-not-found, point-not-covered, no-isochrone-data, direction-not-available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"304":{"description":"Not modified (If-None-Match matched the ETag); no body, no tokens charged"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/places/{geoid}/pois":{"get":{"tags":["areal"],"summary":"POIs within a census place","description":"Every point of interest whose location falls within a census place's\nboundary (city/town). The place analog of `/v1/pois`; filter by `type` to\nget, e.g., all supermarkets in a city. This route is spatial only, with no\ntravel times.","operationId":"place_pois_v1_places__geoid__pois_get","parameters":[{"name":"geoid","in":"path","required":true,"schema":{"type":"string","description":"Census place GEOID","title":"Geoid"},"description":"Census place GEOID"},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"description":"Destination type id(s) to keep","title":"Type"},"description":"Destination type id(s) to keep"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Name substring","title":"Q"},"description":"Name substring"},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PoiSearchResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Resource not found (block-not-found, poi-not-found, place-not-found, point-not-covered, no-isochrone-data, direction-not-available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"304":{"description":"Not modified (If-None-Match matched the ETag); no body, no tokens charged"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/places/{geoid}/boundary":{"get":{"tags":["areal"],"summary":"Boundary polygon of a census place","description":"The boundary polygon of a census place (city/town) as a GeoJSON Feature.\nFree (no API key). Handy as a background outline when mapping a city's blocks\nor POIs; the geometry is lightly simplified for display.","operationId":"place_boundary_v1_places__geoid__boundary_get","parameters":[{"name":"geoid","in":"path","required":true,"schema":{"type":"string","description":"Census place GEOID","title":"Geoid"},"description":"Census place GEOID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceBoundary"}}}},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/blocks/summary":{"post":{"tags":["batch"],"summary":"Per-category travel times for many blocks","description":"Fastest travel time from each of many census blocks to each destination\ncategory, by mode. This is the batch form of `GET /v1/blocks/{geoid}/summary`.\nEach result row carries its origin `geoid`, and per-block population and land\narea come back in `blocks`. The whole batch counts as one request against the\nrate limit.","operationId":"blocks_summary_batch_v1_blocks_summary_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockSummaryBatch"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchBlockSummaryResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/blocks/pois":{"post":{"tags":["batch"],"summary":"Per-POI travel times for many blocks","description":"Every nearby POI and its travel time from each of many census blocks, one\nrow per (origin block, POI, mode). This is the batch form of\n`GET /v1/blocks/{geoid}/pois`. Each row carries its origin `geoid`. The batch\nis not paginated, so each origin returns all matching POIs within\n`max_minutes`.","operationId":"blocks_pois_batch_v1_blocks_pois_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockPoisBatch"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchBlockPoisResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/pois/catchment":{"post":{"tags":["batch"],"summary":"Blocks that can reach many POIs","description":"Every census block within reach of each of many POIs and its travel time,\none row per (POI, block, mode). This is the batch form of\n`GET /v1/pois/{dest_id}/catchment`. Each row carries its origin `dest_id`.","operationId":"poi_catchment_batch_v1_pois_catchment_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatchmentBatch"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchCatchmentResponse"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/isochrone":{"get":{"tags":["isochrone"],"summary":"Travel-time contours from a block or point","description":"Travel-time contours around a census block (by GEOID) or a lat/lon point.\nSupply `block` XOR `lon`+`lat`, and `minutes` XOR `contours` (up to 4\nascending levels). `format=geojson` returns contour polygons (largest first);\n`format=blocks` returns the reachable blocks with their travel minutes.\nMetered at 10 tokens per contour level with a `ck_` key; unmetered for a Close+\nmember `mt_` bearer.","operationId":"get_isochrone_v1_isochrone_get","parameters":[{"name":"block","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"15-digit census block GEOID","title":"Block"},"description":"15-digit census block GEOID"},{"name":"lon","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Longitude (WGS84)","title":"Lon"},"description":"Longitude (WGS84)"},{"name":"lat","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Latitude (WGS84)","title":"Lat"},"description":"Latitude (WGS84)"},{"name":"mode","in":"query","required":false,"schema":{"type":"string","description":"walk | bike | transit","default":"walk","title":"Mode"},"description":"walk | bike | transit"},{"name":"direction","in":"query","required":false,"schema":{"type":"string","description":"to | from","default":"to","title":"Direction"},"description":"to | from"},{"name":"minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Single threshold, 1-60","title":"Minutes"},"description":"Single threshold, 1-60"},{"name":"contours","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Up to 4 ascending thresholds, e.g. 15,30,45","title":"Contours"},"description":"Up to 4 ascending thresholds, e.g. 15,30,45"},{"name":"format","in":"query","required":false,"schema":{"type":"string","description":"geojson | blocks","default":"geojson","title":"Format"},"description":"geojson | blocks"},{"name":"v","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque CDN cache-buster; echoed","title":"V"},"description":"Opaque CDN cache-buster; echoed"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/IsochroneGeoJSON"},{"$ref":"#/components/schemas/IsochroneBlocks"}],"title":"Response 200 Get Isochrone V1 Isochrone Get"}}}},"400":{"description":"Invalid request (e.g. invalid-parameters, invalid-cursor, invalid-bbox, missing-location, missing-area, invalid-geometry, polygon-too-complex, missing-origins, too-many-origins)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationProblem"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Resource not found (block-not-found, poi-not-found, place-not-found, point-not-covered, no-isochrone-data, direction-not-available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"304":{"description":"Not modified (If-None-Match matched the ETag); no body, no tokens charged"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"apiKey":[]}]}},"/v1/isochrone/meta":{"get":{"tags":["isochrone"],"summary":"Isochrone store version and assumptions","description":"The active store version and its assumptions.\n\nThe frontend reads this for attribution, for the `v=` cache key, and to\nlearn which directions/modes actually exist rather than assuming.","operationId":"get_isochrone_meta_v1_isochrone_meta_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IsochroneMetaResponse"}}}},"503":{"description":"Backend temporarily unavailable (debit-unavailable, store-unavailable); may set Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"304":{"description":"Not modified (If-None-Match matched the ETag); no body, no tokens charged"}}}},"/v1/tokens":{"get":{"tags":["account"],"summary":"Token balance","description":"The current token balance of the presented API key's account. Requires\na key and counts toward the per-key rate limit, but never charges tokens,\nso a zero-balance key can always check.","operationId":"token_balance_v1_tokens_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokensResponse"}}}},"401":{"description":"Missing or invalid API key (missing-key, invalid-key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key disabled (account-disabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited or token balance exhausted (rate-limited, tokens-exhausted); sets Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"apiKey":[]}]}},"/auth/request":{"servers":[{"url":"https://account.close.city"}],"post":{"tags":["account"],"operationId":"portal_auth_request","summary":"Email the user a sign-in code","description":"Send a magic link and a six-digit code to the user's email. The user reads the code from their own inbox and gives it to the client — that human-in-the-loop step is deliberate. New accounts receive a one-time grant of free API tokens on first sign-in (see GET /v1/plans on api.close.city). Rate-limited per email address and per IP.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"}}}}}},"responses":{"200":{"description":"Code sent if the address is valid."},"400":{"description":"Rejected email address."},"429":{"description":"Too many requests for this email or IP."}}}},"/auth/verify-code":{"servers":[{"url":"https://account.close.city"}],"post":{"tags":["account"],"operationId":"portal_auth_verify_code","summary":"Verify the sign-in code","description":"Exchange the emailed six-digit code for a portal session. The session arrives as a Set-Cookie response header; keep a cookie jar and send it on the requests that follow.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","code"],"properties":{"email":{"type":"string","format":"email"},"code":{"type":"string","description":"Six digits."}}}}}},"responses":{"200":{"description":"Signed in; session cookie set."},"400":{"description":"Wrong or expired code."},"429":{"description":"Too many attempts."}}}},"/auth/csrf":{"servers":[{"url":"https://account.close.city"}],"get":{"tags":["account"],"operationId":"portal_auth_csrf","summary":"Read the session's CSRF token","description":"Return the CSRF token for the signed-in session. Send it as an X-CSRF-Token header on POST /keys and POST /billing/subscribe.","security":[{"sessionCookie":[]}],"responses":{"200":{"description":"The CSRF token.","content":{"application/json":{"schema":{"type":"object","properties":{"csrf":{"type":"string"}}}}}},"401":{"description":"No signed-in session."}}}},"/keys":{"servers":[{"url":"https://account.close.city"}],"post":{"tags":["account"],"operationId":"portal_create_key","summary":"Mint an API key","description":"Create a new ck_ API key for the signed-in account. The raw key is returned exactly once; store it and pass it as the Authorization bearer on api.close.city. Accounts hold at most 3 active keys.","security":[{"sessionCookie":[]}],"parameters":[{"name":"X-CSRF-Token","in":"header","required":true,"schema":{"type":"string"},"description":"The session's CSRF token, from GET /auth/csrf."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","description":"Optional label."}}}}}},"responses":{"201":{"description":"The new key, shown once.","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"prefix":{"type":"string"},"tokens_remaining":{"type":"integer","description":"The account's current token balance. The signup grant is once per account, so this can be 0 for a returning account."}}}}}},"401":{"description":"No signed-in session."},"403":{"description":"Missing or invalid X-CSRF-Token."},"409":{"description":"Active-key limit reached; revoke one."}}}},"/billing/subscribe":{"servers":[{"url":"https://account.close.city"}],"post":{"tags":["account"],"operationId":"portal_billing_subscribe","summary":"Start a Close+ subscription checkout","description":"Return a Stripe Checkout URL for the $10/month Close+ membership. Hand the URL to the user to open in their own browser — payment is never automated. See GET /v1/plans on api.close.city for what the membership includes.","security":[{"sessionCookie":[]}],"parameters":[{"name":"X-CSRF-Token","in":"header","required":true,"schema":{"type":"string"},"description":"The session's CSRF token, from GET /auth/csrf."}],"responses":{"200":{"description":"Checkout ready.","content":{"application/json":{"schema":{"type":"object","properties":{"checkout_url":{"type":"string"}}}}}},"401":{"description":"No signed-in session."},"403":{"description":"Missing or invalid X-CSRF-Token."},"404":{"description":"Close+ is not available."},"409":{"description":"Already subscribed; manage at the returned portal URL.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"portal_url":{"type":["string","null"]}}}}}}}}}},"components":{"schemas":{"Address":{"properties":{"street":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Street"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"zip":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zip"}},"type":"object","title":"Address","description":"A POI street address; every field is nullable. (shape.shape_pois,\nqueries.pois.detail)"},"ArealBlockResult":{"properties":{"geoid":{"type":"string","title":"Geoid"},"dest_type_id":{"type":"integer","title":"Dest Type Id"},"mode_id":{"type":"integer","title":"Mode Id","description":"Numeric mode id (see /v1/meta/modes)"},"travel_time":{"type":"number","title":"Travel Time","description":"Minutes, 1 decimal"},"population":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Population","description":"Present only when include_population=true"}},"type":"object","required":["geoid","dest_type_id","mode_id","travel_time"],"title":"ArealBlockResult","description":"One (block, category, mode) row. NOTE the int `mode_id` here, unlike the\nstring `mode` on the block/point routes. (queries.spatial._pivot)"},"ArealBlocksResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/ArealBlockResult"},"type":"array","title":"Results"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["results"],"title":"ArealBlocksResponse","description":"POST /v1/blocks/query and GET /v1/places/{geoid}/blocks\n(routers.spatial._paged)"},"BatchBlockCategoryTime":{"properties":{"dest_type_id":{"type":"integer","title":"Dest Type Id"},"mode":{"type":"string","title":"Mode","description":"Travel mode label, e.g. 'walk'"},"travel_time":{"type":"number","title":"Travel Time","description":"Minutes, capped at 30, 1 decimal"},"geoid":{"type":"string","title":"Geoid","description":"Origin block GEOID"}},"type":"object","required":["dest_type_id","mode","travel_time","geoid"],"title":"BatchBlockCategoryTime","description":"A CategoryTime row tagged with its origin block. (routers.batch)"},"BatchBlockPoiTime":{"properties":{"dest_id":{"type":"integer","title":"Dest Id"},"mode":{"type":"string","title":"Mode"},"travel_time":{"type":"number","title":"Travel Time","description":"Minutes, capped at 30, 1 decimal"},"name":{"type":"string","title":"Name"},"lon":{"type":"number","title":"Lon"},"lat":{"type":"number","title":"Lat"},"address":{"$ref":"#/components/schemas/Address"},"geoid":{"type":"string","title":"Geoid","description":"Origin block GEOID"}},"type":"object","required":["dest_id","mode","travel_time","name","lon","lat","address","geoid"],"title":"BatchBlockPoiTime","description":"A PoiTime row tagged with its origin block. (routers.batch)"},"BatchBlockPoisResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/BatchBlockPoiTime"},"type":"array","title":"Results"},"errors":{"items":{"$ref":"#/components/schemas/OriginError"},"type":"array","title":"Errors"},"truncated":{"items":{"type":"string"},"type":"array","title":"Truncated"},"truncated_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Truncated Reason","description":"'insufficient-balance' or 'row-budget'; null if nothing was truncated"}},"type":"object","required":["results","errors","truncated"],"title":"BatchBlockPoisResponse","description":"POST /v1/blocks/pois (routers.batch.blocks_pois_batch)"},"BatchBlockSummaryResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/BatchBlockCategoryTime"},"type":"array","title":"Results"},"blocks":{"items":{"$ref":"#/components/schemas/BlockMeta"},"type":"array","title":"Blocks","description":"Per-origin block metadata"},"errors":{"items":{"$ref":"#/components/schemas/OriginError"},"type":"array","title":"Errors"},"truncated":{"items":{"type":"string"},"type":"array","title":"Truncated","description":"Origin GEOIDs skipped once the row budget was spent"},"truncated_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Truncated Reason","description":"'insufficient-balance' or 'row-budget'; null if nothing was truncated"}},"type":"object","required":["results","blocks","errors","truncated"],"title":"BatchBlockSummaryResponse","description":"POST /v1/blocks/summary (routers.batch.blocks_summary_batch)"},"BatchCatchmentResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/BatchCatchmentResult"},"type":"array","title":"Results"},"errors":{"items":{"$ref":"#/components/schemas/OriginError"},"type":"array","title":"Errors"},"truncated":{"items":{"type":"integer"},"type":"array","title":"Truncated","description":"dest_ids skipped once the row budget was spent"},"truncated_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Truncated Reason","description":"'insufficient-balance' or 'row-budget'; null if nothing was truncated"}},"type":"object","required":["results","errors","truncated"],"title":"BatchCatchmentResponse","description":"POST /v1/pois/catchment (routers.batch.poi_catchment_batch)"},"BatchCatchmentResult":{"properties":{"geoid":{"type":"string","title":"Geoid"},"mode":{"type":"string","title":"Mode"},"travel_time":{"type":"number","title":"Travel Time","description":"Minutes, 1 decimal"},"dest_id":{"type":"integer","title":"Dest Id","description":"Origin POI destination id"}},"type":"object","required":["geoid","mode","travel_time","dest_id"],"title":"BatchCatchmentResult","description":"A catchment row tagged with its origin POI. (routers.batch)"},"BatchPointCategoryTime":{"properties":{"dest_type_id":{"type":"integer","title":"Dest Type Id"},"mode":{"type":"string","title":"Mode","description":"Travel mode label, e.g. 'walk'"},"travel_time":{"type":"number","title":"Travel Time","description":"Minutes, capped at 30, 1 decimal"},"origin_lat":{"type":"number","title":"Origin Lat"},"origin_lon":{"type":"number","title":"Origin Lon"}},"type":"object","required":["dest_type_id","mode","travel_time","origin_lat","origin_lon"],"title":"BatchPointCategoryTime","description":"A CategoryTime row tagged with its origin point. (routers.batch)"},"BatchPointPoiTime":{"properties":{"dest_id":{"type":"integer","title":"Dest Id"},"mode":{"type":"string","title":"Mode"},"travel_time":{"type":"number","title":"Travel Time","description":"Minutes, capped at 30, 1 decimal"},"name":{"type":"string","title":"Name"},"lon":{"type":"number","title":"Lon"},"lat":{"type":"number","title":"Lat"},"address":{"$ref":"#/components/schemas/Address"},"origin_lat":{"type":"number","title":"Origin Lat"},"origin_lon":{"type":"number","title":"Origin Lon"}},"type":"object","required":["dest_id","mode","travel_time","name","lon","lat","address","origin_lat","origin_lon"],"title":"BatchPointPoiTime","description":"A PoiTime row tagged with its origin point. (routers.batch)"},"BatchPointPoisResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/BatchPointPoiTime"},"type":"array","title":"Results"},"origins":{"items":{"$ref":"#/components/schemas/PointPoisMeta"},"type":"array","title":"Origins"},"errors":{"items":{"$ref":"#/components/schemas/OriginError"},"type":"array","title":"Errors"},"truncated":{"items":{"$ref":"#/components/schemas/PointOriginKey"},"type":"array","title":"Truncated"},"truncated_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Truncated Reason","description":"'insufficient-balance' or 'row-budget'; null if nothing was truncated"}},"type":"object","required":["results","origins","errors","truncated"],"title":"BatchPointPoisResponse","description":"POST /v1/point/pois (routers.batch.point_pois_batch)"},"BatchPointSummaryResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/BatchPointCategoryTime"},"type":"array","title":"Results"},"origins":{"items":{"$ref":"#/components/schemas/PointSummaryMeta"},"type":"array","title":"Origins"},"errors":{"items":{"$ref":"#/components/schemas/OriginError"},"type":"array","title":"Errors"},"truncated":{"items":{"$ref":"#/components/schemas/PointOriginKey"},"type":"array","title":"Truncated"},"truncated_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Truncated Reason","description":"'insufficient-balance' or 'row-budget'; null if nothing was truncated"}},"type":"object","required":["results","origins","errors","truncated"],"title":"BatchPointSummaryResponse","description":"POST /v1/point/summary (routers.batch.point_summary_batch)"},"BlockMeta":{"properties":{"geoid":{"type":"string","title":"Geoid","description":"15-digit census block GEOID"},"population":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Population"},"land_area_m2":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Land Area M2","description":"Block land area in square metres"}},"type":"object","required":["geoid"],"title":"BlockMeta","description":"Census-block metadata. (queries.blocks.summary_rows -> block_meta)"},"BlockPoisBatch":{"properties":{"origins":{"items":{"type":"string"},"type":"array","title":"Origins","description":"Census block GEOIDs (1-250)"},"mode":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Mode"},"type":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Type"},"dest_id":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Dest Id"},"max_minutes":{"anyOf":[{"type":"number","maximum":30.0,"minimum":0.0},{"type":"null"}],"title":"Max Minutes"}},"type":"object","required":["origins"],"title":"BlockPoisBatch"},"BlockPoisResponse":{"properties":{"block_geoid":{"type":"string","title":"Block Geoid"},"results":{"items":{"$ref":"#/components/schemas/PoiTime"},"type":"array","title":"Results"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["block_geoid","results"],"title":"BlockPoisResponse","description":"GET /v1/blocks/{geoid}/pois (routers.blocks.blocks_pois)"},"BlockSummaryBatch":{"properties":{"origins":{"items":{"type":"string"},"type":"array","title":"Origins","description":"Census block GEOIDs (1-250)"},"mode":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Mode","description":"Travel modes; default all"},"type":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Type","description":"Destination type ids; default all"}},"type":"object","required":["origins"],"title":"BlockSummaryBatch"},"BlockSummaryResponse":{"properties":{"block":{"$ref":"#/components/schemas/BlockMeta"},"results":{"items":{"$ref":"#/components/schemas/CategoryTime"},"type":"array","title":"Results"}},"type":"object","required":["block","results"],"title":"BlockSummaryResponse","description":"GET /v1/blocks/{geoid}/summary (routers.blocks.blocks_summary)"},"BlocksQuery":{"properties":{"polygon":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Polygon","description":"GeoJSON Polygon or MultiPolygon geometry"},"center":{"anyOf":[{"$ref":"#/components/schemas/Center"},{"type":"null"}]},"radius_m":{"anyOf":[{"type":"number","maximum":28000.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Radius M"},"type":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Type"},"mode":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Mode"},"include_population":{"type":"boolean","title":"Include Population","default":false},"limit":{"anyOf":[{"type":"integer","maximum":1000.0,"minimum":1.0},{"type":"null"}],"title":"Limit"},"cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},"type":"object","title":"BlocksQuery"},"CatchmentBatch":{"properties":{"dest_ids":{"items":{"type":"integer"},"type":"array","title":"Dest Ids","description":"POI destination ids (1-250)"},"mode":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Mode"},"block":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Block"},"max_minutes":{"anyOf":[{"type":"number","maximum":30.0,"minimum":0.0},{"type":"null"}],"title":"Max Minutes"}},"type":"object","required":["dest_ids"],"title":"CatchmentBatch"},"CatchmentResponse":{"properties":{"dest_id":{"type":"integer","title":"Dest Id"},"results":{"items":{"$ref":"#/components/schemas/CatchmentResult"},"type":"array","title":"Results"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["dest_id","results"],"title":"CatchmentResponse"},"CatchmentResult":{"properties":{"geoid":{"type":"string","title":"Geoid"},"mode":{"type":"string","title":"Mode"},"travel_time":{"type":"number","title":"Travel Time","description":"Minutes, 1 decimal"}},"type":"object","required":["geoid","mode","travel_time"],"title":"CatchmentResult","description":"One block that can reach the POI, by mode. (shape.shape_catchment)"},"CategoryTime":{"properties":{"dest_type_id":{"type":"integer","title":"Dest Type Id"},"mode":{"type":"string","title":"Mode","description":"Travel mode label, e.g. 'walk'"},"travel_time":{"type":"number","title":"Travel Time","description":"Minutes, capped at 30, 1 decimal"}},"type":"object","required":["dest_type_id","mode","travel_time"],"title":"CategoryTime","description":"Fastest travel time to one destination category by one mode.\n(shape.shape_summary)"},"Center":{"properties":{"lon":{"type":"number","maximum":180.0,"minimum":-180.0,"title":"Lon"},"lat":{"type":"number","maximum":90.0,"minimum":-90.0,"title":"Lat"}},"type":"object","required":["lon","lat"],"title":"Center"},"ClosePlusPlan":{"properties":{"id":{"type":"string","title":"Id","examples":["close_plus"]},"name":{"type":"string","title":"Name"},"price_usd_per_month":{"type":"integer","title":"Price Usd Per Month","examples":[10]},"price_display":{"type":"string","title":"Price Display","examples":["$10/month"]},"tokens_granted_each_paid_month":{"type":"integer","title":"Tokens Granted Each Paid Month"},"map_destination_types_at_once":{"type":"integer","title":"Map Destination Types At Once"},"saved_maps":{"type":"integer","title":"Saved Maps"},"property_reports_per_day":{"type":"integer","title":"Property Reports Per Day"},"subscribe_url":{"type":"string","title":"Subscribe Url","description":"Close+ landing page; agents see the docs for the checkout-URL flow"},"refund_policy":{"type":"string","title":"Refund Policy"},"cancellation":{"type":"string","title":"Cancellation"}},"type":"object","required":["id","name","price_usd_per_month","price_display","tokens_granted_each_paid_month","map_destination_types_at_once","saved_maps","property_reports_per_day","subscribe_url","refund_policy","cancellation"],"title":"ClosePlusPlan","description":"The Close+ membership. (routers.meta.plans)"},"DestinationType":{"properties":{"dest_type_id":{"type":"integer","title":"Dest Type Id"},"name":{"type":"string","title":"Name"},"label":{"type":"string","title":"Label"},"is_leaf":{"type":"boolean","title":"Is Leaf"},"leaf_ids":{"items":{"type":"integer"},"type":"array","title":"Leaf Ids","description":"Leaf type ids this node expands to in travel-time filters"}},"type":"object","required":["dest_type_id","name","label","is_leaf","leaf_ids"],"title":"DestinationType","description":"One node in the destination-type taxonomy.\n(routers.meta.meta_destination_types)"},"DestinationTypesResponse":{"properties":{"destination_types":{"items":{"$ref":"#/components/schemas/DestinationType"},"type":"array","title":"Destination Types"}},"type":"object","required":["destination_types"],"title":"DestinationTypesResponse"},"FreePlan":{"properties":{"id":{"type":"string","title":"Id","examples":["free"]},"name":{"type":"string","title":"Name"},"price_usd_per_month":{"type":"integer","title":"Price Usd Per Month","examples":[0]},"card_required":{"type":"boolean","title":"Card Required"},"signup_grant_tokens":{"type":"integer","title":"Signup Grant Tokens","description":"One-time API token grant on first sign-in"},"map_destination_types_at_once":{"type":"integer","title":"Map Destination Types At Once"},"sign_up":{"$ref":"#/components/schemas/PlanSignup"}},"type":"object","required":["id","name","price_usd_per_month","card_required","signup_grant_tokens","map_destination_types_at_once","sign_up"],"title":"FreePlan","description":"The free tier. (routers.meta.plans)"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status","examples":["ok"]},"version":{"type":"string","title":"Version","examples":["0.1.0"]}},"type":"object","required":["status","version"],"title":"HealthResponse","description":"GET /v1/health (routers.health.health)"},"IsochroneAssumptions":{"properties":{"transit_departure":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transit Departure","examples":["2026-07-15T08:00:00"]},"transit_window_min":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Transit Window Min","examples":[60]},"transit_percentile":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Transit Percentile","examples":[10]},"max_trip_duration_min":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Trip Duration Min","examples":[60]}},"additionalProperties":true,"type":"object","title":"IsochroneAssumptions","description":"Routing assumptions echoed from the store. Keys are store-defined; the\ncurrent set is listed but extra keys are allowed. (routers.isochrone._assumptions)"},"IsochroneBlock":{"properties":{"geoid":{"type":"string","title":"Geoid"},"travel_min":{"type":"integer","title":"Travel Min"}},"type":"object","required":["geoid","travel_min"],"title":"IsochroneBlock"},"IsochroneBlocks":{"properties":{"blocks":{"items":{"$ref":"#/components/schemas/IsochroneBlock"},"type":"array","title":"Blocks"},"reachable_blocks":{"type":"integer","title":"Reachable Blocks"},"block":{"type":"string","title":"Block"},"direction":{"type":"string","title":"Direction"},"mode":{"type":"string","title":"Mode"},"version":{"type":"string","title":"Version"},"assumptions":{"$ref":"#/components/schemas/IsochroneAssumptions"},"v":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"V"}},"type":"object","required":["blocks","reachable_blocks","block","direction","mode","version","assumptions"],"title":"IsochroneBlocks","description":"GET /v1/isochrone?format=blocks (routers.isochrone._blocks_body)."},"IsochroneFeature":{"properties":{"type":{"type":"string","title":"Type","examples":["Feature"]},"geometry":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Geometry","description":"GeoJSON geometry, or null when the contour is empty"},"properties":{"$ref":"#/components/schemas/IsochroneFeatureProperties"}},"type":"object","required":["type","properties"],"title":"IsochroneFeature"},"IsochroneFeatureProperties":{"properties":{"contour":{"type":"integer","title":"Contour","description":"Contour level in minutes"},"mode":{"type":"string","title":"Mode"},"reachable_blocks":{"type":"integer","title":"Reachable Blocks"}},"type":"object","required":["contour","mode","reachable_blocks"],"title":"IsochroneFeatureProperties"},"IsochroneGeoJSON":{"properties":{"type":{"type":"string","title":"Type","examples":["FeatureCollection"]},"features":{"items":{"$ref":"#/components/schemas/IsochroneFeature"},"type":"array","title":"Features"},"block":{"type":"string","title":"Block","description":"15-digit origin/destination block GEOID"},"direction":{"type":"string","title":"Direction","description":"'to' or 'from'"},"mode":{"type":"string","title":"Mode"},"version":{"type":"string","title":"Version","description":"Store version key"},"assumptions":{"$ref":"#/components/schemas/IsochroneAssumptions"},"v":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"V","description":"Echoed cache-buster, when supplied"}},"type":"object","required":["type","features","block","direction","mode","version","assumptions"],"title":"IsochroneGeoJSON","description":"GET /v1/isochrone?format=geojson (routers.isochrone._geojson_body).\nFeatures are ordered largest contour first (painter's order)."},"IsochroneMetaResponse":{"properties":{"version":{"type":"string","title":"Version"},"directions":{"items":{"type":"string"},"type":"array","title":"Directions","examples":[["to","from"]]},"modes":{"items":{"type":"string"},"type":"array","title":"Modes","examples":[["walk","bike","transit"]]},"max_minutes":{"type":"integer","title":"Max Minutes","examples":[60]},"dest_set":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dest Set"},"assumptions":{"$ref":"#/components/schemas/IsochroneAssumptions"}},"type":"object","required":["version","directions","modes","max_minutes","assumptions"],"title":"IsochroneMetaResponse","description":"GET /v1/isochrone/meta (routers.isochrone.get_isochrone_meta)"},"LastUpdatedResponse":{"properties":{"last_updated":{"type":"string","title":"Last Updated","description":"ISO-8601 timestamp of the newest published component","examples":["2026-07-01T00:00:00+00:00"]}},"type":"object","required":["last_updated"],"title":"LastUpdatedResponse","description":"GET /v1/last-updated (routers.meta.last_updated)"},"ModeItem":{"properties":{"mode_id":{"type":"integer","title":"Mode Id"},"mode":{"type":"string","title":"Mode","description":"Short label","examples":["walk"]},"description":{"type":"string","title":"Description","examples":["Walking"]}},"type":"object","required":["mode_id","mode","description"],"title":"ModeItem","description":"One travel mode. (routers.meta._modes)"},"ModesResponse":{"properties":{"modes":{"items":{"$ref":"#/components/schemas/ModeItem"},"type":"array","title":"Modes"}},"type":"object","required":["modes"],"title":"ModesResponse"},"OriginError":{"properties":{"type":{"type":"string","title":"Type","description":"Error slug: block-not-found, no-block-data, point-not-covered, or poi-not-found"},"detail":{"type":"string","title":"Detail"}},"additionalProperties":true,"type":"object","required":["type","detail"],"title":"OriginError","description":"One origin that could not be resolved in a batch call. Extra members\ncarry the origin key: `geoid` (blocks), `origin_lat`/`origin_lon` (points),\nor `dest_id` (catchment). (routers.batch)"},"Place":{"properties":{"name":{"type":"string","title":"Name"},"geoid":{"type":"string","title":"Geoid","description":"Census place GEOID"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State","description":"Two-letter USPS state abbreviation (e.g. 'RI')"},"lon":{"type":"number","title":"Lon","description":"Centroid longitude (WGS84)"},"lat":{"type":"number","title":"Lat","description":"Centroid latitude (WGS84)"}},"type":"object","required":["name","geoid","lon","lat"],"title":"Place","description":"A census place (city/town) matched by name, with its GEOID and WGS84\ncentroid. (routers.places.places)"},"PlaceBoundary":{"properties":{"type":{"type":"string","title":"Type","examples":["Feature"]},"geometry":{"additionalProperties":true,"type":"object","title":"Geometry","description":"GeoJSON Polygon/MultiPolygon"},"properties":{"$ref":"#/components/schemas/PlaceBoundaryProperties"}},"type":"object","required":["type","geometry","properties"],"title":"PlaceBoundary","description":"GET /v1/places/{geoid}/boundary (routers.spatial.place_boundary). The\ncensus place's boundary as a GeoJSON Feature (WGS84, lightly simplified for\ndisplay). Free (no API key)."},"PlaceBoundaryProperties":{"properties":{"geoid":{"type":"string","title":"Geoid","description":"Census place GEOID"}},"type":"object","required":["geoid"],"title":"PlaceBoundaryProperties"},"PlacesResponse":{"properties":{"places":{"items":{"$ref":"#/components/schemas/Place"},"type":"array","title":"Places"}},"type":"object","required":["places"],"title":"PlacesResponse"},"PlanSignup":{"properties":{"portal":{"type":"string","title":"Portal","description":"Account portal (browser sign-up)"},"agent_guide":{"type":"string","title":"Agent Guide","description":"Programmatic sign-up guide for API clients and agents"},"mcp":{"type":"string","title":"Mcp","description":"MCP server with in-chat sign-up tools"}},"type":"object","required":["portal","agent_guide","mcp"],"title":"PlanSignup","description":"Sign-up pointers for the free tier. (routers.meta.plans)"},"PlansResponse":{"properties":{"plans":{"items":{"anyOf":[{"$ref":"#/components/schemas/FreePlan"},{"$ref":"#/components/schemas/ClosePlusPlan"}]},"type":"array","title":"Plans"},"token_packs":{"items":{"$ref":"#/components/schemas/TokenPack"},"type":"array","title":"Token Packs"},"terms":{"type":"string","title":"Terms"},"billing_details":{"type":"string","title":"Billing Details"}},"type":"object","required":["plans","token_packs","terms","billing_details"],"title":"PlansResponse","description":"GET /v1/plans (routers.meta.plans)"},"PoiDetail":{"properties":{"dest_id":{"type":"integer","title":"Dest Id"},"name":{"type":"string","title":"Name"},"lon":{"type":"number","title":"Lon"},"lat":{"type":"number","title":"Lat"},"address":{"$ref":"#/components/schemas/Address"},"type_ids":{"items":{"type":"integer"},"type":"array","title":"Type Ids"},"attrs":{"additionalProperties":true,"type":"object","title":"Attrs","description":"Whitelisted attributes (currently only 'brand', when present)"}},"type":"object","required":["dest_id","name","lon","lat","address","type_ids","attrs"],"title":"PoiDetail","description":"GET /v1/pois/{dest_id} (queries.pois.detail)"},"PoiSearchResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/PoiSearchResult"},"type":"array","title":"Results"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque keyset cursor; null on the last page"}},"type":"object","required":["results"],"title":"PoiSearchResponse"},"PoiSearchResult":{"properties":{"dest_id":{"type":"integer","title":"Dest Id"},"name":{"type":"string","title":"Name"},"lon":{"type":"number","title":"Lon"},"lat":{"type":"number","title":"Lat"},"address":{"$ref":"#/components/schemas/Address"}},"type":"object","required":["dest_id","name","lon","lat","address"],"title":"PoiSearchResult","description":"A POI search hit. NOTE: no mode/travel_time here (search is spatial, not\nrouted). (routers.pois.poi_search)"},"PoiTime":{"properties":{"dest_id":{"type":"integer","title":"Dest Id"},"mode":{"type":"string","title":"Mode"},"travel_time":{"type":"number","title":"Travel Time","description":"Minutes, capped at 30, 1 decimal"},"name":{"type":"string","title":"Name"},"lon":{"type":"number","title":"Lon"},"lat":{"type":"number","title":"Lat"},"address":{"$ref":"#/components/schemas/Address"}},"type":"object","required":["dest_id","mode","travel_time","name","lon","lat","address"],"title":"PoiTime","description":"One POI reachable from an origin, with its travel time. (shape.shape_pois)"},"PointOrigin":{"properties":{"lon":{"type":"number","maximum":180.0,"minimum":-180.0,"title":"Lon"},"lat":{"type":"number","maximum":90.0,"minimum":-90.0,"title":"Lat"}},"type":"object","required":["lon","lat"],"title":"PointOrigin"},"PointOriginKey":{"properties":{"origin_lat":{"type":"number","title":"Origin Lat"},"origin_lon":{"type":"number","title":"Origin Lon"}},"type":"object","required":["origin_lat","origin_lon"],"title":"PointOriginKey","description":"The lat/lon that identifies a point origin in a batch. (routers.batch)"},"PointPoisBatch":{"properties":{"origins":{"items":{"$ref":"#/components/schemas/PointOrigin"},"type":"array","title":"Origins","description":"Origin lat/lon points (1-250)"},"mode":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Mode"},"type":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Type"},"dest_id":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Dest Id"},"max_minutes":{"anyOf":[{"type":"number","maximum":30.0,"minimum":0.0},{"type":"null"}],"title":"Max Minutes"}},"type":"object","required":["origins"],"title":"PointPoisBatch"},"PointPoisMeta":{"properties":{"origin_lat":{"type":"number","title":"Origin Lat"},"origin_lon":{"type":"number","title":"Origin Lon"},"resolved_block":{"type":"string","title":"Resolved Block","description":"GEOID of the block containing the point"}},"type":"object","required":["origin_lat","origin_lon","resolved_block"],"title":"PointPoisMeta","description":"Per-origin resolved block for POST /v1/point/pois. (routers.batch)"},"PointPoisResponse":{"properties":{"resolved_block":{"type":"string","title":"Resolved Block"},"results":{"items":{"$ref":"#/components/schemas/PoiTime"},"type":"array","title":"Results"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["resolved_block","results"],"title":"PointPoisResponse","description":"GET /v1/point/pois (routers.point.point_pois)"},"PointSummaryBatch":{"properties":{"origins":{"items":{"$ref":"#/components/schemas/PointOrigin"},"type":"array","title":"Origins","description":"Origin lat/lon points (1-250)"},"mode":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Mode"},"type":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Type"}},"type":"object","required":["origins"],"title":"PointSummaryBatch"},"PointSummaryMeta":{"properties":{"origin_lat":{"type":"number","title":"Origin Lat"},"origin_lon":{"type":"number","title":"Origin Lon"},"resolved_block":{"type":"string","title":"Resolved Block","description":"GEOID of the block containing the point"},"population":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Population"},"land_area_m2":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Land Area M2"}},"type":"object","required":["origin_lat","origin_lon","resolved_block"],"title":"PointSummaryMeta","description":"Per-origin block metadata for POST /v1/point/summary. (routers.batch)"},"PointSummaryResponse":{"properties":{"resolved_block":{"type":"string","title":"Resolved Block","description":"GEOID of the block containing the point"},"block":{"$ref":"#/components/schemas/BlockMeta"},"results":{"items":{"$ref":"#/components/schemas/CategoryTime"},"type":"array","title":"Results"}},"type":"object","required":["resolved_block","block","results"],"title":"PointSummaryResponse","description":"GET /v1/point/summary (routers.point.point_summary)"},"Problem":{"properties":{"type":{"type":"string","title":"Type","description":"Problem type URI; the final path segment is the stable slug","examples":["https://api.close.city/problems/not-found"]},"title":{"type":"string","title":"Title"},"status":{"type":"integer","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail"}},"additionalProperties":true,"type":"object","required":["type","title","status"],"title":"Problem","description":"RFC 9457 problem detail. Served as `application/problem+json`. Additional\nmembers appear for some problem types (e.g. `errors`). (core.problems.problem)"},"TokenPack":{"properties":{"tokens":{"type":"integer","title":"Tokens"},"purchase_url":{"type":"string","title":"Purchase Url"}},"type":"object","required":["tokens","purchase_url"],"title":"TokenPack","description":"A one-time token purchase. (routers.meta.plans)"},"TokensResponse":{"properties":{"tokens_remaining":{"type":"integer","title":"Tokens Remaining","description":"Current prepaid token balance of the key's account"}},"type":"object","required":["tokens_remaining"],"title":"TokensResponse","description":"GET /v1/tokens (routers.tokens.token_balance)"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"ValidationErrorItem":{"properties":{"loc":{"items":{},"type":"array","title":"Loc"},"msg":{"type":"string","title":"Msg"},"type":{"type":"string","title":"Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationErrorItem"},"ValidationProblem":{"properties":{"type":{"type":"string","title":"Type","description":"Problem type URI; the final path segment is the stable slug","examples":["https://api.close.city/problems/not-found"]},"title":{"type":"string","title":"Title"},"status":{"type":"integer","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail"},"errors":{"anyOf":[{"items":{"$ref":"#/components/schemas/ValidationErrorItem"},"type":"array"},{"type":"null"}],"title":"Errors"}},"additionalProperties":true,"type":"object","required":["type","title","status"],"title":"ValidationProblem","description":"400 invalid-parameters, carrying the offending fields.\n(core.problems, RequestValidationError handler)"},"VintageComponent":{"properties":{"component":{"type":"string","title":"Component","description":"road_network | transit_network | pois | blocks | parks"},"version":{"type":"string","title":"Version"},"effective_date":{"type":"string","title":"Effective Date","description":"ISO date","examples":["2026-05-01"]}},"type":"object","required":["component","version","effective_date"],"title":"VintageComponent","description":"One dataset component's active version. (routers.meta.meta_vintage)"},"VintageResponse":{"properties":{"components":{"items":{"$ref":"#/components/schemas/VintageComponent"},"type":"array","title":"Components"}},"type":"object","required":["components"],"title":"VintageResponse"}},"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"API key as a Bearer token. Create a free key at https://account.close.city (5,000 free tokens on signup, no card). Agents can complete sign-up programmatically. See https://docs.close.city."},"sessionCookie":{"type":"apiKey","in":"cookie","name":"__Host-wtm_session","description":"Portal session cookie, set by POST /auth/verify-code. State-changing portal routes also require the session's CSRF token (from GET /auth/csrf) in an X-CSRF-Token header."}}},"servers":[{"url":"https://api.close.city"}]}