API contracts / App Service v2 / Config

Typed config bundle (ETag)

OperationgetConfig
Call
GET /gateway/urvi-app-service/api/v2/config
Group
Config
Features
Language selection, App startup and role detection, Device registration and remote actions, Data download (Cadre), Data download (Unit / FMT), Home and bottom bar, Farmer hub (option tiles), Farmer list & search, Add/Edit farmer (IE profile), Farmer category (Farmer/C4/C5), Land assets, Leased land, Geofencing, Livestock, Crop stock (inventory), 365 DKG kitchen garden, ATM model (Anytime Money plot), ATM harvest, Crop Actual harvest, Analytics dashboard, Crop Actual (portfolio), PMDS and A Grade crop details, Certification survey, Compact Block, Activity Tracker, KAP / Annual Action Plan 2025-26, VO / SHG / Farmer endorsement, Settings, Program configuration and instructions
Replaces today

Use case. Called during data download (first item), on Home pull-to-refresh, hourly in the background and whenever bootstrap reports a new configEtag. Always sent with If-None-Match; usually answers 304. Carries feature switches, the current season, sync knobs, all masters (products, practices, asset categories, UOM, dropdowns, AAP reject reasons), help videos, programme instructions and config, the KAP form schema and every validation limit, so client and server validate with the same numbers. The app replaces its local masters atomically on 200.

Rules.

  • Labels carry every language; the app picks the user's language with English fallback.
  • Replaces *_EXTERNAL_SWITCH ref-data, Firebase Remote Config and versionName_versionCode allow-lists.
  • Season is current; the server maps it to year-specific datasets (no app release per season).

Error codes. VERSION_TOO_OLD

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
If-None-MatchheaderstringNoETag from a previous response; 304 when unchanged."cfg-2025-26-v41"

Request

No body.

Responses

200 Config bundle.

Schema ConfigBundle.

Example 200 body
{
  "version": "cfg-2025-26-v41",
  "generatedAt": "2025-10-14T09:30:00+05:30",
  "season": {
    "current": "2025-26",
    "previous": "2024-25",
    "startDate": "2025-06-01",
    "endDate": "2026-05-31",
    "kapSeason": "2025-26"
  },
  "featureSwitches": {
    "farmerAddEdit": true,
    "profileConsent": true,
    "multipleCategoryEdits": false,
    "editAuthenticatedLand": false,
    "khataMandatory": true,
    "surveyMandatory": true,
    "geofencingAssets": true,
    "geofencingAtm": true,
    "atm": true,
    "atmHarvest": true,
    "cropActual": true,
    "cropActualHarvestContinuous": true,
    "cropActualHarvestWhole": true,
    "pmdsCropType": true,
    "rdsCropType": false,
    "cropActualCopyForward": true,
    "copyDisabledCropActual": false,
    "currentMonthPortfolioOnly": true,
    "kap": true,
    "certification": true,
    "activityTracker": true,
    "profile": true,
    "land": true,
    "deviceBinding": true,
    "removeBindingOnNewDevice": true,
    "removeBindingOnLogout": true,
    "showForceSync": true,
    "showAnalyticsTab": true,
    "helpVideoAutoPopup": false
  },
  "geofenceMethods": {
    "osmFixed": true,
    "osmMotion": true,
    "osmTap": true,
    "googleEarth": false,
    "kmlUpload": true
  },
  "sync": {
    "maxOpsPerBatch": 100,
    "retryBaseSeconds": 30,
    "retryMaxSeconds": 3600,
    "maxAttempts": 20,
    "snapshotPageSize": 150,
    "setupCacheMinutes": 60,
    "disabledLandRefreshMinutes": 360,
    "analyticsRefreshHours": 12,
    "changesPollMinutes": 15
  },
  "formLimits": {
    "farmer": {
      "nameMaxLength": 100,
      "reasonMaxLength": 100,
      "ageMin": 18,
      "ageMax": 110,
      "lastMandatoryCategoryUpdateDate": "2025-07-31"
    },
    "land": {
      "acresMin": 0.01,
      "acresMax": 99.99
    },
    "livestock": {
      "countMax": 999
    },
    "atm": {
      "acresMax": 99.99,
      "c5MaxAcres": 0.5,
      "c5MaxCount": 1
    },
    "cropBlock": {
      "acresMax": 99.99,
      "sowingLookbackMonths": 6
    },
    "pmds": {
      "seedVarietiesMin": 6,
      "seedVarietiesMax": 35,
      "seedQuantityKgMin": 1,
      "seedQuantityKgMax": 999
    },
    "aGrade": {
      "mainCropsMax": 1,
      "associatedCropsMin": 2,
      "biodiversityCropsMin": 2
    },
    "harvest": {
      "cropMaxQuintals": 999.99
    },
    "compactBlock": {
      "minTotalAcres": 5
    },
    "geofence": {
      "minPoints": 3,
      "maxAccuracyM": 20,
      "motionMinDistanceM": 5,
      "motionIntervalSeconds": 2
    },
    "activityTracker": {
      "submitAfterLocalTime": "18:00",
      "photoMaxKb": 45
    },
    "kap": {
      "extentMax": 99.99
    }
  },
  "masters": {
    "products": [
      {
        "code": "PADDY",
        "name": {
          "en": "Paddy",
          "te": "Paddy (te)"
        },
        "majorType": "CEREALS",
        "categoryCode": "CEREALS",
        "cropTypes": [
          "AGRICULTURE",
          "A_GRADE",
          "NO_NF_CROP"
        ],
        "isDummy": false
      },
      {
        "code": "TOMATO",
        "name": {
          "en": "Tomato",
          "te": "Tomato (te)"
        },
        "majorType": "VEGETABLES_LEAFY_TUBERS",
        "categoryCode": "VEGETABLES",
        "cropTypes": [
          "AGRICULTURE",
          "HORTICULTURE"
        ],
        "isDummy": false
      }
    ],
    "practices": [
      {
        "code": "AP-GOV-KAP-100_PERCENT_CHEMICAL_FREE_NATURAL_FARMING",
        "name": {
          "en": "100% chemical-free natural farming",
          "te": "100% chemical-free natural farming (te)"
        },
        "isAGrade": false,
        "isS2S": true,
        "isPmds": false,
        "isNoNf": false,
        "isChemicalShare": false
      }
    ],
    "assetCategories": [
      {
        "code": "LAND_OWNED",
        "landType": "IRRIGATED",
        "functionalityCode": "IRRIGATED",
        "label": {
          "en": "Land Owned - Irrigated",
          "te": "Land Owned - Irrigated (te)"
        },
        "khataApplicable": true,
        "surveyApplicable": true,
        "acresApplicable": true,
        "descriptionApplicable": false
      }
    ],
    "uoms": [
      {
        "code": "UOM.AREA.ACRE",
        "symbol": "ac",
        "name": {
          "en": "Acre",
          "te": "Acre (te)"
        }
      },
      {
        "code": "UOM.WEIGHT.QUINTAL",
        "symbol": "q",
        "name": {
          "en": "Quintal",
          "te": "Quintal (te)"
        }
      }
    ],
    "genders": [
      {
        "code": "FEMALE",
        "label": {
          "en": "Female",
          "te": "Female (te)"
        },
        "order": 1
      },
      {
        "code": "MALE",
        "label": {
          "en": "Male",
          "te": "Male (te)"
        },
        "order": 2
      }
    ],
    "lifeStatusReasons": [
      {
        "code": "MIGRATED",
        "label": {
          "en": "Migrated to another village",
          "te": "Migrated to another village (te)"
        },
        "group": "INACTIVE",
        "order": 2
      },
      {
        "code": "OTHER",
        "label": {
          "en": "Other",
          "te": "Other (te)"
        },
        "group": "INACTIVE",
        "order": 9,
        "requiresText": true
      }
    ],
    "aapRejectReasons": [
      {
        "code": "EXTENT_MISMATCH",
        "label": {
          "en": "Extent does not match land records",
          "te": "Extent does not match land records (te)"
        },
        "order": 1
      }
    ]
  },
  "kapFormSchema": {
    "season": "2025-26",
    "previousSeason": "2024-25",
    "fields": [
      {
        "code": "c1Acres",
        "label": {
          "en": "C1 extent (acres)",
          "te": "C1 extent (acres) (te)"
        },
        "type": "decimal",
        "min": 0,
        "max": 99.99,
        "enabled": true,
        "disabledForCategories": [
          "C4",
          "C5"
        ]
      },
      {
        "code": "pmdsAcres",
        "label": {
          "en": "PMDS extent (acres)",
          "te": "PMDS extent (acres) (te)"
        },
        "type": "decimal",
        "min": 0,
        "max": 99.99,
        "maxOf": "c1Acres",
        "enabled": true,
        "disabledForCategories": [
          "C4",
          "C5"
        ]
      }
    ],
    "pmdsYearOptions": [
      "2019-20",
      "2020-21",
      "2021-22",
      "2022-23",
      "2023-24",
      "2024-25"
    ],
    "dgcSeasonOptions": [
      "PMDS",
      "KHARIF",
      "RABI",
      "RDSS1",
      "RDSS2"
    ]
  },
  "helpVideos": [
    {
      "module": "CROP_ACTUAL",
      "title": {
        "en": "How to record Crop Actual",
        "te": "How to record Crop Actual (te)"
      },
      "url": "https://video.example.invalid/crop-actual",
      "autoPopup": false
    }
  ],
  "programInstructions": [
    {
      "order": 1,
      "text": {
        "en": "Record Crop Actual every month.",
        "te": "Record Crop Actual every month. (te)"
      }
    }
  ],
  "programConfig": [
    {
      "key": "KAP_25_26",
      "label": {
        "en": "KAP 25-26 entries",
        "te": "KAP 25-26 entries (te)"
      },
      "value": "1"
    }
  ],
  "homeBanner": {
    "en": "Welcome to Urvi",
    "te": "Welcome to Urvi (te)"
  },
  "notificationWebUrl": "https://notices.example.invalid/urvi"
}
FieldTypeRequiredRulesMeaning
versionstringYesBundle version; equals the ETag without quotes.
generatedAtstring (date-time)No
seasonSeasonYes
featureSwitchesFeatureSwitchesYesTyped feature switches (replace `*_EXTERNAL_SWITCH` ref-data, Remote Config and `versionName_versionCode` allow-lists). Unknown future switches may appear; clients ignore them.
geofenceMethodsGeofenceMethodsNo
syncSyncSettingsYes
formLimitsFormLimitsYesRule parameters shared by client and server so both validate with the same numbers.
mastersMastersYesReference data. Labels carry every language.
kapFormSchemaKapFormSchemaYes
helpVideosHelpVideo[]No
programInstructionsProgramInstruction[]No
programConfigProgramConfigItem[]No
homeBannerLocalizedTextNoLabel in every supported language; clients fall back to `en`.
notificationWebUrlstring (uri)No

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"
}

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"
}