API contracts / App Service v2 / Files

Create a file upload (resumable or single-shot)

OperationcreateFileUpload
Call
POST /gateway/urvi-app-service/api/v2/files
Group
Files
Features
Add/Edit farmer (IE profile), Land assets, Leased land, Geofencing, Crop Actual (portfolio), ATM model (Anytime Money plot), ATM harvest, Crop Actual harvest, Certification survey, Activity Tracker, VO / SHG / Farmer endorsement, VO / SHG surveys, Device registration and remote actions, Pending sync
Replaces today

Use case. Called by the outbox worker before the ops that reference a file: farmer photo, crop / ATM / harvest / activity photos, land / crop / ATM KML geofences, certification signatures, assessment attachments, endorsement abstracts and remote-action diagnostics. The file may be uploaded before its parent exists on the server; ops reference it by fileId. JSON body creates a resumable upload (then PATCH /files/{fileId} with Upload-Offset); multipart/form-data uploads a small file (<= 1 MB) in one request and returns COMPLETE. Never re-uploads server images and never falls back to another store.

Rules.

  • Idempotent on clientId: a repeat returns the existing upload with its current offset.
  • Allowed types per kind: images (jpeg, png, webp) for PHOTO_*; application/vnd.google-earth.kml+xml for KML_GEOFENCE; png for SIGNATURE; image, PDF or Word for ENDORSEMENT_ABSTRACT; encrypted zip for DIAGNOSTICS.
  • Max 20 MB; incomplete uploads expire after 7 days.

Error codes. FILE_TOO_LARGE, UNSUPPORTED_MEDIA_TYPE, FILE_CHECKSUM_MISMATCH, INVALID_KML

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
Idempotency-Keyheaderstring (uuid)YesUUID 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 FileUploadRequest.

Example request body
{
  "fileName": "crop-840001.jpg",
  "mimeType": "image/jpeg",
  "sizeBytes": 48213,
  "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "kind": "PHOTO_CROP",
  "clientId": "7a6b5c4d-0000-4000-8000-000000000226",
  "ownerClientId": "5b8e3c4a-0000-4000-8000-000000008193"
}
FieldTypeRequiredRulesMeaning
fileNamestringYesmax length 200
mimeTypestringYes
sizeBytesintegerYes≥ 1; ≤ 20971520Max 20 MB (`FILE_TOO_LARGE`).
sha256stringYespattern ^[a-f0-9]{64}$
kindFileKindYesone of PHOTO_FARMER, PHOTO_CROP, PHOTO_ATM, PHOTO_HARVEST, PHOTO_ACTIVITY, KML_GEOFENCE, SIGNATURE, ENDORSEMENT_ABSTRACT, ASSESSMENT_ATTACHMENT, DIAGNOSTICS
clientIdstring (uuid)YesClient UUID of the file (idempotent create).
ownerClientIdstring (uuid)NoOptional: entity the file will belong to (it may not exist on the server yet).

Responses

201 Upload created (PENDING) or completed (multipart).

Schema FileUpload.

Example 201 body
{
  "fileId": "7a6b5c4d-0000-4000-8000-000000000226",
  "status": "PENDING",
  "uploadOffset": 0,
  "sizeBytes": 48213,
  "uploadUrl": "https://api.example.invalid/gateway/urvi-app-service/api/v2/files/7a6b5c4d-0000-4000-8000-000000000226",
  "expiresAt": "2025-10-21T09:30:00+05:30"
}
FieldTypeRequiredRulesMeaning
fileIdstring (uuid)Yes
statusstringYesone of PENDING, COMPLETE
uploadOffsetintegerYes≥ 0
sizeBytesintegerYes≥ 1
uploadUrlstring (uri)NoWhere to PATCH chunks (this API) or a presigned URL.
expiresAtstring (date-time)NoIncomplete uploads expire after this.

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

409 Same `clientId` with different size or checksum.

Schema Problem.

Example 409 body
{
  "type": "https://urvi.example.invalid/problems/file-checksum-mismatch",
  "title": "File differs",
  "status": 409,
  "detail": "An upload with this id exists with a different checksum.",
  "code": "FILE_CHECKSUM_MISMATCH",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1"
}

413 File too large.

Schema Problem.

Example 413 body
{
  "type": "https://urvi.example.invalid/problems/file-too-large",
  "title": "File too large",
  "status": 413,
  "detail": "Files may be at most 20 MB.",
  "code": "FILE_TOO_LARGE",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1"
}

415 Media type not allowed for this kind.

Schema Problem.

Example 415 body
{
  "type": "https://urvi.example.invalid/problems/unsupported-media-type",
  "title": "Unsupported file type",
  "status": 415,
  "detail": "KML_GEOFENCE accepts KML files only.",
  "code": "UNSUPPORTED_MEDIA_TYPE",
  "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"
}