Terra MarkTerraSystem

API Documentation & Live Sandbox

JSON over HTTP, keyless, open — zero authentication required. Call any endpoint directly from JavaScript, Python, .NET, Node.js, or SQL.

Interactive API Sandbox

checking…

Select an endpoint, adjust the parameters, and execute a live request against this deployment. Nothing is mocked and nothing is stored.

Response Payload —
// Click "Execute Live API Request" to see real server response
Jump to: Conventions Errors Service Cells Areas & map data Places Administrative regions Borders

Conventions & Rules

Error Reference

CodeHTTP StatusDescription
out_of_extent422Coordinate falls outside the grid rectangle extent.
bad_resolution400Resolution out of valid range (0–14).
bad_check_character400Terra Grid Code failed checksum validation.
bad_cell400String is not a valid Terra Index String (TIS).
too_many400Polyfill request exceeds maximum cell count safety limit.

Endpoints Reference

Service

GET/v1/health

Grid identity, coverage extent, base resolution, and resolution ladder array.

curl https://terra.example.sa/v1/health
GET/v1/stats/resolution

Complete resolution facts for all 15 levels: cell area, flat-to-flat width, corner-to-corner diameter, and Kingdom cell counts. Pass optional bbox=south,west,north,east and zoom query params for viewport specific estimates.

curl "https://terra.example.sa/v1/stats/resolution?bbox=24.60,46.60,24.80,46.85&zoom=13"

Cells

POST/v1/index

Bulk index up to 10,000 coordinates in a single request. Individual failures are reported per row in the results array without failing the batch.

curl -X POST https://terra.example.sa/v1/index \
  -H "Content-Type: application/json" \
  -d '{
        "res": 8,
        "points": [
          {"id": "ORD-1", "lat": 24.6877, "lon": 46.7219},
          {"id": "ORD-2", "lat": 21.4858, "lon": 39.1925}
        ]
      }'
GET/v1/cell/<tis>

Get centre coordinate, 6 vertex boundary polygon, area in hectares, Grid Code, and full ancestor chain up to Res 0.

curl https://terra.example.sa/v1/cell/t108858156b1ffff8
GET/v1/cell/<tis>/parent?res=6

The ancestor of a cell. One level up by default; pass res for any coarser level. A Terra index carries its own ancestry in its bits, so this is arithmetic rather than a lookup.

curl "https://terra.example.sa/v1/cell/t108858156b1ffff8/parent?res=6"
GET/v1/cell/<tis>/children

The seven cells one level down, or 7n for a deeper res. A request above the batch limit is refused rather than answered with a truncated list.

curl https://terra.example.sa/v1/cell/t108858156b1ffff8/children
GET/v1/cell/<tis>/disk?k=2

Returns all cells within k steps (3k² + 3k + 1 cells). Replaces spatial radius queries with exact B-tree set lookups: WHERE terra_cell = ANY(...).

curl "https://terra.example.sa/v1/cell/t108858156b1ffff8/disk?k=2"
GET/v1/cell/<tis>/ring?k=2

Only the cells exactly k steps out — the 6k boundary of the disk, without its interior.

curl "https://terra.example.sa/v1/cell/t108858156b1ffff8/ring?k=2"
GET/v1/distance?a=<tis>&b=<tis>

Steps between two cells — not metres — with an approximate metre equivalent beside them. Both cells must share a resolution.

curl "https://terra.example.sa/v1/distance?a=t108858156b1ffff8&b=t108858156b20ffff8"
GET/v1/grid-code/<code>

Validate a Grid Code someone typed by hand and resolve it to a cell. A bad check character is a 400 and is never auto-corrected: the nearest valid code is a different place on the ground.

curl https://terra.example.sa/v1/grid-code/T08-11C1ATR5

Areas & map data

POST/v1/polyfill

Returns all covering hexagonal cells for a bounding box or GeoJSON Polygon. Assigned via center-containment.

curl -X POST https://terra.example.sa/v1/polyfill \
  -H "Content-Type: application/json" \
  -d '{"res": 8, "bbox": [24.680, 46.700, 24.690, 46.710]}'
GET/v1/map/hex?bbox=&zoom=

Hexagons covering a viewport, as GeoJSON. Resolution follows the map's zoom unless one is named. Past the draw limit it returns a count instead of geometry, so the client can say "zoom in" rather than wait on a fill nothing can render.

curl "https://terra.example.sa/v1/map/hex?bbox=24.60,46.60,24.80,46.85&zoom=13&clip=1"
GET/v1/map/tile?res=&x=&y=

One fixed tile of the grid, as GeoJSON. A cell belongs to the tile its centre falls in, so tiling a viewport neither drops a cell nor draws one twice. The answer is a constant of the grid and the boundary, so it is cached for a year — pass v=<map_version> and a boundary change re-fetches. Shapes are cut to the Kingdom: cells the border crosses come back as only their inside part, tagged clipped with inside_ha.

curl "https://terra.example.sa/v1/map/tile?res=8&x=2336&y=1234&clip=1"
GET/v1/map/ksa.geojson

The Saudi outline, simplified, for drawing beneath the grid. Land alone by default; zone=territory adds the EEZ as a second feature so the coast can be drawn solid and the sea boundary dashed, and zone=marine returns the EEZ by itself.

curl "https://terra.example.sa/v1/map/ksa.geojson?zone=territory"

Places

GET/v1/places?q=<text>

Find a province or governorate by name, in Arabic or English, and get the bounding box a map needs to frame it. id is the same code the administrative endpoints use, so a result can be applied straight back as a map filter. A place whose source archive holds no boundary is left out rather than returned without a box.

curl "https://terra.example.sa/v1/places?q=makkah&kind=governorate&limit=5"
GET/v1/places/<kind>/<id>/geometry

The outline itself, as a GeoJSON Feature — the half of the pair POST /v1/polyfill was missing, since it turns a polygon into cells and a caller asking for the cells of a province had to already hold the province. Rings are the source rings: rounded to the requested precision, never simplified.

curl "https://terra.example.sa/v1/places/province/07/geometry?precision=5"

Administrative regions

GET/v1/admin/regions?level=

The 13 provinces or the 149 governorates, with both names and the province each governorate belongs to. The relation is verified geometrically rather than trusted from the attribute table.

curl "https://terra.example.sa/v1/admin/regions?level=governorate"
GET/v1/cell/<tis>/admin

The administrative context of a cell, aggregated over its Res 8 descendants: the primary region, a purity share, the unassigned share for ground in no unit at all, and the full mix. A distribution, never a bare id.

curl https://terra.example.sa/v1/cell/t10444b01fffffff8/admin
GET/v1/cell/<tis>/ids

The province and governorate ids for a cell and nothing else. Padded text keys — "02", "0207" — so the response drops straight into a foreign key column with no mapping step.

curl https://terra.example.sa/v1/cell/t10854284ea9ffff8/ids
POST/v1/cells/ids

The same lookup for up to 10,000 cells or points at once. A bad cell is reported in its own row rather than failing the batch, so one corrupt record does not reject 9,999 good ones.

curl -X POST https://terra.example.sa/v1/cells/ids \
  -H "Content-Type: application/json" \
  -d '{"cells": ["t10854284ea9ffff8", "t108858156b1ffff8"]}'
POST/v1/admin/lookup

Bulk cell → region with names, shaped like POST /v1/index so the same client code fits. Accepts cells or raw points.

curl -X POST https://terra.example.sa/v1/admin/lookup \
  -H "Content-Type: application/json" \
  -d '{"res": 8, "points": [{"id": "ORD-1", "lat": 24.68, "lon": 46.72}]}'
GET/v1/admin/cover/manifest

Version and size of the downloadable assignment table. Check this first: if admin_version matches what you stored last time, the boundaries have not moved and there is nothing to do — which is the normal case.

curl https://terra.example.sa/v1/admin/cover/manifest
GET/v1/admin/cover?page=0

One page of the cover. Rows are arrays rather than objects, because the keys would otherwise be two thirds of the payload repeated two million times. cell_id is a signed 64-bit integer and exceeds Number.MAX_SAFE_INTEGER — a JavaScript client must not parse these.

curl "https://terra.example.sa/v1/admin/cover?page=0"
GET/v1/admin/cover/schema.sql

The table, the ancestor function and the statement that uses them, as SQL you can run as-is. Turns a per-row API call into one indexed join in your own database.

curl https://terra.example.sa/v1/admin/cover/schema.sql

Borders

GET/v1/in-ksa?lat=&lon=

Is a coordinate inside the Kingdom, and if so on land or at sea? The check the grid itself does not do: the grid extent is a rectangle covering the Kingdom plus a GCC buffer, so Doha, Kuwait City and Amman all index without error.

curl "https://terra.example.sa/v1/in-ksa?lat=24.6877&lon=46.7219"