APIs & services / asset-service

Upload the abstract file attached to an endorsement.

Endpointtoday's app
Call
POST /gateway/asset-service/api/v1/endorsements/attachment?endorsementID&endorsementUUID
Service
asset-service
Features
VO / SHG / Farmer endorsement
When
Queued sync (ENDORSEMENT_ATTACHMENT)
Auth
X-SESSIONID stamped when queued (CoreAPI dooWithRetry); X-REQUESTID idempotency key
In the App Service

Use case

Uploads the abstract file a cadre attaches to an endorsement on the endorsement screen (EndorsementRepositoryImpl.uploadEndorsementAbstract -> DataRepository.uploadEndorsementAbstract). The repository saves the file path on the row and adds an ENDORSEMENT_ATTACHMENT POST ledger entry that depends on the endorsement POST. EndorsementWorker.postAttachment queues EndorsementEntity.postAttachment(): multipart "file" plus URI params for the endorsement id and uuid. On 2xx, EndorsementAttachmentRH only closes the ledger; the body is not read. On error it retries later.

Headers

HeaderValueNotes
X-SESSIONID<session id>Stamped by CoreAPI when the queued operation runs (CoreAPIDefaultImpl.doOperation). On a 401 the token is invalidated and the call retried. BaseResponseHandler also refreshes the session after a 500 on a gateway URL (first 5 attempts).
X-REQUESTID(removed)CoreAPIDefaultImpl.processOperation removes X-REQUESTID for multipart requests, so file uploads have no idempotency key.
Content-Typemultipart/form-data; boundary=<generated>Built by CoreAPI makeMultiPartHttpRequest because the operation has a File param.

Parameters

ParamInRequiredExampleNotes
endorsementIDqueryYes3101EndorsementEntity.id. If the parent POST has not finished, this may be 0 because the value is captured when the operation is built.
endorsementUUIDqueryYese0000000-0000-4000-8000-000000003101EndorsementEntity.uuid.
fileformYesSHG_A_abstract.xlsxFile at EndorsementEntity.abstractFile. PII: abstract report contents.

Request

Example request body (synthetic data)
{
  "file": {
    "part": "binary abstract file (Excel/PDF)"
  }
}
FieldTypeRequiredNotes
filefileYesPicked or generated abstract file.

Response

Example response body (synthetic data)
{
  "id": 42001,
  "uuid": "a1b2c3d4-0000-4000-8000-000000000042",
  "attachmentUUID": "a1b2c3d4-0000-4000-8000-000000000042",
  "fileName": "land_5501_geofence.kml",
  "attachmentDateTime": "2025-06-02 10:15:00",
  "attachmentKind": "ATTACHMENT_KIND.FILE",
  "attachmentKindMetaData": "<?xml version=\"1.0\"?><kml>...polygon...</kml>",
  "attachmentKindIdentifier": null,
  "tempAttachmentURL": "https://<signed-download-host>/<path>?<signature>",
  "appCreatedAt": "1748859300000"
}
FieldTypeRequiredNotes
(body)AttachmentResponseNot read by the app.

Errors

StatusWhenWhat the app does
401Session expiredCoreAPI invalidates the session id and retries once. If it still fails, the response handler returns TryAgain.LATER and the operation stays in the queue.
409Duplicate X-REQUESTIDSyncQueueProcessor records the request id and swaps in a fresh X-REQUESTID for the next attempt.
4xx/5xx (other)Server rejects or failsonError returns TryAgain.LATER (EndorsementAttachmentRH). Each failure is logged in the local error_log table (URL, body, headers). Every 10th attempt (up to attempt 5000) the whole operation is copied to Firestore urvi_sync_log. A 500 on a gateway URL in the first 5 attempts forces a session refresh.

Source

  • data/src/main/java/org/mindtree/app/agricultor/data/sync/entity/EndorsementEntity.kt
  • data/src/main/java/org/mindtree/app/agricultor/data/sync/work/EndorsementWorker.kt
  • data/src/main/java/org/mindtree/app/agricultor/data/sync/rh/EndorsementAttachmentRH.kt
  • data/src/main/java/org/mindtree/app/agricultor/data/repo/DataRepository.kt
  • app/src/main/java/org/platformcommons/urvi/datasource/repository/impl/EndorsementRepositoryImpl.kt