API contracts / App Service v2 / Auth & session

Session bootstrap after login and on cold start

OperationgetBootstrap
Call
GET /gateway/urvi-app-service/api/v2/session/bootstrap
Group
Auth & session
Features
App startup and role detection, Village, Habitation and VO selection, Device registration and remote actions, Home and bottom bar, Side menu
Replaces today

Use case. Called once right after login and on every cold start (cached; offline the app uses the last copy). Returns the user, tenant, flow type (Cadre / Unit / FCCC), typed permissions, the work-node tree for the Village > Habitation > VO picker, the device-binding status, pending remote actions, app-version policy and the current config ETag. The app routes: Cadre without a saved VO -> work-node selection; Unit -> unit data download; binding CONFLICT -> the non-dismissable device-conflict dialog; pending actions -> the remote-action lock screen.

Rules.

  • Unit flow when any role contains unit-incharge or fmt_l1 (tenant ap.gov).
  • Device binding: no session -> the server registers this device (BOUND_HERE); other device bound -> CONFLICT with otherDevice.
  • No assigned work nodes -> 200 with an empty workNodes array; the app shows its "technical issue" error and offers logout.

Error codes. DEVICE_BLOCKED, 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

Request

No body.

Responses

200 Bootstrap.

Schema Bootstrap.

Example 200 body
{
  "user": {
    "userId": 9001,
    "login": "user.a@@ap.gov",
    "displayName": "User A",
    "roleCodes": [
      "role.ap.gov.cadre"
    ],
    "flowType": "CADRE",
    "permissions": {
      "farmerAddEdit": true,
      "readOnlyProfile": false,
      "endorse": false,
      "resolveFlags": true,
      "compactBlocks": false,
      "fmtCropEdit": false,
      "voGeoFilter": false,
      "analytics": true,
      "surveys": false
    },
    "unitIncharge": {
      "userId": 9002,
      "displayName": "User B",
      "roleCode": "role.ap.gov.unit-incharge"
    }
  },
  "tenant": {
    "code": "ap.gov",
    "name": "RySS",
    "languages": [
      "en",
      "te"
    ],
    "timeZone": "Asia/Kolkata"
  },
  "workNodes": [
    {
      "id": 3101,
      "code": "VIL-3101",
      "type": "VILLAGE",
      "name": {
        "en": "Village A",
        "te": "Village A (te)"
      },
      "parentId": null,
      "children": [
        {
          "id": 3901,
          "code": "HAB-3901",
          "type": "HABITATION",
          "name": {
            "en": "Habitation A",
            "te": "Habitation A (te)"
          },
          "parentId": 3101,
          "children": [
            {
              "id": 4101,
              "code": "VO-4101",
              "type": "VO",
              "name": {
                "en": "VO A",
                "te": "VO A (te)"
              },
              "parentId": 3901,
              "children": []
            }
          ]
        }
      ]
    }
  ],
  "device": {
    "enforced": true,
    "status": "BOUND_HERE",
    "canTakeOver": true
  },
  "pendingActions": [],
  "appVersion": {
    "minimum": "2.0.0",
    "recommended": "2.1.0",
    "latest": "2.1.0"
  },
  "configEtag": "\"cfg-2025-26-v41\"",
  "serverTime": "2025-10-14T09:30:00+05:30",
  "currentSeason": "2025-26"
}
FieldTypeRequiredRulesMeaning
userUserYes
tenantTenantYes
workNodesGeoNode[]YesWork-node tree assigned to the user (districts down to SHGs for Cadre; VOs for Unit).
deviceDeviceBindingStatusYes
pendingActionsRemoteAction[]No
appVersionAppVersionPolicyYes
configEtagstringYesCurrent ETag of `GET /config`; skip the config call when unchanged.
serverTimestring (date-time)YesUse to detect a wrong device clock.
currentSeasonstringNopattern ^\d{4}-\d{2}$Season label, e.g. `2025-26`.

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