Docs › API reference › Harvest & traceability

Harvest & traceability

Harvest records, pre-harvest intervals, traceability lots, QR labels, certificates, market prices.

25 operations · base /api/v1/harvest

GET/api/v1/harvest/certifications

List the workspace's certificates

Scope: harvest.certification.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/certifications" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "certificate_number": "…",
    "expires_in_days": 1,
    "expiry_date": "2026-10-28",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "is_expired": true,
    "issued_by": "…",
    "issued_date": "2026-10-28",
    "name": "…",
    "parcel_code": "…",
    "parcel_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "scheme": "…"
  }
]
GET/api/v1/harvest/certifications/expiring

Expiring certificates

Sorted by expiry date ASCENDING — the longest-expired come first. within_days is the look-ahead window from today (default 90). include_expired is ON by default: the expired group is the most urgent.

Scope: harvest.certification.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
within_daysintqueryno—
include_expiredboolqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/certifications/expiring" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "certificate_number": "…",
    "expires_in_days": 1,
    "expiry_date": "2026-10-28",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "is_expired": true,
    "issued_by": "…",
    "issued_date": "2026-10-28",
    "name": "…",
    "parcel_code": "…",
    "parcel_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "scheme": "…"
  }
]
GET/api/v1/harvest/harvest-records

List harvest records

Filter by status. Paginated.

Scope: harvest.harvest.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
statusstringqueryno—
pageintqueryno—
pageSizeintqueryno—
filter_rulesstringqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/harvest-records" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "items": [
    {
      "actual_quantity_kg": 1.5,
      "created_at": "2026-10-28T07:30:00Z",
      "crop_type_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "crop_type_name": "…",
      "declared_quantity_kg": 1.5,
      "farming_task_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "harvest_date": "2026-10-28",
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "needs_review": true,
      "parcel_code": "…",
      "parcel_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "return_reason": "…",
      "returned_at": "2026-10-28T07:30:00Z",
      "season_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "status": "…",
      "trace_anchor_date": "2026-10-28",
      "trace_bundle_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "trace_incident": true,
      "trace_status": "…"
    }
  ],
  "page": 1,
  "page_size": 1,
  "total": 1
}
POST/api/v1/harvest/harvest-records

Declare a harvest

Creates a HarvestRecord. If confirm=true (default), it is confirmed immediately and harvest.declared is published. If confirm=false, it is saved as Draft.

Scope: harvest.harvest.createTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
confirmboolbodyno—
crop_type_idGUIDbodyno—
declared_quantity_kgintbodyno—
farming_task_idGUIDbodyno—
harvest_datedatebodyno—
notesstringbodyno—
organismsobjectbodyno—
parcel_idGUIDbodyno—
phi_override_reasonstringbodyno—
photo_urlsobjectbodyno—
season_idGUIDbodyno—

Example

curl -X POST "https://api-prod.nextfarm.vn/api/v1/harvest/harvest-records" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{ "confirm": true, "crop_type_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001", "declared_quantity_kg": 1.5, "farming_task_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001", "harvest_date": "2026-10-28", "notes": "…", "organisms": [ { "fruit_count": 1, "organism_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001", "quantity_kg": 1.5 } ], "parcel_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001", "phi_override_reason": "…", "photo_urls": [ "…" ], "season_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001" }'

Sample response

201 Created
{
  "created_at": "2026-10-28T07:30:00Z",
  "crop_type_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "crop_type_name": "…",
  "declared_quantity_kg": 1.5,
  "farming_task_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "harvest_date": "2026-10-28",
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "needs_review": true,
  "parcel_code": "…",
  "parcel_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "return_reason": "…",
  "returned_at": "2026-10-28T07:30:00Z",
  "season_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "status": "…",
  "trace_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "warnings": [
    "…"
  ]
}

Safe retries: lost the response and not sure the record was created? Resend it unchanged with the same Idempotency-Key — if it exists you get that same record back (201, same id); otherwise it is created. Without a key every call creates a new record.

GET/api/v1/harvest/harvest-records/preview-trace

Pre-lock check: what the trace bundle will receive

Scope: harvest.harvest.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
parcelIdGUIDqueryno—
seasonIdGUIDqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/harvest-records/preview-trace" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "certification_expiry": "2026-10-28",
  "certification_name": "…",
  "certification_number": "…",
  "has_season": true,
  "input_count": 1,
  "parcel_has_boundary": true,
  "season_name": "…",
  "stage_count": 1,
  "stages_with_photo": 1
}
GET/api/v1/harvest/harvest-records/summary

Yield summary by household / zone / crop / parcel

group_by = owner (by household) | zone (by zone) | crop (by crop) | parcel (by parcel). Only CONFIRMED records count (Confirmed · Verified · Collected); kg = actual weighed amount if verified, otherwise the declared amount. from/to filter by harvest date (yyyy-MM-dd), zoneId/cropTypeId filter further. Household and zone are fetched from gis at read time (if gis does not respond ⇒ an external service error is returned, NOT partial figures). Paginated (max 200 rows/page), sorted by total kg descending.

Scope: harvest.harvest.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
group_bystringqueryno—
fromdatequeryno—
todatequeryno—
zoneIdGUIDqueryno—
cropTypeIdGUIDqueryno—
pageintqueryno—
pageSizeintqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/harvest-records/summary" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "items": [
    {
      "key": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "name": "…",
      "parcel_count": 1,
      "record_count": 1,
      "total_kg": 1.5
    }
  ],
  "page": 1,
  "page_size": 1,
  "total": 1
}
GET/api/v1/harvest/harvest-records/{id}

Get a harvest record

Scope: harvest.harvest.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/harvest-records/<id>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "actual_quantity_kg": 1.5,
  "created_at": "2026-10-28T07:30:00Z",
  "crop_type_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "crop_type_name": "…",
  "declared_quantity_kg": 1.5,
  "farming_task_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "harvest_date": "2026-10-28",
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "needs_review": true,
  "parcel_code": "…",
  "parcel_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "return_reason": "…",
  "returned_at": "2026-10-28T07:30:00Z",
  "season_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "status": "…",
  "trace_anchor_date": "2026-10-28",
  "trace_bundle_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "trace_incident": true,
  "trace_status": "…"
}
PUT/api/v1/harvest/harvest-records/{id}

Update a harvest declaration

Can only be updated when status = draft.

Scope: harvest.harvest.createTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—
declared_quantity_kgintbodyno—
harvest_datedatebodyno—
notesstringbodyno—
phi_override_reasonstringbodyno—

Example

curl -X PUT "https://api-prod.nextfarm.vn/api/v1/harvest/harvest-records/<id>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{ "declared_quantity_kg": 1.5, "harvest_date": "2026-10-28", "notes": "…", "phi_override_reason": "…" }'

Sample response

200 OK
{
  "created_at": "2026-10-28T07:30:00Z",
  "crop_type_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "crop_type_name": "…",
  "declared_quantity_kg": 1.5,
  "farming_task_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "harvest_date": "2026-10-28",
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "needs_review": true,
  "parcel_code": "…",
  "parcel_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "return_reason": "…",
  "returned_at": "2026-10-28T07:30:00Z",
  "season_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "status": "…",
  "trace_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "warnings": [
    "…"
  ]
}
GET/api/v1/harvest/market-prices

List recorded prices

Filter by commodity (multiple codes), market/region and date range. Paginated.

Scope: harvest.market-prices.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
commodityCodeobjectqueryno—
marketstringqueryno—
fromDatedatequeryno—
toDatedatequeryno—
pageintqueryno—
pageSizeintqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/market-prices" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "items": [
    {
      "commodity_code": "…",
      "commodity_name": "…",
      "created_at": "2026-10-28T07:30:00Z",
      "grade": "…",
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "market": "…",
      "note": "…",
      "recorded_by_name": "…",
      "recorded_on": "2026-10-28",
      "source": "…",
      "unit": "…",
      "unit_price": 1.5
    }
  ],
  "page": 1,
  "page_size": 1,
  "total": 1
}
GET/api/v1/harvest/market-prices/series

Price series over time for charting

All series are returned in THE SAME unit (the response-level `unit` field). The FE chart has only one y-axis — commodities with a different unit are skipped, NOT converted, because guessing a wrong conversion factor silently corrupts the data. If `unit` is not passed, the most common unit in the filtered range is used.

Scope: harvest.market-prices.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
commodityCodeobjectqueryno—
fromDatedatequeryno—
toDatedatequeryno—
unitstringqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/market-prices/series" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "series": [
    {
      "commodity_code": "…",
      "commodity_name": "…",
      "points": [
        {
          "recorded_on": "2026-10-28",
          "unit_price": 1.5
        }
      ],
      "unit": "…"
    }
  ],
  "unit": "…"
}
GET/api/v1/harvest/market-prices/{id}

Get a price record

Scope: harvest.market-prices.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/market-prices/<id>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "commodity_code": "…",
  "commodity_name": "…",
  "created_at": "2026-10-28T07:30:00Z",
  "grade": "…",
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "market": "…",
  "note": "…",
  "recorded_by_name": "…",
  "recorded_on": "2026-10-28",
  "source": "…",
  "unit": "…",
  "unit_price": 1.5
}
GET/api/v1/harvest/parcels/phi-active

Parcels currently within a pre-harvest interval

Combines spray events logged in the journal, pesticide issue slips and veterinary drugs from inventory, and veterinary drugs in herd/pond books — i.e. both orchard parcels and ponds/barns currently within a pre-harvest interval or drug withdrawal period. on = the date evaluated (defaults to today, Vietnam time). Each row: parcel_id, safe_from (earliest allowed harvest date), blocking (drug applications holding the interval; kind = spray | inventory | inventory_vet | vet). Scoped to the viewer's parcel scope. Used by the Harvest and Farm overview screens.

Scope: harvest.harvest.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
ondatequeryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/parcels/phi-active" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "active": true,
    "blocking": {
      "active_ingredient": "…",
      "field_log_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "kind": "…",
      "phi_days": 1,
      "product": "…",
      "safe_from": "2026-10-28",
      "sprayed_on": "2026-10-28"
    },
    "on_date": "2026-10-28",
    "parcel_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "safe_from": "2026-10-28"
  }
]
GET/api/v1/harvest/parcels/{parcelId}/phi-status

Whether a parcel is within a pre-harvest interval

Computed from pesticide spray events (and veterinary drugs in herd/pond books) that record a pre-harvest interval in days. on = the planned harvest date (yyyy-MM-dd, defaults to today, Vietnam time). active=true ⇒ declaring a harvest on that date will be blocked unless a reason is given; safe_from = the earliest allowed harvest date.

Scope: harvest.harvest.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
parcelIdGUIDpathyes—
ondatequeryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/parcels/<parcelId>/phi-status" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "active": true,
  "blocking": {
    "active_ingredient": "…",
    "field_log_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "kind": "…",
    "phi_days": 1,
    "product": "…",
    "safe_from": "2026-10-28",
    "sprayed_on": "2026-10-28"
  },
  "on_date": "2026-10-28",
  "parcel_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "safe_from": "2026-10-28"
}
GET/api/v1/harvest/product-infos

List product profiles

Includes the workspace's own profiles and shared profiles (empty workspace_id).

Scope: harvest.trace.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/product-infos" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "benefits": [
      {
        "description": "…",
        "title": "…"
      }
    ],
    "crop_name": "…",
    "display_name": "…",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "image_urls": [
      "…"
    ],
    "is_active": true,
    "tagline": "…",
    "updated_at": "2026-10-28T07:30:00Z",
    "usage_note": "…",
    "workspace_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
  }
]
GET/api/v1/harvest/qr-codes

List QR codes of a season

Scope: harvest.qr-codes.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
seasonIdGUIDqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/qr-codes" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "code": "…",
    "created_at": "2026-10-28T07:30:00Z",
    "effective_to": "2026-10-28",
    "first_scanned_at": "2026-10-28T07:30:00Z",
    "harvest_date": "2026-10-28",
    "harvest_record_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "last_scanned_at": "2026-10-28T07:30:00Z",
    "scan_count": 1,
    "season_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
  }
]
GET/api/v1/harvest/qr-codes/usage

Labels used / cap of the Free plan (5 labels total per workspace)

Scope: harvest.qr-codes.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/qr-codes/usage" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "limit": 1,
  "remaining": 1,
  "used": 1
}
GET/api/v1/harvest/qr-codes/{id}/scans

Daily scans of a QR code

Scope: harvest.qr-codes.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—
daysintqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/qr-codes/<id>/scans" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "code": "…",
  "days": [
    {
      "day": "2026-10-28",
      "visitors": 1
    }
  ],
  "first_scanned_at": "2026-10-28T07:30:00Z",
  "last_scanned_at": "2026-10-28T07:30:00Z",
  "qr_code_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
  "scan_count": 1,
  "warn_threshold": 1
}
GET/api/v1/harvest/trace

List the workspace's TraceBundles (sign-in required)

Scope: harvest.trace.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/trace" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "anchor_date": "2026-10-28",
    "anchor_is_backfill": true,
    "anchor_status": "…",
    "bundle_version": 1,
    "certification": "…",
    "content_hash": "…",
    "created_at": "2026-10-28T07:30:00Z",
    "farmer": "…",
    "harvest_date": "2026-10-28",
    "harvest_record_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "has_open_incident": true,
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "is_locked": true,
    "parcel_code": "…",
    "product": "…",
    "season_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "stage_count": 1,
    "zone_name": "…"
  }
]
GET/api/v1/harvest/trace-anchors

The workspace's anchoring runs with batches + sealed batches awaiting the next run

Scope: harvest.trace.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
takeintqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/trace-anchors" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "anchor_schedule_local": "…",
  "anchors": [
    {
      "anchor_date": "2026-10-28",
      "attempts": 1,
      "bitcoin_block_height": 1,
      "bitcoin_confirmed_at": "2026-10-28T07:30:00Z",
      "bundles": [
        {
          "bundle_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
          "content_hash": "…",
          "harvest_date": "2026-10-28",
          "harvest_record_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
          "parcel_code": "…",
          "product": "…",
          "version": 1
        }
      ],
      "confirmed_at": "2026-10-28T07:30:00Z",
      "created_at": "2026-10-28T07:30:00Z",
      "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "is_backfill": true,
      "leaf_count": 1,
      "merkle_root": "…",
      "polygon_chain_id": 1,
      "polygon_confirmed_at": "2026-10-28T07:30:00Z",
      "polygon_tx_hash": "…",
      "status": "…",
      "submitted_at": "2026-10-28T07:30:00Z"
    }
  ],
  "pending": [
    {
      "bundle_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
      "parcel_code": "…",
      "product": "…",
      "sealed_at": "2026-10-28T07:30:00Z",
      "version": 1
    }
  ]
}
GET/api/v1/harvest/trace-certificate/{id}

Blockchain verification certificate (PDF)

Scope: harvest.trace.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/trace-certificate/<id>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

This endpoint does not declare a response schema yet — call it in the API Explorer to see the shape.

GET/api/v1/harvest/trace-incidents

The workspace's data drift incidents

Scope: harvest.trace.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
statusstringqueryno—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/trace-incidents" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
[
  {
    "anchored_hash": "…",
    "bundle_version": 1,
    "current_hash": "…",
    "detected_at": "2026-10-28T07:30:00Z",
    "diff_json": "…",
    "has_newer_version": true,
    "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "kind": "…",
    "parcel_code": "…",
    "product": "…",
    "resolution": "…",
    "resolution_note": "…",
    "resolved_at": "2026-10-28T07:30:00Z",
    "restore_requested_at": "2026-10-28T07:30:00Z",
    "restore_requested_by": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "status": "…",
    "trace_bundle_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001",
    "workspace_id": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
  }
]
GET/api/v1/harvest/trace-pdf/{code}

Download the traceability PDF by QR code (SIGN-IN REQUIRED)

Returns the batch's VietGAP PDF. The file contains the household's full name + phone number so it is NOT served on a public route. 404 when: the code does not exist · the code has expired · the batch has not rendered a PDF · the file is no longer in storage.

Scope: harvest.trace.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
codestringpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/trace-pdf/<code>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

This endpoint does not declare a response schema yet — call it in the API Explorer to see the shape.

GET/api/v1/harvest/trace-seal-document/{id}

Download the sealed document (full hashed version) — internal users only

Scope: harvest.trace.viewTry in API Explorer ▶

Parameter

ParameterTypeInRequiredDescription
idGUIDpathyes—

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/trace-seal-document/<id>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

This endpoint does not declare a response schema yet — call it in the API Explorer to see the shape.

GET/api/v1/harvest/trace-settings

GET /api/v1/harvest/trace-settings

Scope: harvest.trace.viewTry in API Explorer ▶

Parameter

No parameters.

Example

curl -X GET "https://api-prod.nextfarm.vn/api/v1/harvest/trace-settings" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

Sample response

200 OK
{
  "scan_warn_threshold": 1
}