When to use
- A brand owner needs to know “are we FSMA 204-compliant for batch X?” before the Jan 20, 2026 enforcement date — and afterward, every day.
- Before issuing a recall, audit which lots have enough KDE coverage to construct the FDA Sortable Spreadsheet export.
- A 3PL onboarding a new shipper needs to gap-analyze their KDE posture before contracting.
- Continuous-readiness dashboards.
GET /epcis/api/2.0/traceability/lots/{lot_id}/fda-export. This skill
is the gap-analysis step that runs before the export to flag missing
KDEs.
For a historical snapshot — “what KDEs did we have on file as of
a past date”, the question an FDA investigator or auditor actually
asks during a § 1.1455(c) request, not “what do our records show
right now” — use
GET /epcis/api/2.0/traceability/lots/{lot_id}/as-of?as_of={timestamp}
(C-5400). It replays the same immutable CriticalTrackingEvent ledger
filtered to rows captured at or before as_of, never by the
underlying event’s own event_date — a CTE recorded (entered into
the system) after the audit date is correctly excluded from the
snapshot even if the event itself occurred earlier.
Auth
OAuth token (orX-API-Key) with OWNER or MANAGER membership on
the organization that owns the GTINs being audited.
Flow
Note (C-5399): for a single lot, prefer the dedicated readiness endpoint over composing the steps below by hand:TradingPartner counts that CTE incomplete, not
satisfied. See Output below for its response shape.
It does not do Step 2’s food-category-aware CTE-presence checklist or
Step 4’s two-dimensional (cte_coverage_pct + kde_coverage_pct) / 2 score —
those still require composing Steps 1-2 by hand (see Known gaps). Steps
1-4 below describe the full manual audit, and remain the only path for
resolving GTINs to lots (Step 1) and for bulk/multi-lot audits (no bulk
endpoint exists yet).
Step 1 — Resolve GTINs to lots
For each GTIN you want to audit, list the lots that have any EPCIS activity:/10/{lot}) — the server matches
EPC URIs by exact string, so a prefix-trimmed URI captures every lot
under the GTIN. Collect distinct epcList values from the response,
parse the AI(10) lot segment off each one.
Alternatively, pull lots directly from the products API:
GET /products/api/v1/products/{gtin}/lots (if exposed for the org).
Step 2 — Audit CTE coverage per lot
For each lot, ask the EPCIS ledger which bizSteps were observed:bizStep values from the response. Compare against
the FSMA 204 CTE set expected for the product’s food category. The
generic checklist:
A lot missing a required bizStep has a KDE gap.
Step 3 — Audit KDE completeness per CTE
For each captured EPCIS event in the lot’s chain, verify that the KDEs FSMA 204 expects for that CTE type are present. Required KDEs by CTE type (per FDA Sortable Spreadsheet template):
Closient extracts these KDEs from the EPCIS
ilmd block (Step 7 of
capture-epcis-event) and the resolved trading-partner / location
records. An event with bizStep=harvesting but no cbvmda:harvest_start_date
in ilmd is a KDE gap.
Step 4 — Compose a readiness score
Thefsma-204-readiness endpoint (see the Note above) computes Step 3’s
KDE-completeness rubric for you, per lot. What follows is the fuller
two-dimensional rubric an agent doing a manual, food-category-aware audit
(Step 2 + Step 3 together) would compose — the endpoint does not (yet)
implement the CTE-presence half of it:
cte_coverage_pct= (CTEs observed for the lot ∩ CTEs required for the food category) / required.kde_coverage_pct= (KDE fields populated across captured CTEs) / expected KDE fields across those CTE types.
Required inputs
gtin— GTIN-8 / 12 / 13 / 14 (server zero-pads shorter forms).lot(when scoping to a specific batch).
Optional inputs
food_category— to pick the correct CTE checklist. Closient infers this fromProduct.product_categorywhen it’s set.date_range— bound the audit to a recent window (e.g. last 365 days of shipments).
Output
fsma-204-readiness endpoint (per lot, C-5399)
score is complete_count / cte_count — the fraction of CTEs currently on
file for the lot that pass the corrected KDE-completeness rubric. A lot
with zero CTEs scores 0.0, not null (see Guidance for agents below).
issues values are one or more of missing_immediate_subsequent_recipient
(SHIP), missing_immediate_previous_source (RECEIVE), and
missing_reference_document (any CTE type).
This is KDE completeness only — it does not include cte_coverage_pct
(whether the lot has every CTE type its food category requires) or a
missing_ctes list of entirely-absent CTE types. That half of the
two-dimensional rubric (Step 4 above) is still a manual composition of
Steps 1-2 until the food-category checklist moves server-side (Known
gaps).
Manual composition (Steps 1-4, multi-GTIN or CTE-presence audits)
A list of structured rows, one per (GTIN, lot):Guidance for agents
- Run the audit on the materialized CTE table, not raw events,
where you can. The
CriticalTrackingEventmodel (seeapps.epcis.models) is the authoritative source of CTE rows — EPCIS events that didn’t produce a CTE (because the bizStep isn’t FSMA-relevant) are noise for this audit. The/traceability/lots/{lot_id}/fda-exportendpoint already does this filtering; reading its 202-pending response tells you which CTEs exist for the lot. - Don’t conflate “lot exists” with “lot is ready”. A lot with
zero EPCIS events is
0.0readiness, not “no data”. The product exists in the catalog; FSMA 204 requires CTEs. - Lock-state matters. Once a
ProductLothas been used in a CTE, itsLOCKED_FIELDS(lot code, harvest dates, expiration) are immutable. Don’t propose a fix that requires editing those fields — instead, the agent should surface a “capture a corrective event with the missing KDE in ILMD” workflow (callscapture-epcis-eventwith the right bizStep + ilmd block). - Audit BY ORGANIZATION’s role in the chain. A brand owner who
only packs (not harvests) is not on the hook for HARVEST KDEs —
those belong to the grower upstream. The CTE checklist in Step 2
is conditional on the org’s role; for a packer-only, only
INITIAL_PACK+SHIPare owed. - Surface the fix path, not just the gap. A missing
growing_areaKDE on a HARVEST event is fixable by capturing a correctivebizStep=harvestingevent with the rightcbvmda:growing_area— hand the agent the exact endpoint and JSON shape it needs. - Don’t recompute on every page render for a manual (Step 1-4)
multi-GTIN audit. The
fsma-204-readinessendpoint (per lot) is cheap enough to call directly — it runs one query pass over the lot’s own CTEs, no caching layer. A bulk, multi-GTIN audit still costs ≥ 2 EPCIS queries per lot until the bulk endpoint below ships; batch those.
Known gaps (planned)
- No food-category-aware CTE checklist on the server. The
expected-CTE-by-FTL-category table (Step 2) lives in this skill doc
rather than as a server-side rule, so
fsma-204-readinesscannot tell you a lot is missing an entire CTE type (e.g. no COOLING event at all) — only that the CTEs actually on file have incomplete KDEs. When the checklist moves server-side,fsma-204-readinesswill gain amissing_ctesfield and the skill will reference the checklist by URL instead of restating the table. - No bulk-GTIN readiness scan. Agents auditing dozens of GTINs
have to fan out queries, one
fsma-204-readinesscall per lot. A bulk endpoint (POST /compliance/api/v1/fsma204-readiness/scantaking a GTIN list) is planned for the FSMA dashboard refactor.
Related skills
capture-epcis-event— the corrective-action surface; agents capture missing-KDE events to close gaps surfaced by this audit.query-epcis-events— the underlying read behind the manual Step 1-4 audit and behindfsma-204-readinessitself.manage-recall— pre-recall sanity check; only issue recalls on lots whose readiness score is high enough to compose a defensible FDA Sortable Spreadsheet.check-recalls— consumer side of recalls; orthogonal to readiness but reads the same CTE ledger.