APIs & services / portfolio-service

Create a farming model (ATM / DKG).

Endpointtoday's app
Call
POST /gateway/portfolio-service/api/v1/farming-model
Service
portfolio-service
Features
ATM model (Anytime Money plot), 365 DKG kitchen garden
When
Queued sync (IE_ATM POST)
Auth
X-SESSIONID stamped when queued (CoreAPI dooWithRetry); X-REQUESTID idempotency key
In the App Service

Use case

Queued create of an ATM or DKG farming model (IE_ATM POST via ATMWorker) after the user saves the ATM/DKG form. The worker fills owningEntityId from the farmer alias and assetId from the land table. FarmingModelPostRH saves the server id and line item ids and clears sync errors. Asset errors schedule FetchFarmerAssetDataWorker (isATM=true); ERR-PLT-GEN-101 re-resolves owningEntityId; the body is refreshed and retried.

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)
{
  "uuid": "fm-0000-4000-8000-000000000501",
  "appCreatedAt": 1780000000000,
  "id": null,
  "raisedBeds": true,
  "vegetableCrops": "PRODUCT.SPINACH,PRODUCT.OKRA",
  "maizeCultivation": false,
  "pulseCrops": "PRODUCT.REDGRAM",
  "practices": "PRACTICE.MULCHING",
  "relayCropping": false,
  "relayCroppingDetails": null,
  "incomeGeneration": true,
  "incomeGenerationDetails": "Sells surplus locally",
  "titleId": "TILE-0002",
  "owningEntityId": "40001",
  "owningEntityType": "ENTITY_TYPE.IE",
  "aliasId": "ie-alias-0001",
  "landSize": 0.1,
  "isDKG": false,
  "modelType": "MODEL_TYPE.ATM",
  "assetId": 9002,
  "asset": "ASSET-CODE-0002",
  "assetCheckSum": "<asset checksum>",
  "hasSyncError": false,
  "syncErrorId": null,
  "lastModifiedAt": null,
  "geoFencingFileId": null,
  "geoFencingFileName": null,
  "geoFencingCreatedOn": null,
  "geoFencingFilePath": null,
  "geotaggingFileName": null,
  "geotaggingCreatedOn": null,
  "geotaggingFilePath": null,
  "farmingModelLineItemDTOs": [
    {
      "actualOutput": null,
      "appCreatedAt": 1780000000000,
      "appLastModifiedAt": 1780000000000,
      "createdAt": null,
      "cropChangeReason": null,
      "cropSubType": "CROP_SUB_TYPE.LEAFY",
      "cropType": "CROP_TYPE.VEGETABLE",
      "earlyHarvestReason": null,
      "expectedHarvestDate": "2026-09-01",
      "expectedOutput": null,
      "genericProduct": "PRODUCT.SPINACH",
      "harvestCompleteDateTime": null,
      "harvestStartDateTime": null,
      "harvestStatus": "HARVEST_STATUS.PENDING",
      "harvestType": null,
      "id": null,
      "inactiveAt": null,
      "inactiveReason": null,
      "interestedInCropMarketing": false,
      "isActive": true,
      "isMajorCrop": false,
      "lastModifiedAt": null,
      "surplusOutput": null
    }
  ],
  "imageUrl": null,
  "imageAttachmentId": null,
  "imageCreatedAt": null,
  "appId": "fm-0000-4000-8000-000000000501",
  "syncStatus": "SYNC_PENDING"
}
FieldTypeRequiredNotes
uuidstringYesClient id; RH maps server id back by uuid (farming_model table).
owningEntityId / owningEntityType / aliasIdstringYesFarmer IE id (resolved from aliasId if 0), ENTITY_TYPE.IE, farmer alias.
modelType / isDKGstring / booleanYesATM model vs DKG (kitchen garden) screen.
asset / assetId / assetCheckSum / titleId / landSizemixedYesSelected land; assetId filled from land assets table if missing.
raisedBeds, vegetableCrops, maizeCultivation, pulseCrops, practices, relayCropping(+Details), incomeGeneration(+Details)mixedNoAnswers on the ATM / DKG form.
farmingModelLineItemDTOs[]arrayNoOne per crop: genericProduct, cropType, cropSubType, expectedHarvestDate, isMajorCrop, harvestStatus, etc.
appCreatedAtlongNoDevice timestamp.
geo*, image*, hasSyncError, syncErrorId, appId, opId, syncStatusmixedNoLocal-only columns serialised by Gson; ignored by server.

Response

Example response body (synthetic data)
{
  "uuid": "fm-0000-4000-8000-000000000501",
  "appCreatedAt": 1780000000000,
  "id": 5501,
  "raisedBeds": true,
  "vegetableCrops": "PRODUCT.SPINACH,PRODUCT.OKRA",
  "maizeCultivation": false,
  "pulseCrops": "PRODUCT.REDGRAM",
  "practices": "PRACTICE.MULCHING",
  "relayCropping": false,
  "relayCroppingDetails": null,
  "incomeGeneration": true,
  "incomeGenerationDetails": "Sells surplus locally",
  "titleId": "TILE-0002",
  "owningEntityId": "40001",
  "owningEntityType": "ENTITY_TYPE.IE",
  "aliasId": "ie-alias-0001",
  "landSize": 0.1,
  "isDKG": false,
  "modelType": "MODEL_TYPE.ATM",
  "assetId": 9002,
  "asset": "ASSET-CODE-0002",
  "assetCheckSum": "<asset checksum>",
  "hasSyncError": false,
  "syncErrorId": null,
  "lastModifiedAt": null,
  "geoFencingFileId": null,
  "geoFencingFileName": null,
  "geoFencingCreatedOn": null,
  "geoFencingFilePath": null,
  "geotaggingFileName": null,
  "geotaggingCreatedOn": null,
  "geotaggingFilePath": null,
  "farmingModelLineItemDTOs": [
    {
      "actualOutput": null,
      "appCreatedAt": 1780000000000,
      "appLastModifiedAt": 1780000000000,
      "createdAt": null,
      "cropChangeReason": null,
      "cropSubType": "CROP_SUB_TYPE.LEAFY",
      "cropType": "CROP_TYPE.VEGETABLE",
      "earlyHarvestReason": null,
      "expectedHarvestDate": "2026-09-01",
      "expectedOutput": null,
      "genericProduct": "PRODUCT.SPINACH",
      "harvestCompleteDateTime": null,
      "harvestStartDateTime": null,
      "harvestStatus": "HARVEST_STATUS.PENDING",
      "harvestType": null,
      "id": 5601,
      "inactiveAt": null,
      "inactiveReason": null,
      "interestedInCropMarketing": false,
      "isActive": true,
      "isMajorCrop": false,
      "lastModifiedAt": null,
      "surplusOutput": null
    }
  ],
  "imageUrl": null,
  "imageAttachmentId": null,
  "imageCreatedAt": null
}
FieldTypeRequiredNotes
id / uuidmixedupdateFarmingModelId by uuid.
farmingModelLineItemDTOs[].idlongupdateFarmingModeLineItemsIds.

Errors

StatusWhenWhat the app does
4xx errorCode ERR_PLATFORM_ASSET_CHECKSUM_MISMATCH / ..._LIMIT_EXCEEDLand checksum/area problemFetchFarmerAssetDataWorker(isATM=true); assetId refreshed; retry.
4xx errorCode ERR-PLT-GEN-101Owner not foundowningEntityId re-resolved from alias; retry.
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/FarmingModel.kt
  • data/src/main/java/org/mindtree/app/agricultor/data/sync/work/ATMWorker.kt
  • data/src/main/java/org/mindtree/app/agricultor/data/sync/rh/FarmingModelPostRH.kt
  • app/src/main/java/org/platformcommons/urvi/bridge/BridgeSyncHelper.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