Skip to main content
FSMA 204 (the FDA Food Traceability Rule, 21 CFR § 1.1320) requires that any entity handling a food on the Food Traceability List (FTL) maintain Key Data Elements (KDEs) for each Critical Tracking Event (CTE) — harvest, cooling, initial pack, first land-receive, shipping, receiving, transformation. § 1.1455(c) further requires those records be furnished to FDA within 24 hours of request. This skill walks an agent through auditing one or more GTINs for KDE coverage by reading the EPCIS event ledger and the materialized CTE rows that Closient produces automatically when FSMA-relevant events are captured.

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.
For the FDA Sortable Spreadsheet export (the artifact you furnish under § 1.1455(c)), use the EPCIS endpoint 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 (or X-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:
It runs Step 3’s KDE-completeness rubric server-side, in one call, using the corrected logic (C-5398): a trading-partner GLN captured but never resolved to a registered 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:
Use the prefix match (no trailing /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:
Pull the distinct 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

The fsma-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:
Where:
  • 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.
A lot at < 80% is unlikely to satisfy a § 1.1455(c) request.

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 from Product.product_category when 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 CriticalTrackingEvent model (see apps.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-export endpoint 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.0 readiness, not “no data”. The product exists in the catalog; FSMA 204 requires CTEs.
  • Lock-state matters. Once a ProductLot has been used in a CTE, its LOCKED_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 (calls capture-epcis-event with 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 + SHIP are owed.
  • Surface the fix path, not just the gap. A missing growing_area KDE on a HARVEST event is fixable by capturing a corrective bizStep=harvesting event with the right cbvmda: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-readiness endpoint (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-readiness cannot 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-readiness will gain a missing_ctes field 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-readiness call per lot. A bulk endpoint (POST /compliance/api/v1/fsma204-readiness/scan taking a GTIN list) is planned for the FSMA dashboard refactor.
  • 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 behind fsma-204-readiness itself.
  • 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.