APIs & services / portfolio-service

Update crop plans.

Endpointtoday's app
Call
PATCH /gateway/portfolio-service/api/v1/portfolios/
Service
portfolio-service
Features
Crop Actual (portfolio), Crop Plan
When
Queued sync (IE_PORTFOLIO PATCH)
Auth
X-SESSIONID stamped when queued (CoreAPI dooWithRetry); X-REQUESTID idempotency key
In the App Service

Use case

Queued update of a crop plan portfolio (IE_PORTFOLIO PATCH) - e.g. adding another line item to an existing portfolio. Sends a list with one portfolio. IEPortfolioPatchRH maps returned PLI ids by uuid and clears sync errors; error handling matches the POST (asset refresh worker, body fix-up, retry later).

Headers

HeaderValueNotes
X-SESSIONID<session token>Stamped when the operation is queued (dooWithRetry) and re-set by CoreAPI at send time; refreshed on 401.
X-REQUESTID<uuid v4>Idempotency key generated by OperationManagerImpl.createOperation for POST/PUT/PATCH when the op enters the offline queue.
X-ACK-REQUESTID<X-REQUESTID of an earlier completed op>Added by SyncQueueProcessor for POST/PUT/PATCH: acknowledges a request id the device already saw succeed.
Content-Typeapplication/jsonAdded by CoreAPI.

Request

Example request body (synthetic data)
[
  {
    "owningEntityId": "40001",
    "id": 5001,
    "uuid": "3a9d0000-0000-4000-8000-000000000101",
    "ownerEntityType": {
      "code": "ENTITY_TYPE.IE",
      "refClass": {
        "code": "CLASS.ENTITY_TYPE"
      }
    },
    "appMillMetadata": {
      "ie_appId": "ie-alias-0001"
    },
    "actor": {
      "actorId": "40001",
      "id": 0,
      "actorType": "ACTOR_TYPE.IE"
    },
    "portfolioLineItemList": [
      {
        "portfolioId": "3a9d0000-0000-4000-8000-000000000101",
        "id": 6001,
        "asset": "ASSET-CODE-0001",
        "uuid": "5f6c1d2e-0000-4000-8000-00000000a001",
        "practiceMasterCodes": [
          "PRACTICE.MULCHING",
          "PRACTICE.SEED_TREATMENT"
        ],
        "portfolioLineItemType": "PORTFOLIO_LINE_ITEM_TYPE.ACTUAL",
        "imageUrl": "/data/user/0/<app>/files/pli_6001.jpg",
        "isActive": true,
        "currentSeason": "KHARIF_2026",
        "methodMaster": {
          "id": 3,
          "uuid": "m-0003",
          "methodCode": "METHOD.PMDS"
        },
        "practiceMaster": {
          "practiceCode": "PRACTICE.MULCHING",
          "id": 4,
          "uuid": "p-0004"
        },
        "appCreatedAt": "1780000000000",
        "appLastModifiedAt": "1780000000000",
        "createdAt": null,
        "lastModifiedAt": null,
        "titleId": "TILE-0001",
        "assetId": 9001,
        "assetCheckSum": "<asset checksum>",
        "hasSyncError": false,
        "syncErrorId": null,
        "compactBlockId": null,
        "isLinkedToCompactBlock": false,
        "createdByApp": 109,
        "lastModifiedByApp": 109,
        "createdFromDevice": "<device id>",
        "lastUpdatedFromDevice": "<device id>",
        "geoFencingFileName": null,
        "geoFencingCreatedOn": null,
        "geoFencingFilePath": null,
        "geoFenceAttachments": null,
        "isEditable": true,
        "imageAttachmentId": null,
        "imageCreatedAt": null,
        "changeLog": null,
        "cropSeason": "KHARIF",
        "isAttachmentFetched": false,
        "portfolioProductLineItemList": [
          {
            "portfolioLineItemId": "5f6c1d2e-0000-4000-8000-00000000a001",
            "id": 7001,
            "uuid": "7b1e0000-0000-4000-8000-000000000201",
            "genericProduct": "PRODUCT.PADDY",
            "plannedStartDate": "2026-06-01",
            "plannedEndDate": "2026-10-31",
            "actualStartDate": "2026-06-05",
            "actualEndDate": null,
            "cropChangeReason": null,
            "assetProportion": {
              "id": 0,
              "uoM": {
                "code": "UOM.ACRE",
                "description": "Acre",
                "measurementType": {
                  "code": "MEASUREMENT_TYPE.AREA",
                  "description": "Area",
                  "globalRefClass": {
                    "code": "GREF.MEASUREMENT_TYPE",
                    "description": "",
                    "name": "Measurement type"
                  },
                  "name": "Area"
                },
                "name": "Acre",
                "symbol": "ac"
              },
              "value": 0.5
            },
            "isMajorCrop": true,
            "cropType": "CROP_TYPE.MAIN",
            "harvestStatus": "HARVEST_STATUS.PENDING",
            "harvestStartDateTime": null,
            "harvestCompleteDateTime": null,
            "appCreatedAt": "1780000000000",
            "appLastModifiedAt": "1780000000000",
            "createdAt": null,
            "lastModifiedAt": null,
            "ppliCropType": "PPLI_CROP_TYPE.PMDS",
            "expectedHarvestDate": "2026-10-15",
            "seedSource": "SEED_SOURCE.OWN",
            "seedVariety": "Variety A",
            "interestedInCropMarketing": false,
            "sowingDate": "2026-06-05",
            "appId": "7b1e0000-0000-4000-8000-000000000201",
            "syncStatus": "SYNC_PENDING"
          }
        ],
        "portfolioLineItemQuestionResponses": [
          {
            "portfolioLineItemAppId": "5f6c1d2e-0000-4000-8000-00000000a001",
            "id": 0,
            "uuid": "8c2f0000-0000-4000-8000-000000000301",
            "questionId": 12,
            "category": "PMDS",
            "subCategory": "SEED_TREATMENT",
            "questionType": "SINGLE_SELECT",
            "questionCode": "Q_SEED_TREATMENT",
            "questionLabel": "Seed treated?",
            "answerLanguageCode": "en",
            "answerValue": "YES",
            "answerLabel": "Yes",
            "answerText": null,
            "appCreatedAt": "1780000000000",
            "appLastModifiedAt": "1780000000000"
          }
        ],
        "isSelected": false,
        "isPresentInDifferentCB": false,
        "appId": "5f6c1d2e-0000-4000-8000-00000000a001",
        "syncStatus": "SYNC_PENDING"
      }
    ],
    "appId": "3a9d0000-0000-4000-8000-000000000101",
    "syncStatus": "SYNC_PENDING"
  }
]
FieldTypeRequiredNotes
[] (array of one Portfolio)arrayYesSame shape as the line-items/v2 POST body.
[0].portfolioLineItemList[].idintegerNoServer PLI id (0/null on first create). Column portfolio_portfoliolineitem.id.
[0].portfolioLineItemList[].uuidstringYesClient UUID; server echoes it so the RH can map ids back.
[0].portfolioLineItemList[].asset / assetId / assetCheckSumstring / integer / stringYesLand (asset) code, server asset id and checksum from the Land Assets table. Checksum mismatch -> ERR_PLATFORM_ASSET_CHECKSUM_MISMATCH.
[0].portfolioLineItemList[].titleIdstringNoLand tile id used to match geofence files and compact blocks.
[0].portfolioLineItemList[].portfolioLineItemTypestringYesPLAN vs ACTUAL (crop plan / crop actual screen).
[0].portfolioLineItemList[].currentSeason / cropSeasonstringNoFrom app config CURRENT_SEASON.
[0].portfolioLineItemList[].practiceMasterCodesstring[]NoPractices ticked on the crop actual screen (practicemaster table).
[0].portfolioLineItemList[].methodMaster / practiceMasterobjectNoMethod (PMDS/RDS) and practice selected.
[0].portfolioLineItemList[].portfolioProductLineItemList[]arrayYesOne entry per crop on the land: genericProduct, cropType, ppliCropType, assetProportion (area value + UoM), planned/actual dates, sowingDate, seedSource, seedVariety, expectedHarvestDate, harvestStatus, isMajorCrop.
[0].portfolioLineItemList[].portfolioLineItemQuestionResponses[]arrayNoPMDS A-grade question answers (portfolio_question_response table).
[0].portfolioLineItemList[].createdByApp / lastModifiedByApp / createdFromDevice / lastUpdatedFromDevicelong / stringNoAudit fields set by the app.
[0].portfolioLineItemList[].appCreatedAt / appLastModifiedAtstring (epoch ms)NoDevice timestamps.
[0].portfolioLineItemList[].imageUrl, geoFencing*, hasSyncError, syncErrorId, isEditable, isSelected, isPresentInDifferentCB, practices, appId, opId, syncStatusmixedNoLocal-only columns that Gson also serialises; the server ignores them.

Response

Example response body (synthetic data)
[
  {
    "owningEntityId": "40001",
    "id": 5001,
    "uuid": "3a9d0000-0000-4000-8000-000000000101",
    "ownerEntityType": {
      "code": "ENTITY_TYPE.IE",
      "refClass": {
        "code": "CLASS.ENTITY_TYPE"
      }
    },
    "actor": {
      "actorId": "40001",
      "id": 0,
      "actorType": "ACTOR_TYPE.IE"
    },
    "portfolioLineItemList": [
      {
        "portfolioId": "3a9d0000-0000-4000-8000-000000000101",
        "id": 6001,
        "asset": "ASSET-CODE-0001",
        "uuid": "5f6c1d2e-0000-4000-8000-00000000a001",
        "practiceMasterCodes": [
          "PRACTICE.MULCHING",
          "PRACTICE.SEED_TREATMENT"
        ],
        "portfolioLineItemType": "PORTFOLIO_LINE_ITEM_TYPE.ACTUAL",
        "imageUrl": "/data/user/0/<app>/files/pli_6001.jpg",
        "isActive": true,
        "currentSeason": "KHARIF_2026",
        "methodMaster": {
          "id": 3,
          "uuid": "m-0003",
          "methodCode": "METHOD.PMDS"
        },
        "practiceMaster": {
          "practiceCode": "PRACTICE.MULCHING",
          "id": 4,
          "uuid": "p-0004"
        },
        "appCreatedAt": "1780000000000",
        "appLastModifiedAt": "1780000000000",
        "createdAt": null,
        "lastModifiedAt": null,
        "titleId": "TILE-0001",
        "assetId": 9001,
        "assetCheckSum": "<asset checksum>",
        "hasSyncError": false,
        "syncErrorId": null,
        "compactBlockId": null,
        "isLinkedToCompactBlock": false,
        "createdByApp": 109,
        "lastModifiedByApp": 109,
        "createdFromDevice": "<device id>",
        "lastUpdatedFromDevice": "<device id>",
        "geoFencingFileName": null,
        "geoFencingCreatedOn": null,
        "geoFencingFilePath": null,
        "geoFenceAttachments": null,
        "isEditable": true,
        "imageAttachmentId": null,
        "imageCreatedAt": null,
        "changeLog": null,
        "cropSeason": "KHARIF",
        "isAttachmentFetched": false,
        "portfolioProductLineItemList": [
          {
            "portfolioLineItemId": "5f6c1d2e-0000-4000-8000-00000000a001",
            "id": 7001,
            "uuid": "7b1e0000-0000-4000-8000-000000000201",
            "genericProduct": "PRODUCT.PADDY",
            "plannedStartDate": "2026-06-01",
            "plannedEndDate": "2026-10-31",
            "actualStartDate": "2026-06-05",
            "actualEndDate": null,
            "cropChangeReason": null,
            "assetProportion": {
              "id": 0,
              "uoM": {
                "code": "UOM.ACRE",
                "description": "Acre",
                "measurementType": {
                  "code": "MEASUREMENT_TYPE.AREA",
                  "description": "Area",
                  "globalRefClass": {
                    "code": "GREF.MEASUREMENT_TYPE",
                    "description": "",
                    "name": "Measurement type"
                  },
                  "name": "Area"
                },
                "name": "Acre",
                "symbol": "ac"
              },
              "value": 0.5
            },
            "isMajorCrop": true,
            "cropType": "CROP_TYPE.MAIN",
            "harvestStatus": "HARVEST_STATUS.PENDING",
            "harvestStartDateTime": null,
            "harvestCompleteDateTime": null,
            "appCreatedAt": "1780000000000",
            "appLastModifiedAt": "1780000000000",
            "createdAt": null,
            "lastModifiedAt": null,
            "ppliCropType": "PPLI_CROP_TYPE.PMDS",
            "expectedHarvestDate": "2026-10-15",
            "seedSource": "SEED_SOURCE.OWN",
            "seedVariety": "Variety A",
            "interestedInCropMarketing": false,
            "sowingDate": "2026-06-05",
            "appId": "7b1e0000-0000-4000-8000-000000000201",
            "syncStatus": "SYNC_PENDING"
          }
        ],
        "portfolioLineItemQuestionResponses": [
          {
            "portfolioLineItemAppId": "5f6c1d2e-0000-4000-8000-00000000a001",
            "id": 0,
            "uuid": "8c2f0000-0000-4000-8000-000000000301",
            "questionId": 12,
            "category": "PMDS",
            "subCategory": "SEED_TREATMENT",
            "questionType": "SINGLE_SELECT",
            "questionCode": "Q_SEED_TREATMENT",
            "questionLabel": "Seed treated?",
            "answerLanguageCode": "en",
            "answerValue": "YES",
            "answerLabel": "Yes",
            "answerText": null,
            "appCreatedAt": "1780000000000",
            "appLastModifiedAt": "1780000000000"
          }
        ],
        "isSelected": false,
        "isPresentInDifferentCB": false,
        "appId": "5f6c1d2e-0000-4000-8000-00000000a001",
        "syncStatus": "SYNC_PENDING"
      }
    ]
  }
]
FieldTypeRequiredNotes
[].portfolioLineItemList[] ids/uuidsmixedupdateOptionLineItemIds.

Errors

StatusWhenWhat the app does
4xx with asset errorCodeChecksum mismatch / quantity limitFetchFarmerAssetDataWorker scheduled; queued body refreshed; retried later.
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/entity/Portfolio.kt
  • data/src/main/java/org/mindtree/app/agricultor/data/sync/work/IEPortfolioWorker.kt
  • data/src/main/java/org/mindtree/app/agricultor/data/sync/rh/IEPortfolioPatchRH.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