APIs & services / portfolio-service

Upload a crop photo, or (with saveFileContent=true, updatePortfolioLineItemWithGeoFenceAttachment=true) a crop KML geofence.

Endpointtoday's app
Call
POST /gateway/portfolio-service/api/v1/portfolios/line-items/attachment/item/custom
Service
portfolio-service
Features
Crop Actual (portfolio), Geofencing
When
Queued sync (IE_PORTFOLIO_LINE_ITEM POST image / SYNC_POST_GEOFENCING)
Auth
X-SESSIONID stamped when queued (CoreAPI dooWithRetry); X-REQUESTID idempotency key
In the App Service

Use case

Queued multipart upload for a crop line item: the crop photo (IE_PORTFOLIO_LINE_ITEM POST -> PortfolioLineItemPicRH) or the land geofence KML (SYNC_POST_GEOFENCING -> PortfolioLineItemGeofencingPostRH, with saveFileContent=true and updatePortfolioLineItemWithGeoFenceAttachment=true). An http image URL is downloaded first. On success the attachment id is saved as imageAttachmentId or added to geoFenceAttachments. On photo failures, after N attempts (config) the photo is uploaded to Firebase Storage as a fallback and the op closed; geofence failures fix the file path / refresh ids and retry.

Headers

HeaderValueNotes
X-SESSIONID<session token>Stamped when queued (dooWithRetry); refreshed on 401.
X-ACK-REQUESTID<X-REQUESTID of an earlier completed op>Added by SyncQueueProcessor for POST/PUT. X-REQUESTID is removed for multipart requests by CoreAPIDefaultImpl.processOperation.
Content-Typemultipart/form-data; boundary=<generated>Multipart because the op has a File param.

Parameters

ParamInRequiredExampleNotes
portfolioLineItemIdqueryYes6001Server PLI id.
portfolioIdqueryYes5001Server portfolio id (0 if unknown).
portfolioLineItemUUIDqueryYes5f6c1d2e-0000-4000-8000-00000000a001Client uuid.
appCreatedAtqueryYes1780000000000imageCreatedAt / geoFencingCreatedOn as epoch ms (now if missing).
portfolioLineItemMonthqueryYes2026/06/01First crop plannedStartDate reformatted yyyy/MM/dd.
saveFileContentqueryNotrueGeofence only.
updatePortfolioLineItemWithGeoFenceAttachmentqueryNotrueGeofence only.

Request

Example request body (synthetic data)
{
  "file": "<multipart part: pli_6001.jpg or geofence_tile_0001.kml>"
}
FieldTypeRequiredNotes
filebinaryYesLocal photo taken on the crop actual screen, or KML captured on the geofencing screen.

Response

Example response body (synthetic data)
{
  "attachmentDateTime": "2026-07-01T10:15:00.000+05:30",
  "fileName": "pli_6001.jpg",
  "attachmentKind": "ATTACHMENT_KIND.IMAGE",
  "attachmentKindMetaData": null,
  "attachmentKindIdentifier": 6001,
  "attachmentUUID": "a1b2c3d4-0000-4000-8000-000000000401",
  "id": 88001,
  "uuid": "a1b2c3d4-0000-4000-8000-000000000402",
  "tempAttachmentURL": "https://<storage-host>/signed/pli_6001.jpg?sig=<redacted>",
  "appCreatedAt": "1780000000000"
}
FieldTypeRequiredNotes
idintegerAttachment id; highest id per type wins. Stored as imageAttachmentId / geoFenceAttachments / geoFencingFileId.
attachmentDateTimestringSaved as geoFencingCreatedOn.
other fieldsmixedNot read.

Errors

StatusWhenWhat the app does
any, attempts >= FIREBASE_ATTACHMENT_UPLOAD_POST_FAIL_COUNT and FIREBASE_ATTACHMENT_UPLOAD_FLAG onPhoto upload keeps failingPhoto uploaded to Firebase Storage, metadata to Firestore; ledger marked done.
401Session token expired or invalidCoreAPI invalidates the session id and retries once immediately; if still failing the op stays in the queue (TryAgain.LATER).
500Server error on a /gateway URLBaseResponseHandler fetches a new session id (first 5 attempts) and returns TryAgain.LATER; retried per RetryScheduler policy (retry threshold/delay come from app config).
503Service unavailableCoreAPI retries once immediately, then the op is retried later by the sync queue.
any non-2xxAny other failureHandler onError -> TryAgain.LATER (op stays queued and is visible in Pending Sync); a row is written to the local error_log table (Sync Error Log screen) with URL, body, headers and raw response; every 10th attempt the op is mirrored to Firestore for support.

Source

  • data/src/main/java/org/mindtree/app/agricultor/data/sync/work/PortfolioLineItemWorker.kt
  • data/src/main/java/org/mindtree/app/agricultor/data/sync/rh/PortfolioLineItemPicRH.kt
  • data/src/main/java/org/mindtree/app/agricultor/data/sync/rh/PortfolioLineItemGeofencingPostRH.kt
  • data/src/main/java/org/mindtree/app/agricultor/data/setup/AttachmentResponse.kt
  • data/src/main/java/org/mindtree/app/agricultor/data/manager/CoreAPIManager.kt
  • data/src/main/java/org/mindtree/app/agricultor/data/sync/rh/BaseResponseHandler.kt
  • offline-core/src/main/java/com/mindtree/bridge/coreapi/offline/SyncQueueProcessor.java
  • offline-core/src/main/java/com/mindtree/bridge/coreapi/offline/manager/OperationManagerImpl.java
  • core-api/src/main/java/com/mindtree/bridge/coreapi/impl/CoreAPIDefaultImpl.java