A retention policy that says "keep customs records for five years" is wrong in four places at once, and 19 CFR part 163 is unusually explicit about where. The rule does not attach one duration to a folder. It attaches durations to categories of record, each with its own anchor event, and then adds a production window that starts on a day you do not choose.
Modeled as data, it looks like a small state machine with a calendar. Modeled as a cron job deleting anything older than 1,825 days, it deletes packing lists too late, deletes drawback records at the wrong moment, and leaves you unable to answer a demand that arrived on a Friday.
Durations are per category, with different anchors
create table import_record (
record_id text primary key,
entry_id text, -- null when the record is not entry-related
category text not null check (category in
('entry','drawback','packing_list','informal_consignee','de_minimis')),
anchor_event text not null check (anchor_event in
('entry_date','activity_date','claim_paid_date','release_period_end',
'redelivery_date','informal_entry_date')),
anchored_on date not null,
created_at timestamptz not null default now()
);
Section 163.4(a) sets one general period: five years running from the entry date on any record tied to an entry, and five years from the activity that made the record necessary where it is not tied to one. Section 163.4(b) then replaces that with several other measures. Drawback files are held to the third anniversary of the payment date on the claim. Packing lists get 60 calendar days counted from whichever of the release period and the conditional release period ends later, or 60 days from redelivery once a demand for return to custody has issued. If the consignee is neither owner nor purchaser and a broker is appointed, informal-entry records stay two years from the informal entry date. Low-value articles that came in duty and tax free under 19 U.S.C. 1321(a)(2), with sections 10.151 to 10.153, keep two years, and so do a carrier's paperwork on manifested cargo exempt from entry. Paragraph (b)(5) adds that a specific period set elsewhere in the chapter controls over the general one.
create function retention_until(r import_record) returns date as $$
select case r.category
when 'entry' then r.anchored_on + interval '5 years'
when 'drawback' then date_trunc('day', r.anchored_on + interval '3 years')
when 'packing_list' then r.anchored_on + interval '60 days'
when 'informal_consignee' then r.anchored_on + interval '2 years'
when 'de_minimis' then r.anchored_on + interval '2 years'
end::date;
$$ language sql immutable;
Five branches, five anchors, and only two of them share a duration. A purge job that reads one column will get three of these wrong while reporting success.
The demand window is the part with a human in it
create table record_demand (
demand_id text primary key,
received_on date not null,
demand_form text not null check (demand_form in ('written','electronic','oral')),
admissibility boolean not null default false, -- shorter period may be prescribed
due_on date not null,
extension_requested_on date,
extension_decided_on date,
produced_on date
);
Section 163.6(a) sets the terms. CBP can require production by written, oral or electronic notice, and an oral demand has to be followed up in writing or electronically. Records are produced within 30 calendar days of receipt of the demand, or within a shorter period where they are needed in connection with a decision on admissibility or release. A party that cannot comply in time may put in a written or electronic request for a stated longer period, and it has to land before the due date with an explanation of the circumstances. CBP then advises whether the request is denied, granted, or granted for a shorter period.
select demand_id,
case
when extension_requested_on is not null
and extension_requested_on >= due_on then 'extension_asked_too_late'
when produced_on is not null
and produced_on > due_on then 'produced_late'
when produced_on is null and current_date >= due_on
then 'overdue'
when admissibility and due_on - received_on < 30
then 'shortened_window'
else 'on_track'
end as state
from record_demand;
The first branch is the expensive one, and it is invisible in most systems because there is nowhere to record it. The request has to arrive before the due date, so a team that discovers on day 31 that a supplier's invoice is missing has moved from an administrative problem to a documented failure. overdue and extension_asked_too_late look identical in a folder. They are not identical in a file that someone will read later.
Two more columns people forget
Section 163.3 makes readiness the standard, and it says a record surrendered at entry and given back, or excused from production then, stays on the retention list. A schema that treats a submitted document as consumed will drop exactly the records that stay live. Add a returned_or_waived flag and keep the row.
Section 163.11(e) is worth a column too. Being inside the period and scope of an earlier audit that used sampling is not evidence of reasonable care in a later action on those entries. If your system stores an audited_ok boolean next to entries, it is recording something the rule explicitly declines to credit, and someone will read it as a clean bill of health.
This is a shape, not an opinion. Whether a given document is an entry record, when its anchor event falls, and what a demand covers are questions for the party that owes the duty and the officers who read the file. FulfillNexa by SBT (fulfillnexa.com) consolidates supplier shipments and holds seller stock at three sites in China, 13,000 square meters at the Suzhou end, 8,000 at Dongguan and 3,000 at Shenzhen, and the retention clock on an entry is not ours to hold. What we do hold is the date the count was taken, which is the row most likely to be missing when a demand asks what arrived on a particular day two years ago.
Top comments (0)