Web API
OGC web services (WMS, WFS, WMTS) and ArcGIS REST services for tile rendering and per-parcel attribute lookup.
The dataset is also made available to customers as OGC (WMS, WFS, etc) web services, and as ArcGIS REST services for ArcGIS Online, ArcGIS Pro and the ArcGIS SDKs.
Every data endpoint takes the API token issued after signup, either as
Authorization: Bearer <TOKEN> or as a ?token=<TOKEN> query parameter. GetCapabilities,
DescribeFeatureType and GetLegendGraphic are public and unmetered — they describe the
service rather than return parcel data. Everything else except raster tiles counts against your
plan; see Usage and limits.
Tile URL patterns
Two URL shapes serve the same tiles, and they differ in how they count rows:
| Route | y origin |
Use it from |
|---|---|---|
https://api.landrecords.us/pro:parcel_us@EPSG:3857x2@pbf/{z}/{x}/{y}.pbf |
XYZ, top-left | QGIS, ArcGIS, Leaflet, OpenLayers, any plain XYZ client |
https://api.landrecords.us/pro:parcel_us@EPSG:3857x2@png8/{z}/{x}/{y}.png8 |
XYZ, top-left | same |
https://api.landrecords.us/pro/gwc/service/tms/1.0.0/pro:parcel_us@EPSG:3857x2@png8/{z}/{x}/{y}.png8 |
TMS, bottom-left | clients configured for TMS (MapLibre scheme: 'tms') |
Use plain {y} on both — there is no {-y} form. The route already decides the convention,
so flipping y on top of it asks for a tile 2×|latitude| away, which is usually open water.
When in doubt, use the bare (non-/gwc/service/tms/) paths: that is what our WMTS
GetCapabilities advertises as its ResourceURL templates.
Tiles are also served under EPSG:900913 (EPSG:900913x2). There is no EPSG:4326 grid set, so
connect with EPSG:3857 or EPSG:900913 only. All raster tiles are 512×512 px.
Fun fact: this is the same service that powers our data explorer! It is a MapLibre source configured like so:
yourAuthToken = ...;
map.current = new maplibregl.Map({
style: {
version: 8,
sources: {
parcel_us: {
type: 'raster',
scheme: 'tms',
tiles: ['https://api.landrecords.us/pro/gwc/service/tms/1.0.0/pro:parcel_us@EPSG:3857x2@png8/{z}/{x}/{y}.png8'],
tileSize: 512
}
}
},
transformRequest: (url, resourceType) => {
if (resourceType === 'Tile' && url.startsWith('https://api.landrecords.us')) {
return {
url: url,
headers: { 'Authorization': 'Bearer ' + yourAuthToken }
}
}
}
});Drop scheme: 'tms' and point the same source at the bare
https://api.landrecords.us/pro:parcel_us@EPSG:3857x2@png8/{z}/{x}/{y}.png8 path to get the
identical tiles over the XYZ convention. For a vector source, use type: 'vector' with the
@pbf path — parcel attributes travel inside the tile, so hover, highlight and labels resolve
client-side with no round trip.
Vector tile attributes
Every parcel vector tile (@pbf) holds a single layer named parcels, with one polygon
feature per parcel. Each feature carries the same 28 attributes at every zoom, from z10 to
z16 (overscaled zooms reuse z16's features):
| Attribute | Type | Description |
|---|---|---|
lrid |
String | Land Records' UUID for the parcel — the key for looking it up. |
geoid |
String | 5-digit county FIPS: statefp followed by countyfp. |
statefp |
String | State FIPS code. |
countyfp |
String | County FIPS code. |
cousubfp |
String | County subdivision FIPS code. |
placefp |
String | Census place FIPS code of the place containing the parcel's centroid; prefix statefp for the 7-digit place GEOID. |
placetype |
String | Type of place. |
parceladdr |
String | Physical street address. |
parcelcity |
String | City the parcel is in. |
parcelstate |
String | State the parcel is in. |
ownername |
String | Name of the recorded owner. |
ownertype |
String | Type of owner. |
parceltype |
String | Type of parcel. |
accesstype |
String | Type of access. |
usecode |
String | Land use code, as the county records it. |
naicscode |
String | North American Industry Classification System (NAICS) code. |
zoningcode |
String | Zoning code. |
landvalue |
Number | Assessed value of the land alone. |
imprvalue |
Number | Assessed value of improvements (buildings). |
totalvalue |
Number | Total assessed value. |
calcarea |
Number | Area of the parcel polygon, in square metres. |
centroidx, centroidy |
Number | Longitude and latitude of the parcel's geographic center (EPSG:4326). Can fall outside a C-shaped parcel. |
surfpointx, surfpointy |
Number | Longitude and latitude of a point guaranteed to lie inside the parcel — the one to put a label or marker on. |
elevmin, elevavg, elevmax |
Number | Minimum, average and maximum elevation across the parcel. |
The full definitions are in the Table Schema. A few things to know when you read them out of a tile:
- Empty attributes are left out, not sent as
null. A parcel with no recorded zoning has nozoningcodekey at all, so test for the key's presence. - Features have no vector-tile
id. Uselridas the identity — in MapLibre, setpromoteId: 'lrid'on the source to drivefeature-statehover and selection. - Everything else is one lookup away. Tiles carry this subset of the published attributes;
parcelid,usedesc,yearbuilt,bldgsqftand the rest come back from a lookup bylrid. - Low-zoom tiles are heavy. Every parcel keeps every attribute down to z10, so a z10 tile over a dense metro runs to tens of megabytes. For display at low zooms, use the raster tiles and switch to vector around z14.
- Canadian tiles (
pro:parcel_ca, onapi.landrecords.ca) carry the same layer withoutaccesstype,elevmin/elevavg/elevmax,naicscode,ownertype,parceltypeandplacefp, and start at z12.
map.addSource('parcels', {
type: 'vector',
tiles: ['https://api.landrecords.us/pro:parcel_us@EPSG:3857x2@pbf/{z}/{x}/{y}.pbf'],
minzoom: 10,
maxzoom: 16,
promoteId: 'lrid'
});
map.addLayer({
id: 'parcel-lines',
type: 'line',
source: 'parcels',
'source-layer': 'parcels',
paint: { 'line-color': '#2F7A2F', 'line-width': 0.5 }
});Authenticate the source with the same transformRequest as the raster example above.
Parcel Coverage Map Service
We publish our coverage map as a web service for use in your applications. This is the same service that powers our public website at http://landrecords.us/products. It contains information about parcel coverage, as well as coverage for selected attributes.
- County Coverages:
https://api.landrecords.us/pro:county_coverage@EPSG:3857x2@pbf/{z}/{x}/{y}.pbf?token=<TOKEN> - State Coverages:
https://api.landrecords.us/pro:state_coverage@EPSG:3857x2@pbf/{z}/{x}/{y}.pbf?token=<TOKEN>
Both coverage layers are vector-only, and both are also reachable over the TMS route
(/pro/gwc/service/tms/1.0.0/…) with bottom-left rows.
QGIS: Configure in a WMS/WMTS Connection
You can easily load the Nationwide Parcel layer into QGIS.
First, Create a New WMS/WMTS Connection.

Then configure the new connection by pointing to the Landrecords API endpoint (api.landrecords.us), and setting the Authorization token provided after signup:
https://api.landrecords.us/pro/gwc/service/wmts
https://api.landrecords.us/pro/wms

Now you will see all the layers available to you in the Browser:

The WMTS document publishes pro:parcel_us, pro:state_coverage and pro:county_coverage
over the EPSG:3857x2 and EPSG:900913x2 tile matrix sets, in both
application/vnd.mapbox-vector-tile and image/png8.
QGIS: Configure in an XYZ / Vector Tiles Connection
Create a new XYZ Connection (for raster) or Vector Tiles Connection (for MVT):

Configure the connection with the Landrecords API endpoint. Use the standard {z}/{x}/{y}
ordering — QGIS's {-y} flip is not wanted here, because these paths already serve
top-left rows.
https://api.landrecords.us/pro:parcel_us@EPSG:3857x2@pbf/{z}/{x}/{y}.pbf
https://api.landrecords.us/pro:parcel_us@EPSG:3857x2@png8/{z}/{x}/{y}.png8Tile zoom ranges
The parcel layer has data from zoom 10 upward, for both vector and raster tiles (Canadian tiles from z12):
| Layer | Served zooms | Notes |
|---|---|---|
Raster (png8) |
z10–z22 | Zoom <10 → 404 (nothing renders there). Above z16, tiles are re-rendered from their parent tile; high zooms (≥18) are rendered on demand and never persisted — they carry a 14-day browser cache header instead of being served as static objects, so they re-render across sessions. |
Vector (pbf) |
native z10–z16, overscaled above | Zoom >16 returns geometry scaled up from its parent tile; <10 → 404. |
Requesting a zoom outside these ranges returns a 404, never an empty tile — a transparent
tile is indistinguishable from correctly rendered empty ocean, and would hide a client-side
coordinate bug behind pixels that look fine. Served tiles are cached 14 days and marked
immutable; a 404/204 is cached only one hour.

Set the Authorization header to include the API key that was provided to you after signing up for the hosted web service.

Click Save, and now you’re ready to add this layer to your project.
ArcGIS REST services
The parcel layers are also published the way ArcGIS Server publishes a layer, so ArcGIS Online,
ArcGIS Pro and the ArcGIS Maps SDK for JavaScript add them by URL like any other Esri service. The
services directory is https://api.landrecords.us/arcgis/rest/services (the same services answer
on api.landrecords.ca), and each country is published three ways:
| Service | URL | Use it for |
|---|---|---|
| FeatureServer | https://api.landrecords.us/arcgis/rest/services/parcel_us/FeatureServer |
Popups, attribute tables, filters and queries. Draws from about 1:18,000 (z15) in. |
| MapServer | https://api.landrecords.us/arcgis/rest/services/parcel_us/MapServer |
Parcels at every scale as image tiles, plus export, identify and find. |
| VectorTileServer | https://api.landrecords.us/arcgis/rest/services/parcel_us/VectorTileServer |
The vector tiles, styled as parcel outlines. |
Use parcel_ca in place of parcel_us for Canadian parcels, on a plan that includes Canada.
They are the same data, plans and meters as the OGC routes above, not a second copy.
Signing in
ArcGIS clients sign in through the server's token endpoint: enter any user name and your API
key as the password. The token that comes back is your key, so there is no second credential to
manage, and disabling the key ends every session made with it. Scripts can skip sign-in and pass
token=<TOKEN>, Authorization: Bearer <TOKEN> or X-Esri-Authorization: Bearer <TOKEN>.
- ArcGIS Online Map Viewer: Add → Add layer from URL, paste a service URL, and sign in when asked. Use the VectorTileServer or MapServer to show parcels at every scale and the FeatureServer for popups and the attribute table.
- ArcGIS Pro: Insert → Connections → New ArcGIS Server, or Add Data From Path with a service URL. The feature layer needs ArcGIS Pro 3.2 or later, the first release that reads 64-bit object ids.
- QGIS: Layer → Add Layer → Add ArcGIS REST Server Layer, with the directory URL and a Basic authentication (any user name, your key as the password). Use the MapServer or VectorTileServer: QGIS reads object ids as 32-bit, so for parcel features in QGIS use the WFS.
Querying the FeatureServer
FeatureServer/0/query takes the standard ArcGIS parameters: a where clause in standard SQL
(AND/OR/NOT, comparisons, LIKE, IN, BETWEEN, IS NULL, dates), geometry with
spatialRel and distance, objectIds, outFields, outSR, orderByFields, paging of up to
2,000 features, counts, ids, extents and statistics, answered as f=json, geojson or pbf.
The five most valuable parcels in Norfolk, Virginia:
https://api.landrecords.us/arcgis/rest/services/parcel_us/FeatureServer/0/query?where=geoid%20%3D%20'51710'%20AND%20totalvalue%20%3E%2050000000&outFields=parceladdr,totalvalue&orderByFields=totalvalue%20DESC&resultRecordCount=5&returnGeometry=false&f=json&token=<TOKEN>As with the WFS search, a query has to be narrowed by something an index serves:
objectIds, or awhereon an indexed field:geoid,lrid,objectid,parcelidorparcelid2(equality or a prefixLIKE),ownertype,accesstype,placetype, or anownernamematch. These are always answered.- A geometry. Always answered. A
whereon other fields alone (totalvalue > 1000000) is answered inside a geometry of at most 100 km². - Counts, extents and statistics read up to 10,000 matches.
objectid is a 64-bit integer computed from lrid, so it is as permanent as lrid and does not
change between data loads.
On parcel_us, the FeatureServer also publishes a Building permits table (1), related to the
parcel layer through lrid, so a Map Viewer popup can list a parcel's permits.
Errors follow ArcGIS conventions: HTTP 200 with an error body whose code is 499 (no token),
498 (invalid token), 403 (not on your plan), 429 (over a limit) or 400 (a query that can't be
answered). Tiles and export images answer with real HTTP statuses instead.
Parcel Detail Lookup
In addition to the tile services described above, the full WMS and WFS endpoints let you retrieve attribute details for an individual parcel. The two typical lookup patterns are by lon/lat (e.g. a click on a rendered map) and by lrid (a direct, attribute-based lookup). The parcel feature type is pro:parcel_us, served from:
- WMS:
https://api.landrecords.us/pro/wms - WFS:
https://api.landrecords.us/pro/wfs
Both endpoints accept the same Bearer token used by the tile services. For brevity, the URL examples below use ?token=<TOKEN> so they can be pasted directly into a browser; programmatic clients should prefer the Authorization: Bearer <TOKEN> header instead.
Lookups are answered by PostGIS against the parcel polygons themselves — ST_Intersects on
geom, not a proximity guess around a centroid — so "which parcel is at this point" has one
exact answer.
Look up a parcel by lon/lat
The shortest form is our own vendor shortcut on the WFS endpoint:
https://api.landrecords.us/pro/wfs?lon=-76.2859&lat=36.8508&token=<TOKEN>WMS GetFeatureInfo identifies features at a pixel inside a GetMap-style request. Send a small bounding box around your point and query the center pixel. Note the axis order: WMS 1.3.0 with EPSG:4326 expects bbox as minLat,minLon,maxLat,maxLon (this is the most common source of bad results — flip the order and you’ll silently query the wrong place).
https://api.landrecords.us/pro/wms
?service=WMS
&version=1.3.0
&request=GetFeatureInfo
&layers=pro:parcel_us
&query_layers=pro:parcel_us
&crs=EPSG:4326
&bbox=36.8507,-76.2860,36.8509,-76.2858
&width=101&height=101
&i=50&j=50
&info_format=application/json
&feature_count=1
&token=<TOKEN>GetFeatureInfo with info_format=application/json will return a GeoJSON FeatureCollection. A click sent alongside a cql_filter is AND-ed with it — "the parcel
under the cursor, among those the filter allows" — rather than replacing it.
A point can lie in more than one parcel: on a shared boundary, or inside a stack of condo units
drawn on one footprint. numberMatched says how many parcels contain it, and startIndex
pages through them 10 at a time.
Look up a parcel by id
RESOURCEID (or its 1.1 spelling FEATUREID) fetches one feature directly:
https://api.landrecords.us/pro/wfs?request=GetFeature&resourceId=96708b9f-2f4b-398e-1c82-6fe77004432b&token=<TOKEN>resourceId also takes a comma-separated list of up to 50 ids, and the response holds up to 10
of them, so ten parcels you already know cost one request instead of ten:
https://api.landrecords.us/pro/wfs?request=GetFeature&resourceId=<LRID_1>,<LRID_2>,<LRID_3>&token=<TOKEN>cql_filter=lrid IN ('<LRID_1>','<LRID_2>') is the same lookup in filter form. Either way it is
counted as a single parcel record request (see Usage and limits).
Search an area with a bounding box
A WFS GetFeature with a bbox returns every parcel whose polygon intersects the box —
including parcels that only cross its edge, and parcels larger than the box itself:
https://api.landrecords.us/pro/wfs
?service=WFS
&version=2.0.0
&request=GetFeature
&typeNames=pro:parcel_us
&bbox=36.8500,-76.2900,36.8530,-76.2850,urn:ogc:def:crs:EPSG::4326
&count=10
&startIndex=0
&outputFormat=application/json
&token=<TOKEN>The same request with curl and header-based auth:
curl -G 'https://api.landrecords.us/pro/wfs' \
-H "Authorization: Bearer $LR_TOKEN" \
--data-urlencode 'service=WFS' \
--data-urlencode 'version=2.0.0' \
--data-urlencode 'request=GetFeature' \
--data-urlencode 'typeNames=pro:parcel_us' \
--data-urlencode 'bbox=36.8500,-76.2900,36.8530,-76.2850,urn:ogc:def:crs:EPSG::4326' \
--data-urlencode 'count=10' \
--data-urlencode 'startIndex=0' \
--data-urlencode 'outputFormat=application/json'Coordinates are WGS84 degrees, and the axis order follows WFS 2.0: EPSG:4326 is
minLat,minLon,maxLat,maxLon. Add a fifth value to make the order explicit —
urn:ogc:def:crs:EPSG::4326 for latitude first, CRS:84 for longitude first
(bbox=-76.2900,36.8500,-76.2850,36.8530,CRS:84 is the same box). Without one, the order is
inferred from the numbers, which is reliable in North America (latitudes positive, longitudes
negative) but not something to depend on. A box in projected units, such as EPSG:3857 metres,
matches nothing — convert it to degrees first.
The response is a GeoJSON FeatureCollection. Each feature's id is its lrid, its
geometry is the parcel polygon in EPSG:4326, and its properties hold the full attribute row
(every property DescribeFeatureType lists), with a centroid alongside. numberMatched is the
number of parcels in the whole box and numberReturned the number on this page.
Paging. A response holds at most 10 features. To read a whole box, repeat the request
with startIndex advanced by 10 until you have numberMatched parcels:
- Pages come back in
lridorder, the same order on every request, so pages never repeat or skip a parcel. AsortBy(e.g.sortBy=totalvalue DESC) orders the whole box first, withlridbreaking ties; a descending sort puts parcels with no value first. numberMatchedand the stable order cover filters that match up to 10,000 parcels. Past that,numberMatchedisnull(WFS's "unknown") and, without asortBy, the order is no longer guaranteed between requests — narrow the box or the filter to page through it.- Every page is a separate request against your query allowance: a box touching 45 parcels takes 5 requests. See Keeping area searches efficient.
Narrowing the box with attributes. Add a cql_filter to keep only some of the parcels in
the box; the two are AND-ed:
bbox=36.8500,-76.2900,36.8530,-76.2850,urn:ogc:def:crs:EPSG::4326&cql_filter=totalvalue > 1000000The box stands in for the indexed condition, so the filter
may use any property. It can also be written inside the filter as a BBOX predicate, in the
same axis order — cql_filter=BBOX(geom, 36.8500, -76.2900, 36.8530, -76.2850) AND totalvalue > 1000000 — where it counts toward the 3-predicate limit.
bbox cannot be combined with FILTER or resourceId; with Filter Encoding, put a
<fes:BBOX> inside the FILTER instead.
WFS GetFeature with cql_filter
The WFS endpoint accepts a cql_filter parameter to search parcels by attribute or spatial
predicate, returning hydrated GeoJSON features (polygon geometry from ST_AsGeoJSON(geom),
plus the full attribute row). Standard Filter Encoding 2.0 XML in a FILTER parameter is
supported as well, over exactly the same property set; FILTER, RESOURCEID and BBOX are
mutually exclusive, as the specification requires.
Filterable properties: every property DescribeFeatureType publishes — lrid, the 89
published parcel attributes (parcelid, ownername, totalvalue, zoningcode, parceladdr,
yearbuilt, taxacres, fldzone, …) and geom. Naming anything else is reported as a
client error rather than silently returning nothing.
Operators: =, <>, >, >=, <, <=, LIKE, ILIKE, IN, BETWEEN,
IS [NOT] NULL, combined with AND, OR and parentheses. Text comparisons on the indexed
columns are case-insensitive.
Spatial predicates, on the real parcel geometry:
- BBOX — e.g.
BBOX(geom, 37.7, -75.8, 37.9, -75.5). Returns every parcel whose polygon intersects the box, including parcels larger than the box itself. - DWITHIN — e.g.
DWITHIN(geom, POINT(-75.6 37.7), 100, meters); distance is true metres on the spheroid. - INTERSECTS with a point — e.g.
INTERSECTS(geom, POINT(-75.6 37.7)). An exact point-in-polygon test, the same one a map click uses.
One condition must be indexed
parcel_layer is 161M rows, and only these columns carry an index: lrid, parcelid,
parcelid2, ownername, geoid, ownertype, accesstype, placetype. A filter that
constrains none of them (and carries no spatial predicate) is a sequential scan that would end
in the 20-second statement timeout, so it is refused up front with an
ows:ExceptionReport naming the properties that work. One indexed condition is enough —
geoid = '51710' AND usedesc ILIKE '%single family%' is fine, because geoid drives the scan
and the rest filters it. Note that an OR is only as selective as its worst branch.
A bbox parameter, or the click of a GetFeatureInfo, sent alongside the filter counts as its
indexed condition: the spatial index drives the scan, so bbox=…&cql_filter=totalvalue > 500000 needs nothing else.
statefp and countyfp together count as a geoid. The geoid column is the
5-character county FIPS — statefp followed by countyfp — so a filter that pins both
(with = or IN, in the same AND group) is answered from the geoid index even though
neither column is indexed on its own:
statefp = '48' AND countyfp = '113' AND totalvalue > 500000works exactly like geoid = '48113' AND totalvalue > 500000. Either half alone is still
refused.
At most 3 predicates besides the county
A filter may hold at most 3 predicates, not counting conditions on geoid, statefp
or countyfp — the county anchor is free, everything else is bounded. Every predicate
counts toward the one total, including spatial predicates and every branch of an OR; an
IN (...) list or a BETWEEN is a single predicate however many values it names. So
geoid = '48113' AND totalvalue > 500000 AND yearbuilt > 2000 AND bedrooms >= 3 is at the
limit, and a fourth non-county condition is refused with an ows:ExceptionReport saying so.
A clause the parser cannot compile is likewise a 400, never silently dropped: a narrowed
filter that reports success is indistinguishable from one that was honoured.
Special cases:
ownernameis matched as full-text tokens rather than as a substring, soownername = 'SMITH JOHN'finds the name in any order andownername LIKE 'SMIT%'is a prefix search on the last token. A leading wildcard is unnecessary — token matching already means "contains".LIKEongeoidis refused; use=,IN, or aBETWEENover the 5-character county prefix.
Example request:
https://api.landrecords.us/pro/wfs?request=GetFeature&cql_filter=ownername%20LIKE%20'SMITH%25'&count=10&token=<TOKEN>Control how many features are returned with count / maxFeatures / feature_count
(default 10, hard maximum 10), and page with startIndex — see
paging above. An unfiltered GetFeature returns an
estimated numberMatched with zero features — a count, not a 161M-row download.
Other WMS operations
request=GetMapcomposites the raster pyramid into an arbitrary bbox and size (up to 4096 px per axis), for clients that want one image instead of a tile grid.request=GetLegendGraphicreturns the legend swatch.request=DescribeFeatureType&typeNames=pro:parcel_usreturns the GML 3.2 schema — the authoritative list of property names and types for both filter languages.
Usage and limits
Every successful (200) data request made with your token adds one to one of your plan's
meters, however many parcels, features or bytes it returns. Errors, CORS preflights, and the
public GetCapabilities, DescribeFeatureType and GetLegendGraphic documents are never
counted, and neither are raster tiles. Your current counts are on
Account → Subscriptions.
What each request counts as
| Meter | Shown in your account as | Counted for |
|---|---|---|
PARCEL_TILE_VECTOR |
Vector tile requests | Each vector (pbf) tile. |
PARCEL_TILE_RASTER |
Raster tile requests | Nothing. Raster (png8) tiles, ArcGIS MapServer tiles included, are not metered on any plan that includes them, so they never count against a quota. |
PARCEL_DETAILS |
Parcel record requests | Single-parcel lookups: ?lon=&lat=, WMS GetFeatureInfo, INTERSECTS(geom, POINT(…)), resourceId / featureId, and lrid = … or lrid IN (…) filters. |
PARCEL_QUERY |
Search queries (WFS / CQL) | Every other request to /pro/wfs, /pro/wms or /pro/ows: bbox searches, cql_filter and FILTER searches (BBOX, DWITHIN, attribute conditions), unfiltered GetFeature counts, and WMS GetMap images. |
mcp |
AI agent tool calls (MCP) | Each tool call to the MCP server. |
Canadian requests count on the same meters with a _CA suffix (PARCEL_QUERY_CA, …), shown in
your account with "— Canada" after the name.
ArcGIS REST requests count on the same meters:
| ArcGIS request | Meter |
|---|---|
| VectorTileServer tile | PARCEL_TILE_VECTOR |
| MapServer tile | PARCEL_TILE_RASTER (not counted) |
identify; a query by up to 10 objectIds, or at a point |
PARCEL_DETAILS |
A draw query (resultType=tile) asking only for fields the vector tiles carry |
PARCEL_TILE_VECTOR |
Any other query, count, ids, extent or statistics; find; export images |
PARCEL_QUERY |
| Service descriptions, styles, legends, the directory and sign-in | Not counted |
Parcel query limits
PARCEL_QUERY allowances by plan:
| Plan | US (PARCEL_QUERY) |
Canada (PARCEL_QUERY_CA) |
|---|---|---|
| Free Trial | 1,000 | 1,000 |
| Pro Plan | 10,000 per month | Not included |
| Pro Canada | Not included | 10,000 per month |
| Pro North America | 10,000 per month | 10,000 per month |
On a plan that doesn't include the meter, a search answers 403 with Your plan does not include this feature.; a Canadian search on a US-only plan answers with a message pointing at Pro
Canada and Pro North America instead.
Going over a limit
Every meter's counter resets at 00:05 UTC on the 1st of each month. When a key passes a meter's
allowance we add 50% more to that meter's quota for the month at no charge, and email the
address on the account to say so. The meter keeps serving up to 200% of the allowance; the
extra 50% counts toward that, it does not raise it. Past 200%, the
meter's requests answer 429 Too Many Requests until the reset — the key's other meters keep
working:
{
"error": "This key has made 20000 PARCEL_QUERY requests this month, past its limit of 15000 (10000 on its plan + 5000 added at no charge) and the 20000 that PARCEL_QUERY requests stop at. ...",
"meter": "PARCEL_QUERY",
"limit": 15000,
"ceiling": 20000,
"used": 20000,
"resets": "2026-11-01T00:05:00.000Z"
}The response's Retry-After header gives the seconds until the reset. Refused requests are not
counted. We email the address on the account when a meter reaches 80% of its allowance and
again when it passes 100% and the extra quota is added; if you regularly need more, contact us about a larger or custom plan.
Keeping area searches efficient
A request counts once whatever it returns, but returns at most 10 parcels. So:
- A bounding box costs one request per 10 parcels it touches —
⌈N ÷ 10⌉requests for N parcels. The first page'snumberMatchedtells you N before you spend the rest. - A box returns every parcel it touches, not only the ones you want. It saves requests only when the parcels you're after make up most of the box: four parcels in a block of 60 cost 6 box requests, 4 single lookups, or 1 lookup by a list of ids.
- Look up parcels you already know by id.
resourceId=<id>,<id>,…returns up to 10 known parcels per request, with no neighbours taking up the slots, and counts as one parcel record request. Use a box to discover parcels and ids to refresh them. - Narrow the box with attributes (
BBOX(…) AND …) so every page holds only parcels you'll use. - Prefer several small boxes to one large one. Each page re-runs the search over the whole
box and sorts it, so pages of a very large box are slow, and a search that runs past 20 seconds
is cancelled with a
504. - For drawing or hit-testing many parcels, use vector tiles. One tile delivers every parcel in it with the tile attributes — hundreds of parcels in a built-up z16 tile — and counts once, on the vector tile meter.
Querying from an AI assistant or agent
The same serving layer is also exposed over the Model Context Protocol at https://api.landrecords.us/mcp, so Claude — or any MCP-aware client or agent — can query parcels directly through eight structured, read-only tools instead of hand-written CQL. Authentication is the same token used above, sent as Authorization: Bearer <YOUR_TOKEN>, and MCP access is included in the Pro plan.
See the Parcel MCP Server documentation for endpoints, the tool reference, and agent examples.
Secure Parcel Layer Web Services
Visit https://landrecords.us/enterprise-web-service to learn more.