Get Record History

Every uploaded record for one location, newest first, with the current record leading.

Upload the same plot three times and the location has three records. The deduped read (GET /ingestions/assets/latest) returns one of them and hides the other two. This endpoint returns all three, in supersession order, and says which one is live.

What {id} is

A row_id — the row_id attribute on any asset row, and the id in that row's links.history. Follow the link and you never have to build the URL:

GET /ingestions/assets/latest        →  data[].links.history
GET /ingestions/assets               →  data[].links.history
GET /ingestions/assets/{task_id}     →  data[].links.history

A row_id identifies one upload's view of one location, which is the grain supersession works at.

row_id is not the resource id. A row's id is its asset_entity id, which is shared wherever the uploaded attributes are identical — including across organizations. A parent organization reading two children's rows for one location sees the same id twice. Only row_id is unique per record.

A superseded row's row_id is accepted and returns the same history. A client holding a stale id — from an export, or a saved report — gets a useful answer instead of a 404.

Plot locations come from the unfolded list

GET /ingestions/assets/latest folds a plot task to one row, and a folded row is not one record, so it carries no row_id and no links.history. To reach a plot location's history, take the row from GET /ingestions/assets or from the per-task results, which are per-record. Facility and shed rows carry the handle on every endpoint.

The order, and why it cannot lie

record_superseded_at DESC NULLS FIRST, created_at DESC, id ASC

The live record has no supersession stamp, so it comes first by construction — its position and its is_live flag can never disagree. The rest follow most-recently-replaced first.

The live record is often not the newest upload. Currency is decided by the EUDR monitoring window, not by arrival time (EPO-1089): an upload that landed later with no metric yet loses to an earlier one that has one. So expect created_at to be out of order down the list, and read is_live rather than position.

What each record reports

FieldMeaning
idThe record's row_id. Pass it back here, or match it against a row's row_id.
asset_task_idThe upload this record came from. links.asset_task opens it.
source_fileThat upload's filename; null for non-file uploads.
statusThe record's processing status.
created_atWhen that upload linked this location.
monitoring_endThe EUDR monitoring window this record resolved to — the key currency is decided on. null when the record has no metric yet.
record_superseded_atWhen a later upload replaced this record. null on the live one.
superseded_by_row_idThe record that replaced this one. A flat pointer to the live record, so it is one hop from any dead record.
is_liveWhether this is the record GET /ingestions/assets/latest returns.

Exactly one record per history carries is_live: true. A location left inconsistent by a deletion can report two, and this endpoint reports what it finds rather than hiding it.

One history per organization

meta.organization_id is the row's own organization, not the caller's whole visible set. Two organizations that upload the same location each hold a separate history, and each is deduped separately — so a parent organization reading a child's row gets that child's history, not the union.

Pagination

meta.total is always exact, on every page. A history is small (26 records at p95 for a plot location, 52 at most), so the default page_size of 100 returns all of it in one page and the exact count is cheap.

Page-number pagination only: page[number] and page[size]. There is no cursor mode — cursor traversal carries no filtered-set count, and an exact total is the point here. page[cursor] is ignored rather than rejected.

Response formats

All four Accept formats: application/json, application/x-ndjson, application/geo+json, application/x-ndgeo+json.

The geo formats carry geometry: null on every Feature. A history entry is a record event, not a place, and all the entries describe the one location already named in meta.location_id — repeating its geometry per row would be a duplicate rather than information. Read the geometry from /locations/{type}/{location_id}.

404

Returned when the row_id is not visible to the caller, and when the record resolved no location — an unlocated record has no dedupe key, so it belongs to no history. The two are not distinguished, so the endpoint never confirms that an id exists in another organization.

Required scope: ingestions:read