Public read-only API surface of Terra provided for external consumers under the read-only service agreement. Enforced by an explicit endpoint allowlist in the gateway (terra repo, gateway/.../ReadOnlyEndpointFilter.kt): anything not listed returns 403.
https://terra.farmtogether.com/api/ro
Three surfaces:
| Prefix | Backend | Notes |
|---|---|---|
/api/ro/** |
facade | The 90 endpoints listed below (one doc file each) |
/api/ro/titiler/** |
titiler | Raster tiles — see endpoints/titiler.md |
/api/ro/martin/** |
martin | Vector tiles — see endpoints/martin.md |
Send the static API token in the Authorization header, either as a raw UUID or as a Bearer token:
Authorization: 550e8400-e29b-41d4-a716-446655440000
Authorization: Bearer 550e8400-e29b-41d4-a716-446655440000
Tokens are issued by FarmTogether and have an inclusive expiry date (UTC). A token is valid through the end of its expiry date.
The same token also grants access to the Terra web UI in read-only mode. Navigate to:
https://terra.farmtogether.com/readonly-login
Your browser will prompt for basic auth credentials:
- Username: any non-empty name (shown in logs as the session user)
- Password: your API token
After a successful login you are redirected to the main UI. Read-only sessions are held to the same endpoint allowlist as the token API (non-listed calls return 403), and the internal dashboard is not available. Logging out and opening the UI again will prompt for the credentials anew; the token keeps working until its expiry date.
| Code | Meaning |
|---|---|
| 401 | Missing, unknown or expired token |
| 403 | Endpoint (method + path) is not in the read-only allowlist |
| 400 | titiler: url query param outside the allowed S3 prefix or contains .. |
| 429 | More than 4 concurrent in-flight requests per token |
- JTS geometry fields (
Geometry,Point,LineString) are serialized as GeoJSON objects ({"type": ..., "coordinates": [...]}). - Fields named
*Wkt,wkt4326,geom,geometry4326,centroidWktare WKT strings in EPSG:4326. - Dates are ISO-8601 (
2026-10-06,2026-10-06T12:00:00). - Paginated endpoints take a
PageRequest<Filters>body ({"filters": {...}, "page": {"size": 20, "number": 1}, "sort": {"column": "...", "direction": "ASC"}}) and returnPageResponse<T>({"data": [...], "totalPages": n, "totalElements": n, "page": {...}}). Exact Kotlin definitions are included in each endpoint doc. - Each endpoint doc contains the verbatim Kotlin source of the controller method and all request/response DTO classes — treat that code as the authoritative schema.
- GET /api-reference — machine-readable endpoint list with JSON Schemas (draft-07)
- GET /farms/{farmId} — farm overview
- GET /farms/{farmId}/report — short farm report
- GET /farms/{farmId}/price-history
- GET /farms/{farmId}/nearest-airport
- GET /farms/{farmId}/nearest-cities
- POST /farms/{farmId}/nearest-rejected
- GET /farms/{farmId}/owner/other-properties
- GET /farms/{farmId}/climate
- GET /farms/{farmId}/subsidence
- GET /farms/{farmId}/water
- GET /farms/{farmId}/capital
- GET /farms/{farmId}/buildings
- GET /farms/{farmId}/topography
- GET /farms/{farmId}/soils
- GET /farms/{id}/lidar
- GET /farms/{farmId}/hazards — tornado/hail/wind event tracks
- GET /farms/{farmId}/hazards/summary
- GET /farms/{farmId}/hazards/burn-probabilities
- GET /farms/{farmId}/hazards/wildfire-probabilities
- GET /farms/{farmId}/hazards/flood-probabilities
- GET /farms/{farmId}/hazards/frost-probabilities
- GET /farms/{farmId}/sentinel/report — NDVI/NDMI
- GET /farms/{farmId}/vegscape/report — weekly vegetation
- GET /farms/{farmId}/crops
- GET /farms/{farmId}/crops/actual
- GET /farms/available-crop-years
- GET /farms/available-crop-sources
- GET /crops/all
- POST /crops/usda/legend
- POST /crops/nlcd/legend
- POST /farms/search
- POST /sales/search
- POST /farms/{farmId}/similar/sales/search
- POST /parcels/search
- POST /listings/list
- POST /listings/price-changes
- POST /locations/search
- POST /locations/washington/search
- POST /dicts/airports
- POST /dicts/airports/nearest
- POST /dicts/avas
- POST /dicts/basins
- POST /dicts/buildings
- POST /dicts/california-water-rights
- POST /dicts/cash-rent
- POST /dicts/cities
- POST /dicts/cities/closest
- POST /dicts/counties
- GET /dicts/counties/{id}/geometry
- POST /dicts/crops
- POST /dicts/crop-varieties
- POST /dicts/dry-wells
- POST /dicts/ground-water-stations
- POST /dicts/hazards/tornadoes
- POST /dicts/hazards/hails
- POST /dicts/hazards/winds
- POST /dicts/land-survey/by-geom
- POST /dicts/rejection-reasons
- POST /dicts/source-types
- POST /dicts/states
- POST /dicts/tree-age-types
- POST /dicts/water-districts/search
- POST /dicts/water-districts/ratings
- POST /dicts/wells-data
- POST /dicts/wue-water-report/search
- POST /soils/stats
- GET /soils/tasks/{id}
- POST /arcgis/soils/search
- GET /arcgis/soils/tasks/{id}
- POST /arcgis/almonds/search
- POST /arcgis/crops/search
- GET /arcgis/crops/available-years
- POST /arcgis/subbasins/get-attributes
- POST /arcgis/opportunities-zones/intersects
- POST /arcgis/water-districts/get-attributes
- GET /sats/thumbnail — cached imagery only (cold cache → 404)
- POST /sats/planet — Planet scene metadata (DB)
- POST /sats/sky-watch — SkyWatch scene metadata (DB)
- GET /farms/{farmId}/sats — per-farm SkyWatch scenes with pricing