Apply an ordered batch of offline mutations
submitSyncBatch- Call
POST /gateway/urvi-app-service/api/v2/sync/batch- Group
- Sync
- Features
- 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, Crop Actual (portfolio), PMDS and A Grade crop details, Certification survey, Compact Block, Activity Tracker, KAP / Annual Action Plan 2025-26, Farmer endorsement details, VO / SHG / Farmer endorsement, VO / SHG surveys, Pending sync, Settings, Sync error log
- Replaces today
Use case. Called by the single outbox CoroutineWorker whenever ops are ready and the network is up (periodic, after every save, and expedited for "Sync now" / Force sync / per-item retry on Pending Sync). It takes up to 100 ready ops in createdAt order (after their files are uploaded) and sends them as one batch. Every user write in the app goes through here: farmer create / edit / category / photo / roles, land (incl. leased-in, delete, geofence), livestock, crop stock, Crop Actual blocks (PMDS / A Grade), crop and ATM harvests, ATM and DKG, KAP submissions, compact blocks and member removal, endorsement transitions, comments and abstract uploads, and assessment responses (certification, activity tracker, VO / SHG surveys). The app stores serverId and serverVersion per result, marks applied/duplicate done, applies the conflict policy for conflict, marks rejected as failed with the localised reason (visible and retryable on Pending Sync and the sync error log), keeps blocked pending and backs off on retry.
Rules.
- Ops are applied in order; client UUID references (
refs,*ClientIdfields) resolve through a per-tenant client-to-server id map, so children may reference parents created earlier in the same batch. - Each op is idempotent on
opId(kept >= 30 days): a resend returnsduplicatewith the original result. updatepayloads are JSON Merge Patches (RFC 7396) of changed fields;requiredconstraints of the entity schema apply to the merged result. StalebaseVersion->conflictwithserverState, except append-only entities (harvests, comments, assessment responses) which never conflict.- Conflict policy: farmer = field-level merge, server wins on locked fields (frozen category, admin life status); land = rejected if authenticated or disabled since baseVersion, acreage changes re-run the land-usage check; crop_block = version check,
PART_OF_COMPACT_BLOCKwhen in a block; farming_model ATM = version check, DKG = last write wins per month; compact_block = server-authoritative membership; endorsement_action = state machine; kap_plan = rejected once endorsed. - Validation rules (same numbers as
ConfigBundle.formLimits): land usageLAND_AREA_EXCEEDED/LAND_ACRES_BELOW_USAGE; category gatesCATEGORY_FROZEN/CATEGORY_NOT_ALLOWED; PMDS ranges; A Grade crop counts; compact block >= 5 acres; ATM C5 <= 0.5 acre; KAP ceilings; geofence polygon >= 3 points. - A failed op makes later ops that depend on it (
dependsOnor a reference)blocked; independent ops still apply. - Transient failures of a single op return
retry; the HTTP status stays 200. - Large batches may return 202 with a status URL (
GET /sync/batches/{batchId}). - Every mutation is audited (user, device, app version, time); push fan-out (e.g. endorsement status to the cadre) happens after commit.
Error codes. BATCH_TOO_LARGE, IDEMPOTENCY_KEY_REUSED, STALE_VERSION, UNKNOWN_REFERENCE, DEPENDENCY_FAILED, LOCKED_FIELD, DUPLICATE_FARMER, INVALID_AADHAAR, INVALID_MOBILE, AGE_OUT_OF_RANGE, SHG_REQUIRES_FEMALE, CATEGORY_FROZEN, CATEGORY_REQUIRED, CATEGORY_NOT_ALLOWED, FARMER_INACTIVE, FARMER_EDIT_DISABLED, CONSENT_REQUIRED, REASON_REQUIRED, LAND_AREA_EXCEEDED, LAND_ACRES_BELOW_USAGE, LAND_AUTHENTICATED_LOCKED, LAND_DISABLED, LAND_IN_USE, LAND_CHECKSUM_MISMATCH, LAND_NOT_AUTHENTICATED, LEASE_LIMIT_EXCEEDED, LESSOR_IS_SELF, KHATA_REQUIRED, SURVEY_REQUIRED, POLYGON_TOO_FEW_POINTS, POLYGON_NOT_CLOSED, POLYGON_SELF_INTERSECTING, GEOFENCE_ACCURACY_TOO_LOW, GEOFENCE_ZERO_ACRE_LAND, INVALID_KML, CROP_TYPE_DISABLED, A_GRADE_CROP_COUNT, A_GRADE_ASSOCIATED_CROPS_MIN, PMDS_SEED_VARIETIES_RANGE, PMDS_SEED_QUANTITY_RANGE, PRACTICE_REQUIRED, PART_OF_COMPACT_BLOCK, CROP_HARVESTED_LOCKED, SOWING_DATE_OUT_OF_RANGE, EDIT_REASON_REQUIRED, FMT_EDIT_DISABLED, DUPLICATE_TILE, HARVEST_SURPLUS_EXCEEDS_TOTAL, HARVEST_DATE_INVALID, HARVEST_TYPE_DISABLED, HARVEST_PHOTO_REQUIRED, HARVEST_ALREADY_COMPLETED, ATM_C5_AREA_EXCEEDED, ATM_C5_LIMIT_ONE, ATM_LAND_REQUIRED, KAP_DISABLED, KAP_LOCKED_ENDORSED, KAP_VALUE_EXCEEDS_LIMIT, KAP_PMDS_YEARS_REQUIRED, KAP_DGC_SEASON_REQUIRED, ENDORSEMENT_ORDER, ENDORSEMENT_TRANSITION_INVALID, ENDORSEMENT_KAP_NOT_SUBMITTED, ENDORSEMENT_CATEGORY_NOT_FROZEN, ENDORSEMENT_FARMER_NOT_REGISTERED, COMMENT_EMPTY, COMPACT_BLOCK_BELOW_5_ACRES, COMPACT_BLOCK_NAME_TAKEN, TILE_NOT_ELIGIBLE, TILE_IN_OTHER_BLOCK, TILE_NO_GEOFENCE, ASSESSMENT_INCOMPLETE, SIGNATURE_REQUIRED, ACTIVITY_SUBMIT_TOO_EARLY, ACTIVITY_ALREADY_SUBMITTED, ACTIVITY_EDIT_WINDOW_CLOSED, FUTURE_DATE, FILE_NOT_FOUND, FILE_NOT_COMPLETE, FEATURE_DISABLED
Parameters
| Name | In | Type | Required | Meaning | Example |
|---|---|---|---|---|---|
X-App-Version | header | string | Yes | App version `major.minor.patch+build`. Too old -> 426 `VERSION_TOO_OLD`. · pattern ^\d+\.\d+\.\d+(\+\d+)?$ | 2.0.0+200 |
X-Device-Id | header | string (uuid) | Yes | App-scoped device UUID (not ANDROID_ID). | 6b1f2c3d-0000-4000-8000-00000000d001 |
X-Request-Id | header | string (uuid) | No | Client-generated request id for tracing; echoed in responses and problems. | 0e0c5a1b-0000-4000-8000-0000000000a1 |
Accept-Language | header | string | No | Language for messages and labels. · one of en, te, ta; default "en" | te |
X-Tenant | header | string | No | Tenant code; must match the token. Urvi: `ap.gov`. · one of ap.gov | ap.gov |
Idempotency-Key | header | string (uuid) | Yes | UUID per write request; retained >= 30 days. Reusing a key with a different body -> 422 `IDEMPOTENCY_KEY_REUSED`. | 9c8b7a6d-0000-4000-8000-0000000000b1 |
Request
Body schema SyncBatchRequest.
{
"batchId": "5d4c3b2a-0000-4000-8000-000000000193",
"clientTime": "2025-10-14T09:30:00+05:30",
"ops": [
{
"opId": "e0a1b2c3-0000-4000-8000-000000000001",
"entityType": "farmer",
"op": "create",
"clientId": "3f6c1a2e-0000-4000-8000-000000061442",
"baseVersion": null,
"clientTime": "2025-10-14T09:30:00+05:30",
"payload": {
"clientId": "3f6c1a2e-0000-4000-8000-000000061442",
"name": "Farmer B",
"gender": "FEMALE",
"age": 35,
"mobile": "9000000002",
"identity": {
"aadhaar": "999999992345"
},
"maritalStatus": "SINGLE",
"family": {
"relation": "FATHER",
"name": "Father B"
},
"education": "PRIMARY",
"socialCategory": "SC",
"village": {
"id": 3101,
"type": "VILLAGE",
"name": "Village A",
"code": "VIL-3101"
},
"habitation": {
"id": 3901,
"type": "HABITATION",
"name": "Habitation A",
"code": "HAB-3901"
},
"vo": {
"id": 4101,
"type": "VO",
"name": "VO A",
"code": "VO-4101"
},
"shg": {
"id": 52001,
"type": "SHG",
"name": "SHG A",
"code": "SHG-52001"
},
"roles": [
{
"roleCode": "MEMBER"
}
],
"category": {
"code": "FARMER"
},
"status": {
"lifeStatus": "ACTIVE"
},
"photo": {
"fileId": "7a6b5c4d-0000-4000-8000-000000000226",
"kind": "PHOTO_FARMER"
},
"consentGiven": true
}
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000002",
"entityType": "land",
"op": "create",
"clientId": "4a7d2b3f-0000-4000-8000-000000004098",
"baseVersion": null,
"refs": {
"farmerClientId": "3f6c1a2e-0000-4000-8000-000000061442"
},
"dependsOn": [
"e0a1b2c3-0000-4000-8000-000000000001"
],
"payload": {
"clientId": "4a7d2b3f-0000-4000-8000-000000004098",
"farmerClientId": "3f6c1a2e-0000-4000-8000-000000061442",
"category": "LEASED_IN",
"landType": "RAINFED",
"acres": 0.75,
"authenticated": false,
"lease": {
"leaseType": "INCOMING",
"lessorFarmerId": 700001,
"lessorLandId": 810001,
"lessorWorkNode": {
"id": 52001,
"type": "SHG",
"name": "SHG A",
"code": "SHG-52001"
},
"leasedAcres": 0.75
}
}
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000003",
"entityType": "crop_block",
"op": "update",
"clientId": "5b8e3c4a-0000-4000-8000-000000008193",
"serverId": 840001,
"baseVersion": 4,
"refs": {
"farmerClientId": "3f6c1a2e-0000-4000-8000-000000061441",
"landClientId": "4a7d2b3f-0000-4000-8000-000000004097"
},
"payload": {
"clientId": "5b8e3c4a-0000-4000-8000-000000008193",
"practiceCodes": [
"AP-GOV-KAP-100_PERCENT_CHEMICAL_FREE_NATURAL_FARMING"
]
}
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000004",
"entityType": "crop_harvest",
"op": "create",
"clientId": "9f2c7a8e-0000-4000-8000-000000000001",
"refs": {
"cropBlockClientId": "5b8e3c4a-0000-4000-8000-000000008193"
},
"payload": {
"clientId": "9f2c7a8e-0000-4000-8000-000000000001",
"kind": "CROP",
"cropBlockId": 840001,
"cropBlockClientId": "5b8e3c4a-0000-4000-8000-000000008193",
"cropLineClientId": "5b8e3c4a-0000-4000-8000-000000008449",
"productCode": "PADDY",
"harvestType": "WHOLE_CROP",
"totalOutputQuintals": 18.5,
"surplusQuintals": 10,
"harvestDate": "2025-10-12",
"interestedInMarketing": true,
"photo": {
"fileId": "7a6b5c4d-0000-4000-8000-000000000226",
"kind": "PHOTO_HARVEST"
},
"location": {
"lat": 16.5005,
"lng": 80.1006,
"accuracyM": 6
}
}
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000005",
"entityType": "kap_plan",
"op": "create",
"clientId": "a03d8b9f-0000-4000-8000-000000000001",
"refs": {
"farmerClientId": "3f6c1a2e-0000-4000-8000-000000061441"
},
"payload": {
"clientId": "a03d8b9f-0000-4000-8000-000000000001",
"farmerClientId": "3f6c1a2e-0000-4000-8000-000000061441",
"season": "2025-26",
"previousCurrent": {
"c1Acres": 2,
"pmdsAcres": 0.5,
"s2sAcres": 1,
"aGradeAcres": 0,
"s2sInCompactBlockAcres": 0.5,
"desiCows": 2,
"dkg": "SEASONAL",
"atm": true
},
"current": {
"c1Acres": 2.5,
"pmdsAcres": 1,
"s2sAcres": 1.5,
"aGradeAcres": 0.5,
"s2sInCompactBlockAcres": 1,
"desiCows": 2,
"dkg": "DKG_365",
"atm": true
},
"pmdsPractisingYears": [
"2022-23",
"2023-24"
],
"dgc": {
"practising": true,
"seasons": [
"KHARIF",
"RABI"
]
}
}
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000006",
"entityType": "compact_block_member",
"op": "delete",
"clientId": "7d0a5e6c-0000-4000-8000-000000016642",
"serverId": 861002,
"baseVersion": 1,
"refs": {
"compactBlockClientId": "7d0a5e6c-0000-4000-8000-000000016385"
},
"reason": "Farmer removed from block"
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000007",
"entityType": "endorsement_action",
"op": "create",
"clientId": "b14e9caf-0000-4000-8000-000000000001",
"payload": {
"clientId": "b14e9caf-0000-4000-8000-000000000001",
"entityType": "FARMER",
"entityId": 700001,
"action": "ENDORSE",
"comment": "Verified in field visit"
}
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000008",
"entityType": "farming_model",
"op": "create",
"clientId": "6c9f4d5b-0000-4000-8000-000000012291",
"refs": {
"farmerClientId": "3f6c1a2e-0000-4000-8000-000000061441"
},
"payload": {
"clientId": "6c9f4d5b-0000-4000-8000-000000012291",
"modelType": "DKG_365",
"farmerClientId": "3f6c1a2e-0000-4000-8000-000000061441",
"month": "2025-10",
"continuing": true
}
}
]
}| Field | Type | Required | Rules | Meaning |
|---|---|---|---|---|
batchId | string (uuid) | Yes | Client-generated; resending the same batch is safe. | |
clientTime | string (date-time) | No | ||
ops | SyncOp[] | Yes | min items 1; max items 100 | Processed in order. Max 100 (`BATCH_TOO_LARGE`). |
Responses
200 Per-op results (the batch itself succeeded even if some ops were rejected).
Schema SyncBatchResult.
{
"batchId": "5d4c3b2a-0000-4000-8000-000000000193",
"processedAt": "2025-10-14T09:31:02+05:30",
"changesCursor": "chg_eyJ2IjoxMjQwMH0",
"results": [
{
"opId": "e0a1b2c3-0000-4000-8000-000000000001",
"clientId": "3f6c1a2e-0000-4000-8000-000000061442",
"entityType": "farmer",
"status": "applied",
"serverId": 700002,
"serverVersion": 1,
"error": null,
"serverState": null
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000002",
"clientId": "4a7d2b3f-0000-4000-8000-000000004098",
"entityType": "land",
"status": "applied",
"serverId": 810002,
"serverVersion": 1,
"error": null,
"serverState": null
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000003",
"clientId": "5b8e3c4a-0000-4000-8000-000000008193",
"entityType": "crop_block",
"status": "rejected",
"serverId": 840001,
"serverVersion": 5,
"error": {
"type": "https://urvi.example.invalid/problems/part-of-compact-block",
"title": "Part of a compact block",
"status": 422,
"detail": "This crop block is part of compact block CB 1 and cannot be edited.",
"code": "PART_OF_COMPACT_BLOCK",
"requestId": "0e0c5a1b-0000-4000-8000-0000000000a1",
"instance": "/sync/batch#ops/2"
},
"serverState": {
"id": 840001,
"clientId": "5b8e3c4a-0000-4000-8000-000000008193",
"version": 5,
"createdAt": "2025-10-01T08:00:00+05:30",
"updatedAt": "2025-10-14T09:30:00+05:30",
"active": true,
"farmerId": 700001,
"farmerClientId": "3f6c1a2e-0000-4000-8000-000000061441",
"landId": 810001,
"landClientId": "4a7d2b3f-0000-4000-8000-000000004097",
"landChecksum": "c1a5e0d7",
"tileId": "TILE-840001",
"planType": "SEASON_ACTUAL",
"season": "2025-26",
"month": "2025-10",
"cropType": "AGRICULTURE",
"crops": [
{
"clientId": "5b8e3c4a-0000-4000-8000-000000008449",
"id": 841001,
"productCode": "PADDY",
"acres": 1.5,
"isMajor": true,
"seedVariety": "BPT-5204",
"expectedHarvestDate": "2025-12-15",
"harvestStatus": "NOT_STARTED",
"placeholder": false
},
{
"clientId": "5b8e3c4a-0000-4000-8000-000000008450",
"id": 841002,
"productCode": "RED_GRAM",
"acres": 0.5,
"isMajor": false,
"harvestStatus": "NOT_STARTED",
"placeholder": false
}
],
"practiceCodes": [
"AP-GOV-KAP-100_PERCENT_CHEMICAL_FREE_NATURAL_FARMING",
"AP-GOV-KAP-BEEJAMRUTHAM"
],
"sowingDate": "2025-07-10",
"photo": {
"fileId": "7a6b5c4d-0000-4000-8000-000000000225",
"kind": "PHOTO_CROP",
"url": "https://files.example.invalid/urvi/signed/crop-840001.jpg"
},
"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"
},
"changeLog": [],
"compactBlockId": 860001,
"editable": false,
"totalAcres": 2
}
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000004",
"clientId": "9f2c7a8e-0000-4000-8000-000000000001",
"entityType": "crop_harvest",
"status": "duplicate",
"serverId": 940001,
"serverVersion": 1,
"error": null,
"serverState": null
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000005",
"clientId": "a03d8b9f-0000-4000-8000-000000000001",
"entityType": "kap_plan",
"status": "applied",
"serverId": 870001,
"serverVersion": 3,
"error": null,
"serverState": null
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000006",
"clientId": "7d0a5e6c-0000-4000-8000-000000016642",
"entityType": "compact_block_member",
"status": "applied",
"serverId": 861002,
"serverVersion": 2,
"error": null,
"serverState": null
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000007",
"clientId": "b14e9caf-0000-4000-8000-000000000001",
"entityType": "endorsement_action",
"status": "rejected",
"serverId": null,
"serverVersion": null,
"error": {
"type": "https://urvi.example.invalid/problems/endorsement-kap-not-submitted",
"title": "KAP not submitted",
"status": 422,
"detail": "Submit KAP before endorsing this farmer.",
"code": "ENDORSEMENT_KAP_NOT_SUBMITTED",
"requestId": "0e0c5a1b-0000-4000-8000-0000000000a1",
"instance": "/sync/batch#ops/6"
},
"serverState": null
},
{
"opId": "e0a1b2c3-0000-4000-8000-000000000008",
"clientId": "6c9f4d5b-0000-4000-8000-000000012291",
"entityType": "farming_model",
"status": "applied",
"serverId": 850003,
"serverVersion": 1,
"error": null,
"serverState": null
}
],
"idMap": [
{
"entityType": "farmer",
"clientId": "3f6c1a2e-0000-4000-8000-000000061442",
"serverId": 700002
},
{
"entityType": "land",
"clientId": "4a7d2b3f-0000-4000-8000-000000004098",
"serverId": 810002
},
{
"entityType": "kap_plan",
"clientId": "a03d8b9f-0000-4000-8000-000000000001",
"serverId": 870001
},
{
"entityType": "farming_model",
"clientId": "6c9f4d5b-0000-4000-8000-000000012291",
"serverId": 850003
}
]
}| Field | Type | Required | Rules | Meaning |
|---|---|---|---|---|
batchId | string (uuid) | Yes | ||
processedAt | string (date-time) | No | ||
results | SyncOpResult[] | Yes | One per op, same order. | |
idMap | IdMapping[] | Yes | Client UUID -> server id for every entity created or referenced. | |
changesCursor | string | No | Cursor after this batch's own writes; pass to `/farmers/changes` to skip echoes. |
202 Accepted for asynchronous processing; poll `Location`.
Schema SyncBatchStatus.
{
"batchId": "5d4c3b2a-0000-4000-8000-000000000193",
"state": "QUEUED",
"receivedAt": "2025-10-14T09:30:00+05:30",
"progress": {
"total": 100,
"processed": 0
},
"result": null
}| Field | Type | Required | Rules | Meaning |
|---|---|---|---|---|
batchId | string (uuid) | Yes | ||
state | string | Yes | one of QUEUED, PROCESSING, COMPLETED, FAILED | |
receivedAt | string (date-time) | No | ||
completedAt | string (date-time) | No | ||
progress | object | No | ||
result | SyncBatchResult | null | No |
400 Malformed batch (schema) or too many ops.
Schema Problem.
{
"type": "https://urvi.example.invalid/problems/batch-too-large",
"title": "Too many operations",
"status": 400,
"detail": "A batch may contain at most 100 operations.",
"code": "BATCH_TOO_LARGE",
"requestId": "0e0c5a1b-0000-4000-8000-0000000000a1"
}401 Missing, invalid or expired access token. Refresh once, then ask the user to log in; pending outbox ops stay intact.
Schema Problem.
{
"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.
{
"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"
}409 The same `batchId` is still being processed.
Schema Problem.
{
"type": "https://urvi.example.invalid/problems/idempotency-key-reused",
"title": "Batch in progress",
"status": 409,
"detail": "This batch is already being processed; poll its status.",
"code": "IDEMPOTENCY_KEY_REUSED",
"requestId": "0e0c5a1b-0000-4000-8000-0000000000a1"
}412 Precondition failed for the whole batch (e.g. device binding lost).
Schema Problem.
{
"type": "https://urvi.example.invalid/problems/precondition-failed",
"title": "Device not bound",
"status": 412,
"detail": "This device is no longer bound to the user.",
"code": "PRECONDITION_FAILED",
"requestId": "0e0c5a1b-0000-4000-8000-0000000000a1"
}422 The `Idempotency-Key` was reused with a different body. Per-op rule violations are NOT returned here; they appear as `rejected` results with HTTP 200.
Schema Problem.
{
"type": "https://urvi.example.invalid/problems/idempotency-key-reused",
"title": "Idempotency key reused",
"status": 422,
"detail": "This key was used for a different request body.",
"code": "IDEMPOTENCY_KEY_REUSED",
"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.
{
"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.
{
"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.
{
"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"
}