EUDR Audit Trail From Tagged Facilities
End-to-end recipe that goes from a facility upload to an exported EUDR DDS report — where a tag supplied on the upload is the key that binds the upload to the audit record.
Facility upload, tag-driven selection. This workflow uploads
location_type: facilityassets, and every upload must carry a tag. That same tag — not a task id — is what the audit-record create filters on (filter.tag). The tag is the through-line: apply it at upload, select by it at create.
▶Why a tag (not a task id)?
The sibling
Plots-Only workflow
binds the record to a single upload via filter[assets.task_id]. That
is fine when one upload == one record. A tag is the better key when:
- the batch spans multiple uploads (tag them all the same, select once);
- you want a stable, human-meaningful selector (
q2-2026-cocoa) rather than an opaque task UUID; - you re-upload / append over time and want the record's scope to follow the tag.
Tags applied to the asset_task at upload propagate to the resolved
plots, so filter: { "tag": { "eq": "…" } } selects exactly the plots
under every upload that carried that tag.
▶How a facility resolves to plots
The DDS audit trail is built from plots. A facility upload resolves to its underlying plots via its supply shed, and the upload's tag rides through to those plots. So a tagged facility upload feeds the audit record exactly the plots beneath it.
▶Endpoint map
| Step | Method | Path | Threads to next |
|---|---|---|---|
| 01 | POST | /ingestions/assets (location_type: facility, with a tags array) | fac_task_id, fac_tag |
| 02 | GET | /ingestions/{task_id} (poll until staged) | — |
| 03 | PUT | /ingestions/assets?filter[assets.task_id]=eq:{task_id} (metrics:["deforestation"]) | fac_metrics_task_id |
| 04 | GET | /ingestions/{metrics_task_id} (poll until terminal) | — |
| 05 | POST | /regulations/eudr/audit-trail (select by tag: filter: { "tag": { "eq": "{{fac_tag}}" } }) | fac_create_task_id |
| 06 | GET | /regulations/eudr/audit-trail/tasks/{create_task_id} (poll until complete) | fac_record_id |
| 07 | GET | /regulations/eudr/audit-trail/{record_id}/report | (built DDS report) |
| 08 | — | Render a standalone HTML report (Bruno-side preview) | — |
| 09 | GET | /regulations/eudr/audit-trail/{record_id}/audit-trail/html | signed download URL |
| 10 | POST | /regulations/eudr/audit-trail/{record_id}/authorisations | clears authorization_missing |
| 11 | POST | /regulations/eudr/dds/{record_id}/submit | fac_submit_task_id |
| 12 | GET | /regulations/eudr/audit-trail/tasks/{submit_task} (poll until complete) | TRACES identifiers |
Omitting the tag breaks the workflow — step 05 selects by it. Steps 10–12 file the record with EU TRACES — the end of the customer's flow. Submit files only the compliant supply base and requires a live authorisation for the current version (step 10).
▶Variables exchanged
fac_task_id— set by step 01 (the upload); read by steps 02, 03.fac_tag— set by step 01 (the tag applied to the upload); read by step 05 as the selection filter. This is the binding key.fac_metrics_task_id— set by step 03; read by step 04.fac_create_task_id— set by step 05; polled in step 06.fac_record_id— set by step 06 fromresult.records[0].record_id; read by steps 07–08.fac_report_html— set by step 08 (the rendered HTML string).fac_*_poll_retries— used by the polling helper to bound retries.
▶Why this is a workflow, not a per-endpoint test
It exercises the composition: a tagged facility upload flows (facility → shed → plot) into an audit record selected purely by its tag, and the resulting DDS report is rendered to a shareable HTML page. Treat it as runnable documentation.