API contracts / App Service v2 / Land & geofence

A farmer's land parcels

OperationlistFarmerLands
Call
GET /gateway/urvi-app-service/api/v2/farmers/{farmerId}/lands
Group
Land & geofence
Features
Land assets, Geofencing, Leased land
Replaces today

Use case. Called online by the Land screen's pull-to-refresh and after a land-related rejection, to rebuild the local land list with server state (authenticated, disabled, lease status, geofence KML URLs). Leased-in parcels carry lease; owned parcels list leasedTo.

Error codes. NOT_FOUND

Parameters

NameInTypeRequiredMeaningExample
X-App-VersionheaderstringYesApp version `major.minor.patch+build`. Too old -> 426 `VERSION_TOO_OLD`. · pattern ^\d+\.\d+\.\d+(\+\d+)?$2.0.0+200
X-Device-Idheaderstring (uuid)YesApp-scoped device UUID (not ANDROID_ID).6b1f2c3d-0000-4000-8000-00000000d001
X-Request-Idheaderstring (uuid)NoClient-generated request id for tracing; echoed in responses and problems.0e0c5a1b-0000-4000-8000-0000000000a1
Accept-LanguageheaderstringNoLanguage for messages and labels. · one of en, te, ta; default "en"te
X-TenantheaderstringNoTenant code; must match the token. Urvi: `ap.gov`. · one of ap.govap.gov
farmerIdpathstringYesFarmer server id or client UUID (`aliasId`). With a UUID unknown to the server, the farmer is created from the flat master record (get-or-create). · min length 1; max length 643f6c1a2e-0000-4000-8000-00000000f001
If-None-MatchheaderstringNoETag from a previous response; 304 when unchanged."cfg-2025-26-v41"

Request

No body.

Responses

200 Lands.

Schema Land.

Example 200 body
[
  {
    "id": 810001,
    "clientId": "4a7d2b3f-0000-4000-8000-000000004097",
    "version": 3,
    "createdAt": "2025-06-02T10:05:00+05:30",
    "updatedAt": "2025-10-14T09:30:00+05:30",
    "active": true,
    "farmerId": 700001,
    "farmerClientId": "3f6c1a2e-0000-4000-8000-000000061441",
    "category": "LAND_OWNED",
    "landType": "IRRIGATED",
    "ownershipType": "OWNER",
    "khataNo": "KH-0001",
    "surveyNo": "SY-101/2",
    "acres": 2.5,
    "authenticated": true,
    "disabled": false,
    "leasedTo": [],
    "geofence": {
      "polygon": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              80.1001,
              16.5001
            ],
            [
              80.1012,
              16.5001
            ],
            [
              80.1012,
              16.501
            ],
            [
              80.1001,
              16.501
            ],
            [
              80.1001,
              16.5001
            ]
          ]
        ]
      },
      "captureMethod": "OSM_MOTION",
      "accuracyM": 4.5,
      "pointCount": 4,
      "capturedAt": "2025-10-14T09:30:00+05:30",
      "areaAcres": 2.4,
      "kmlUrl": "https://files.example.invalid/urvi/signed/land-1001.kml"
    },
    "checksum": "c1a5e0d7"
  }
]
FieldTypeRequiredRulesMeaning
idinteger (int64)Noserver-setServer id (assigned by the App Service).
clientIdstring (uuid)YesClient-generated UUID (the app's `appId`/`aliasId`). Stable for the life of the entity and used for idempotent creates and parent references.
versioninteger (int64)No≥ 1; server-setMonotonic server version; send as `baseVersion` on updates.
createdAtstring (date-time)Noserver-set
updatedAtstring (date-time)Noserver-set
activebooleanNoFalse once soft-deleted / disabled.
farmerIdinteger (int64)NoServer id (assigned by the App Service).
farmerClientIdstring (uuid)No
categoryLandCategoryNoone of LAND_OWNED, LEASED_IN, ROFR, ENDOWMENT, ASSIGNED_D_PATTA, LAND_OWNED_OTHERS, LEASED_IN_OTHERS
landTypeLandTypeNoone of IRRIGATED, RAINFED
ownershipTypestringNoone of OWNER, CULTIVATOROnly for LAND_OWNED.
descriptionstringNomax length 200
namestringNomax length 100
khataNostringNomax length 50Required for LAND_OWNED when `featureSwitches.khataMandatory` (`KHATA_REQUIRED`).
surveyNostringNomax length 50Required (except leased-in) when `featureSwitches.surveyMandatory` (`SURVEY_REQUIRED`).
acresnumber (double)No≥ 0.01; ≤ 99.99; step 0.01Parcel area, > 0, at most 2 decimals. For leased-in land equals `lease.leasedAcres`. Unit: acres.
authenticatedbooleanNoOnce true and saved, the parcel is locked unless `featureSwitches.editAuthenticatedLand` (`LAND_AUTHENTICATED_LOCKED`).
disabledbooleanNoserver-setDisabled by an administrator; no new crops (`LAND_DISABLED`).
inactiveReasonstringNoDelete reason (required on delete).
leaseLeasedLandNoLease details. One leased-in Land is created per lessor parcel; it copies khata, survey number and geofence.
leasedToFarmerRef[]Noserver-set
geofenceGeofenceNoBoundary of a land parcel, crop block or ATM plot. Send `polygon` or `kmlFileId` (or both).
checksumstringNoserver-setServer checksum of acres + identifiers; crop blocks and ATMs echo it as `landChecksum` (`LAND_CHECKSUM_MISMATCH`).

304 Unchanged since the supplied ETag; use the cached copy.

400 Malformed request or schema violation.

Schema Problem.

Example 400 body
{
  "type": "https://urvi.example.invalid/problems/validation-failed",
  "title": "Validation failed",
  "status": 400,
  "detail": "One or more fields are invalid.",
  "code": "VALIDATION_FAILED",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1",
  "errors": [
    {
      "field": "/mobile",
      "code": "INVALID_MOBILE",
      "message": "Mobile must be 10 digits starting 6-9."
    }
  ]
}

401 Missing, invalid or expired access token. Refresh once, then ask the user to log in; pending outbox ops stay intact.

Schema Problem.

Example 401 body
{
  "type": "https://urvi.example.invalid/problems/token-expired",
  "title": "Session expired",
  "status": 401,
  "detail": "The access token has expired.",
  "code": "TOKEN_EXPIRED",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1"
}

403 Authenticated but not allowed (role, tenant, device binding or feature switch).

Schema Problem.

Example 403 body
{
  "type": "https://urvi.example.invalid/problems/role-not-allowed",
  "title": "Not allowed",
  "status": 403,
  "detail": "Your role cannot perform this action.",
  "code": "ROLE_NOT_ALLOWED",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1"
}

404 Resource not found or outside the user's work nodes.

Schema Problem.

Example 404 body
{
  "type": "https://urvi.example.invalid/problems/not-found",
  "title": "Not found",
  "status": 404,
  "detail": "No such resource in your work area.",
  "code": "NOT_FOUND",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1"
}

426 App version below the minimum; block the UI with an update prompt. Pending outbox ops are kept.

Schema Problem.

Example 426 body
{
  "type": "https://urvi.example.invalid/problems/version-too-old",
  "title": "Update required",
  "status": 426,
  "detail": "Please update Urvi to continue.",
  "code": "VERSION_TOO_OLD",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1",
  "minAppVersion": "2.0.0"
}

429 Rate limited per device / user. Respect `Retry-After`.

Schema Problem.

Example 429 body
{
  "type": "https://urvi.example.invalid/problems/rate-limited",
  "title": "Too many requests",
  "status": 429,
  "detail": "Slow down and retry later.",
  "code": "RATE_LIMITED",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1",
  "retryAfterSeconds": 30
}

500 Unexpected server error; retry with backoff (writes are idempotent).

Schema Problem.

Example 500 body
{
  "type": "https://urvi.example.invalid/problems/internal-error",
  "title": "Server error",
  "status": 500,
  "detail": "Something went wrong. Please try again.",
  "code": "INTERNAL_ERROR",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1"
}