Regions
An OctetRegion is the area you ask about (country, city, disc, polygon, bounding box), and its shape determines how the SDK proves containment.
Why the taxonomy looks the way it does
Different region shapes are verified by different evidence. A country is best proven via the device's mobile country code; the SIM and the serving cell tower both name a country. A disc needs a real GPS fix and can fall back to inertial signals. A city resolves to a polygon set under the hood. Letting callers supply a free-form lat/lon polygon would force the SDK to triangulate and re-quantize every query, which interacts badly with the H3-based proof machinery. Polygons are therefore accepted only as H3 cell sets.
The shapes
| Factory | Verified via | Typical use |
|---|---|---|
earth(maxAltitudeMeters) | Always YES. | Sanity check / fallback. |
country(isoCode) | Fused MCC from serving cell, network operator, SIM home country. | "Is the user in the US?" Works indoors, often without GPS. |
subdivision(isoCode) | Reverse-geocoded admin area on a trusted fix; multi-signal estimator as fallback. | ISO 3166-2 codes: US-CA, FR-75, JP-13. |
usState(stateCode) | Same as subdivision. | Sugar for subdivision("US-XX"). |
city(name) | SDK resolves the name to an H3 polygon set; proof is verified against that polygon. | "Is the user in San Francisco?" |
disc(center, radiusMeters) | H3-rasterized inside the proof; analytic on the caller side. | "Is the device within 250 m of a saved anchor point?" |
ellipse(center, semiMajorM, semiMinorM, headingDeg) | 2D ground ellipse. Disc is a special case. | GNSS uncertainty ellipses, oriented zones. |
box3D(latRange, lonRange, altRange) | 3D bounding box. | Volumetric containment, building floors. |
polygonSet(cells) | Union of H3 cells. | Custom geofences pre-quantized to H3. |
All factories validate eagerly. Invalid lat/lon, malformed ISO codes, non-positive radii, ellipse axes out of order: all trap at construction. An invalid region never reaches a predicate call.
Why polygons are H3-only
If you have a free-form polygon (a delivery zone, an event venue, a building footprint), you (or your tooling) quantize it to H3 cells ahead of time and pass the cell list. The SDK then uses those cells directly in the proof's Merkle membership circuit. No on-the-fly triangulation. No precision drift. No caller-supplied geometry slipping into the proof.
The H3 cell ID encodes its own resolution. The SDK picks the coarsest resolution per query that still satisfies the predicate's accuracy needs. Fine cells when you ask about a city block, coarse cells when you ask about a city.
Construction helpers (Android only)
On Android, two additional surfaces let you build regions dynamically:
getRegion(RegionSpec.country("US")). Symbolic lookup, useful when the region name comes from configuration or a server response. Thecity/namedZonevariants currently throwOctetFutureFlag(atlas + server lookup is not yet wired).buildRegion { disc(center = LatLon(37.42, -122.08), radiusMeters = 250.0) }. DSL sugar over the static factories, ergonomic for assembling regions from runtime data.
iOS exposes the static factories only at v1. Platform parity for the DSL and RegionSpec is on the roadmap.
Inspecting a region
Two helpers turn a region into a string:
whatisRegion(r). Short, human-readable. For log lines and debug overlays. Not stable across SDK versions.regionToStr(r). Canonical, machine-readable, stable wire form. Suitable for log diffs, idempotency keys, eventualregionFromStrround-trip.
Both are surfaced uniformly on every API object via .toStr(), .toJson(), and .toJsonl(). See Serialization.
Where to go next
- OctetRegion API Reference for the exact signatures and validation rules.
- Verdicts for what happens when the cached proof's region is coarser than your query.