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
{id} isA 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_idis not the resourceid. A row'sidis itsasset_entityid, 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 sameidtwice. Onlyrow_idis 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
| Field | Meaning |
|---|---|
id | The record's row_id. Pass it back here, or match it against a row's row_id. |
asset_task_id | The upload this record came from. links.asset_task opens it. |
source_file | That upload's filename; null for non-file uploads. |
status | The record's processing status. |
created_at | When that upload linked this location. |
monitoring_end | The EUDR monitoring window this record resolved to — the key currency is decided on. null when the record has no metric yet. |
record_superseded_at | When a later upload replaced this record. null on the live one. |
superseded_by_row_id | The record that replaced this one. A flat pointer to the live record, so it is one hop from any dead record. |
is_live | Whether 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.
▶Related
- List Latest Ingestion Assets — the deduped read this endpoint reveals the history behind.
- List All Ingestion Assets — every record for
every location, filterable.
links.supersededon a row points there.
Required scope:
ingestions:read