This is the English translation. The Spanish version (SPEC.md) is the reference version until decided otherwise.
PARCID is an open identity registry for units in transit: the identity of what travels. It is the open SSCC: one number for every unit, like the GS1 SSCC, but free, opaque, perpetual and bound to the object; and if the unit already has an SSCC, the registry accepts it as an entry key and adds a body and a history to it (§1, §3.3). It gives every physical unit moving through a supply chain (a parcel, a loaded pallet, a bag, a tote, a crate) a unique, opaque, free worldwide identifier, binds it to the object through a physical signature (its “biometrics”), and keeps a sealed history of what happens to it. The parcel is the first unit profile (§1.1) and the only one with station capture in this version. Registry name: PARCID, domain parcid.com (DECISION 10, decided 23/10/2026); the identifier keeps the PID prefix (read Physical unit ID). Anyone can enrol a unit and resolve an ID without asking permission. Claims about identity (sightings, proof of liveness, comparison, custody storage) are paid services provided by operators such as Know Your Parcel.
This specification is published under the CC BY 4.0 licence. The reference code (ref/) is under CC0 1.0. Public resolution data is offered under CC0 1.0. The resolver, the API and the verification tool are published under Apache-2.0 in a public repository, so that anyone can run a mirror (DECISION 6, decided); the operator’s comparison models stay outside the open-source code: the signature format is public, the engine belongs to the operator. Status: draft v0.2. The registry’s reference implementation (registry/) implements this version and is tested end to end (registry/tests/run-all.sh). Pending DECISION points are listed in §15.
0. Principles
- Identity is free; claims are paid. Enrolment and resolution cost nobody anything. “This is the same parcel”, “this capture is real and current”, “this is how it was at that time” are products.
- Zero personal data in the global registry. The registry is about objects, not people. The content of the label (names, addresses, phone numbers) never enters the database; raw evidence that might contain it is stored encrypted and is read only by whoever holds the owner key.
- Open and verifiable without the registry. Public format, public resolution, full export, records verifiable with standard tools (SHA-256, Ed25519, RFC 3161). If the operator disappeared, every record would remain verifiable.
- Calibrated confidence, not absolute uniqueness. No physical feature is unique the way a fingerprint is. What is promised is a measured, explained confidence, with a level that depends on how the capture was made.
- The operator behaves as if the registry already belonged to a neutral entity: brand without “KYP”, open specification, commitment to hand over the namespace (§13), separate accounting.
- A unit is a state, not an object. A parcel is born when someone closes a box, changes when it is opened or consolidated, and dies at delivery; nobody owns it permanently and nobody issues it an identity. A thing enters the registry when it meets all four conditions: (a) it has no permanent issuer and no serial number of its own; (b) it changes state during the journey; (c) it changes custody between different parties; (d) it lives briefly, from hours to months. Whatever fails condition (a) already has a registry and gets no ID: the shipping container (BIC code, ISO 6346) and the vehicle (VIN, number plate) are context for units, as a link or as a custodian (§1.1, §5.2). This is not a registry of objects or assets: GS1 says what a thing is and which shipment it travels in; this registry says which physical one it is and whether it is still the same.
1. How a unit is made unique (the three routes)
1.1 What a unit is (profiles)
A unit is a physical thing that travels as a single piece under one custody (a handling unit, a piece). Every unit is enrolled with a profile (unit_profile) that fixes which physical-signature features are expected and where they are captured. Profiles in this version:
| Profile | What it is | Scope in v0.1 |
|---|---|---|
parcel |
box, envelope, drum or any closed piece that travels as one | core: full profile, levels 0–3, station capture |
pallet_load |
a loaded pallet: the stacked, wrapped cargo, not the wooden pallet. The SSCC labels the shipment, but nothing binds that label to that physical load; the N→1 consolidation (§5.3) models it exactly | core: levels 0–2; own features in v0.2 |
container_load |
the cargo stowed inside a container. The container (BIC code) and the seal (ISO 17712) are links (§5.2), not the unit | levels 0–2; own features in v0.2 |
tote |
tote, roll cage, keg, cylinder: returnable transport items, with or without a GRAI | levels 0–2; own features in v0.2 |
bag |
mail bag, courier pouch, luggage (the IATA bag_tag is per journey, not per bag) |
levels 0–2; own features in v0.2 |
crate |
transport case for art, instruments or machinery | levels 0–2; own features in v0.2 |
What is not a unit: the shipping container and the vehicle. They have a permanent issuer and an engraved serial (BIC with check digit; VIN and number plate with state registries), and a number plate identifies a person. They are the next level of the same hierarchy: the container is to the load what the pallet is to the parcel, and the registry identifies the load at each level, not the permanent receptacle. A vehicle enters only as a custodian (holder_class: vehicle, §5.2) with an opaque reference, never the plate in clear.
1.2 The three routes
A person has a document issued by a third party and a biometric. A unit carries no document: the registry gives it one at enrolment, and it is bound to the object by three routes at once. (The table describes the parcel profile; in the other profiles the signature features change, the routes do not.) None is sufficient alone; the three together are more than person-based KYC has, because the sealed history does not exist there.
| Route | What it is | Who guarantees it | What happens if it fails |
|---|---|---|---|
| Document | the PARCID printed on or stuck to the parcel (QR, text on the label) | the registry: random, with check symbols, collision-free | it is lost or copied → the other two come into play |
| Biometrics | the physical signature (§6): geometry, weight, 3D shape, cardboard texture in fixed patches, tape, label layout, appearance, damage | the sealed enrolment record, with device signature and timestamp (“birth certificate”) | label copied onto another box → the signature does not match |
| History | the sealed chain of sightings and the lineage (open, consolidate, repack = new linked ID) | each sighting record, chained | two identical boxes cannot have the same history |
1.3 What must be uploaded to create an ID (parcel profile)
The registry accepts anything from almost nothing up to a station capture. The more is uploaded, the higher the assurance level (§7) and the more capable the later comparison.
| Level | What is uploaded | What it distinguishes |
|---|---|---|
| Minimum (L0) | nothing mandatory except the capture class. Optional: dimensions, weight | only the document: the ID. Useful for linking references, not for recognising the parcel |
| Basic (L1) | dimensions (mm) and weight (g) with tolerances, 2 photos (top-down and a perspective one with the 6 faces implicit) or their hashes, Ed25519 client signature | separates the parcel from most of those travelling the same day on the same route (geometry + weight + appearance) |
| Recommended (L2) | the above + cardboard texture patches at 4 fixed positions relative to the origin corner (§6.4), tape path, label layout (without its content), device attestation, freshness nonce | separates two factory-identical, freshly closed boxes: the texture of fibres and stains and the tape path are different in every box |
| Station (L3) | the above captured in normalised geometry (origin 0·0·0, rulers, fixed cameras, own lighting) + point cloud + calibrated scale + multisensor coherence | comparable across machines and over time; it is the parcel’s “passport photo booth” |
What does not make a parcel unique and must not be used as identity: the tracking number (set by the carrier, reused and copied), the SSCC (identifies the logistic unit of a shipment, not the physical object or its state; GS1 allows it to be reused after a period, it carries the issuer’s company prefix and it is enumerable), the label content (personal data; also reprinted). These three are linked to the PARCID (§5.2), they do not replace it.
The registry does not compete with the SSCC: it is a layer on top of it. If the unit carries an SSCC, the registry accepts it as a first-class entry key: the unit is enrolled with links[kind=sscc] and resolved through /00/{SSCC} (§3.3), and the registry adds what the SSCC lacks, the physical signature and the sealed history. The PID stays underneath as the perpetual key, because the SSCC is reused, identifies the issuer and can be enumerated. If the unit carries nothing, the registry gives it a PID for free.
2. The identifier
2.1 Canonical form
PID-1-7QC3-Z79D-G6RZ-8E
│ │ └──────┬──────┘ └┬┘
│ │ │ └ 2 check symbols (10 bits)
│ │ └ 12 random payload symbols (60 bits) in 3 groups of 4
│ └ scheme version (1 symbol)
└ fixed prefix
- Alphabet: Base32 Crockford,
0123456789ABCDEFGHJKMNPQRSTVWXYZ(no I, L, O, U). On reading, lowercase letters are accepted,I/L→1,O→0, and hyphens and spaces are ignored. The canonical form is uppercase with hyphens. - Length: 23 characters with hyphens; 18 without them (
PID+ 15 symbols). It fits on one label line, can be dictated over the phone and typed without ambiguity. - Payload: 60 random bits from the registry’s cryptographic generator (or from the reserved block, §2.4). No information inside: no date, no issuer, no sequence. Space: 2^60 ≈ 1.15 × 10^18.
- Version: one symbol.
1is this specification. It allows lengthening the payload or changing the check without breaking what has been issued.
2.2 Why 60 bits and not more
- Uniqueness is not provided by randomness, it is provided by the registry: the ID is issued centrally (or from a reserved block) and the database rejects duplicates. The “collision-free by birthday bound” property is not needed; what is needed is for the space to be sparse so that nobody can enumerate the database or guess IDs.
- Sparsity: with 10^11 registered IDs (one year of worldwide parcel trade), a random ID hits an existing one with probability 10^11 / 1.15 × 10^18 ≈ 9 × 10^-8. With query limits (§10), enumeration is impracticable. With 10^14 IDs (centuries of use) the density rises to 10^-4; before reaching that, version
2is issued with an 80-bit payload. - 60 bits are 12 symbols: three groups of four, legible and dictatable. The draft in document 04 proposed 70 bits (
KYP-1-7XBD-04QM-3F7K-9H, 14 symbols): at the same length, this specification devotes 12 symbols to the payload and the last 2 to the check. Keeping 70 bits of payload would force a 16-symbol ID to preserve the check. DECISION 1 (decided): 60 bits + 2 check symbols in 23 characters.
2.3 Check (pure system ISO 7064 “MOD 1021-32”)
- Input: the 13 version + payload symbols, as values 0–31.
P = Σ v_i · 32^(12−i) mod 1021. - Check:
C = (1 − 1024 · P) mod 1021(and since 1024 ≡ 3,C = (1 − 3P) mod 1021), encoded in two symbols:C div 32,C mod 32. AlwaysC ≤ 1020 < 1024, so it fits. - Verification: the same sum over the 15 symbols (version + payload + check) must be ≡ 1 (mod 1021).
- Properties (1021 is prime, 32 is invertible modulo 1021): it detects all single-symbol substitutions, all transpositions of adjacent symbols, and 99.9 % of random double errors (1 in 1021 passes). Checked with
ref/parcid.py: 0 of 139,500 substitutions and 0 of 4,068 transpositions undetected; 30 of 20,000 random double errors undetected (0.15 %). - Reference implementation:
ref/parcid.py(generate, normalise, validate; no dependencies). Valid examples:PID-1-B92B-YPQ0-8303-JW,PID-1-91QW-5PA4-R8CT-KZ,PID-1-5GP2-J3D9-G4WF-RE,PID-1-Y51Z-HM66-Q1YQ-FE,PID-1-7QC3-Z79D-G6RZ-8E,PID-1-7G61-S4XF-X5P2-HA.
2.4 Issuance
- Online: the registry generates the payload, checks that it does not exist and inserts it in a transaction; if it collides (probability ≈ n/2^60), it retries.
- Offline (stations and SDKs without network): the device requests in advance a reserved block of up to 1,000 IDs with
POST /reservations, signing with its Ed25519 key the request{ schema:"parcid.reservation-request/1", public_key, count, requested_at, nonce }(within 5 minutes of the registry’s clock). Only for approved devices or devices with a developer key, with a daily limit per device. Enrolling with a reserved ID ("pid"inPOST /parcels) requires the signature of that same device. IDs unused after 90 days are burned: they are never issued to anyone else (DECISION 8, decided). The reservation is a record (§7.5). - An ID is never reused, not even when revoked.
3. Public resolution
3.1 URL
- Canonical form:
https://{host}/{PID}, e.g.https://parcid.com/PID-1-7QC3-Z79D-G6RZ-8E. The registry host isparcid.com(DECISION 10, decided 23/10/2026).org` are registered by third parties). Should the host ever change, the old one would redirect with 301 forever. - Accepted variants (redirected 301 to the canonical one): lowercase, without hyphens, with
I/L/O. - HTML for browsers; JSON if
Accept: application/jsonor with the.jsonsuffix. Same content. - Registry metadata:
https://{host}/.well-known/parcid(specification version, registry public keys withkid, export URL, rate-limit policy).
3.2 QR
- QR content: the full canonical URL (not only the ID), so that any reader can open it. Error correction M. Next to the QR, the ID as text on one line.
- If the QR is printed at the station, it goes on a separate label or inside the existing shipping label; it never covers the carrier’s codes.
3.3 GS1 Digital Link
- The PARCID is not a GS1 key and is not intended to be one. The GS1 Digital Link standard admits non-GS1 key-value pairs in the query string, so a link for an SSCC can carry the ID:
https://{host}/00/{SSCC18}?pid=PID-1-.... - The SSCC is a first-class entry key.
POST /parcelswithlinks[kind=sscc]enrols the unit under its SSCC from the start (the registry verifies the GS1 check digit), and the resolver acceptsGET /00/{SSCC18}and returns the PIDs linked to that SSCC by its holder (§5.2), if they exist and if the holder made them public. Since GS1 allows an SSCC to be reused after a period, the response lists every linked PID with its link date, the active one first; the PID is the perpetual key, the SSCC the entry door. - Who backs the link. Any holder can publicly link an SSCC to its unit, so
GET /00/{SSCC}returns at most 20 PIDs, each withclaim:operator(unit enrolled by an identified operator with a developer key) orself_declared(unverified); operator ones first. - Conversely, resolving an ID lists the linked SSCCs and tracking numbers only if the holder published them; by default they are private.
3.4 Resolution response (the public part)
What anyone sees: it exists, when it was registered, with what unit profile, capture class and assurance level, what state it is in, whether it has lineage, the last verified sighting (date and class, not exact place), and the hashes that allow the enrolment record to be verified. Never: images, dimensions, weight, private references, who registered it, addresses.
{
"pid": "PID-1-7QC3-Z79D-G6RZ-8E",
"spec": "parcid/1",
"status": "active",
"unit_profile": "parcel",
"registered_at": "2026-11-18T09:41:07Z",
"capture_class": "station",
"assurance_level": 3,
"lineage": { "parents": 0, "children": 0 },
"last_sighting": { "at": "2026-11-21T16:02:33Z", "capture_class": "station", "assurance_level": 3, "result": "match" },
"sightings_count": 2,
"enrolment": {
"record_hash": "sha256:4c3f1a…",
"registry_signature_kid": "reg-2026-1",
"timestamp": { "rfc3161": true, "tsa": "tsa.example", "gen_time": "2026-11-18T09:41:09Z" },
"anchor": { "day": "2026-11-18", "merkle_root": "sha256:a91e…", "url": "https://parcid.com/anchors/2026-11-18" }
},
"public_links": [ { "kind": "sscc", "value": "003412345678901238" } ],
"resolved_at": "2026-11-22T10:00:00Z"
}
3.5 Codes
| HTTP | Meaning |
|---|---|
| 200 | exists (any state, including revoked) |
| 301 | non-canonical form → canonical |
| 404 | valid format, not registered ({"error":"not_found","valid_format":true}) |
| 422 | invalid format or check ({"error":"invalid_id","reason":"check"}) |
| 429 | query limit (§10) |
4. Free API (v1)
Base: https://{host}/api/v1. JSON UTF-8. No account needed to register and resolve. Every call is kept in the registry’s own API log for 90 days, without IP addresses and without keys (they are masked); response bodies are kept only for errors and for operations that change something.
| Method and path | Auth | What it does |
|---|---|---|
GET /verify/{PID} |
none | validates format and check, normalises, says whether it exists and its state. Does not count as a full resolution |
GET /parcels/{PID} |
none | public resolution (§3.4) |
GET /parcels/{PID} |
owner key | full resolution: enrolment record, physical signature, evidence (short-lived signed URLs), private links, sightings in detail |
POST /parcels |
none (or developer key to raise limits) | enrolment: creates the ID, returns the owner key once |
POST /parcels/{PID}/links |
key | adds external references (tracking, SSCC, order…) with visibility |
POST /parcels/{PID}/lineage |
key of the parents | declares opening, consolidation, split or repacking and creates the child |
POST /parcels/{PID}/status |
key | retired (delivered and closed) or lost |
POST /parcels/{PID}/rotate-key |
key | issues a new key and invalidates the previous one |
POST /parcels/{PID}/sightings |
key + paid operator service | sighting with comparison (§8) |
GET /parcels/{PID}/proof |
none | inclusion proof of each of the unit’s records in its daily tree, with the signed statement and the OpenTimestamps proofs (§7.3) |
POST /reservations |
device signature + approved device or developer key | block of up to 1,000 IDs for an offline device (§2.4) |
GET /anchors · GET /anchors/{day} · GET /anchors/{day}.ots |
none | chain of daily statements, each with its signature and its .ots proofs (§7.3) |
GET /export · GET /export/{file} |
none | index of daily exports and download (JSON Lines + gzip, CC0, §12) |
GET /stats |
none | aggregate figures: units by profile, level and month; records by type; latest anchor and export; 24 h volume and latency (§10.1) |
GET /health |
none (detail with the operator token) | health for monitors: status and basic checks; with the token, also storage, disk, anchor and job lag |
GET /metrics |
operator token | Prometheus exposition (§10.1) |
POST /beacon |
none | page counter for the registry website, no cookies, no IP (§10.1) |
GET /.well-known/parcid · GET /00/{SSCC} · GET /{PID} |
none | metadata and keys · GS1 Digital Link · short resolution (§3) |
4.1 The owner key
- Format:
pidk_+ 52 Crockford symbols (260 bits). It is returned only once in the enrolment response. The registry stores onlySHA-256(key). - It gives full control over that parcel and nothing else: read it in full, link, declare lineage, change state, rotate. It identifies nobody: there is no mandatory account behind it. Whoever loses it cannot recover it (there is no personal data to which a recovery could be tied); for that reason it is recommended to store it in the customer’s system next to the ID, or to use a (optional) developer account that holds the keys of its parcels in custody.
- It is sent in
Authorization: Bearer pidk_…. Never in the URL. - Lineage: the child is born with its own key; it is returned to whoever declared the operation.
4.2 Enrolment: POST /parcels
Body multipart/form-data (if files are uploaded) or application/json (if only hashes and the already-computed physical signature are sent). Fields:
| Field | Req. | Content |
|---|---|---|
capture_class |
yes | station · mobile_sdk · third_party_device · api |
unit_profile |
no | parcel (default) · pallet_load · container_load · tote · bag · crate (§1.1). In v0.1 only parcel reaches level 3 |
captured_at |
yes | ISO 8601 UTC from the device |
dimensions_mm |
no | { "l":..,"w":..,"h":.., "tolerance_mm":.. } |
weight_g |
no | `{ “value”:.., “tolerance_g”:.., “scale_class”:“calibrated |
evidence[] |
no | files (JPEG/PNG/WebP ≤ 25 MB, MP4 ≤ 200 MB, PLY/PCD ≤ 50 MB) or { "role":"top","sha256":"…","mime":"image/jpeg","bytes":… } if the client keeps them. Roles: top, perspective, side_*, label_layout, pointcloud, video |
signature |
no | physical signature already computed by the client according to §6 (the station and the SDK compute it; a simple client leaves it to the registry) |
device |
no | { "kid":"…", "public_key":"ed25519:base64", "attestation": {...}, "sequence": 1234, "nonce":"…" }. If sent, device_signature and sequence are mandatory: an unsigned device does not count (nobody can use a station’s public key to burn its quota, push its sequence forward or make a record look like it came from it) |
device_signature |
with device |
Ed25519 over capture_hash (§7.2) |
links[] |
no | external references with kind, value, visibility |
evidence_retention |
no | hashes_only (default in the free tier after 30 days) · store (paid custody storage by the operator) |
consent |
yes | { "no_personal_data": true, "terms_version": "2026-10" }: the registrant declares that no personal data is uploaded outside the images and accepts that the images are stored encrypted |
Response 201:
{
"pid": "PID-1-7QC3-Z79D-G6RZ-8E",
"owner_key": "pidk_3K9FZX1Q7MWB8Y2RHA0C5TDVNEG4PJ6S9ZX1Q7MWB8Y2RHA0C5TDVN",
"owner_key_notice": "Save it now. It is not shown again and cannot be recovered.",
"assurance_level": 3,
"resolution_url": "https://parcid.com/PID-1-7QC3-Z79D-G6RZ-8E",
"qr_url": "https://parcid.com/PID-1-7QC3-Z79D-G6RZ-8E/qr.svg",
"enrolment_record": { "...": "full record, §7.3" },
"free_tier": { "evidence_kept_until": "2026-12-18T09:41:07Z", "hashes_kept": "forever" }
}
4.3 Verification: GET /verify/{PID}
{ "input": "pid-1-7qc3-z79d-g6rz-8e", "canonical": "PID-1-7QC3-Z79D-G6RZ-8E", "format": "valid", "check": "valid", "registered": true, "status": "active", "resolution_url": "https://parcid.com/PID-1-7QC3-Z79D-G6RZ-8E" }
With a wrong check: { "input":"PID-1-7QC3-Z79D-G6RZ-8F", "format":"valid", "check":"invalid", "registered":null } and HTTP 422. This endpoint is for label readers, forms and agents: cheap, without a strict limit and not counting as a resolution.
4.4 Errors
{"error":"code","message":"text","request_id":"…"} with codes: invalid_id, invalid_request, not_found, method_not_allowed, unauthorized (wrong key), forbidden (the state does not allow it), payload_too_large, unsupported_media, rate_limited, consent_required, lineage_conflict, paid_service (operator service not contracted), unavailable, server_error.
5. Registry structure
5.1 Immutable core (never changes)
pid, spec_version, unit_profile, registered_at, capture_class, assurance_level at enrolment, dimensions_mm and weight_g (immutable but private: owner key only), signature_hash (SHA-256 of the canonical physical signature), evidence[] (role, mime, bytes, sha256), device.kid, device_signature, record_hash, registry_signature, tsa_token, anchor_day. It is exactly the content of the enrolment record (§7.3).
5.2 Mutable links (with history; nothing is deleted, things are added)
- External references:
kind∈tracking,sscc(first-class entry key, §1 and §3.3; GS1 check digit verified),sgtin,grai(GS1 returnable asset),bic(container, ISO 6346: 4 letters + 6 digits + check digit, which the registry verifies),seal(ISO 17712 seal),bag_tag(IATA baggage tag, 10 digits),order,invoice,customs_declaration,custom;value;visibility∈private(default),public;added_at,removed_at. Containers, seals and returnable assets are context for the unit (§0.6), never units. - Custody:
holder_class∈sender,warehouse,forwarder,carrier,vehicle,customs,recipient,other;holder_refopaque, chosen by the holder (never a personal name; forvehicle, never the plate or the VIN in clear);from,to. - Sightings: §8.
- State:
active→retired(closed by the holder) ·superseded(consumed by lineage) ·lost(declared by the holder) ·revoked(by the registry, §11). Every change with date and actor (owner,registry).
5.3 Lineage
A parcel is an object in a state. If it is opened, consolidated, split or repacked, a new linked ID is born:
| Operation | Parents → children | State of the parents |
|---|---|---|
open |
1 → 1 (the same box opened and closed again) | superseded |
repack |
1 → 1 (another box) | superseded |
consolidate |
N → 1 | all superseded |
split |
1 → N | superseded |
attach |
1 → 1 (the same object gains a higher-level capture, e.g. mobile → station) | stays active; it is a sighting, not lineage |
Each operation is a record (§7) signed by whoever performs it, with the pids of parents and children and the hashes of the evidence. The resolution of a child shows its parents and that of a parent its children; the full history is followed through the graph.
6. The physical signature
6.1 Format
Canonical, compact JSON object (target < 300 KB), separate from the raw evidence. It is stored in full in the registry (it contains no personal data) and its hash is published in the record; its content is read by whoever holds the key and by the comparison services.
{
"schema": "parcid.signature/1",
"unit_profile": "parcel",
"capture_class": "station",
"frame": { "origin": "corner_0_0_0", "axes": "l_w_h", "unit": "mm", "calibration": "pns-ruler-60x60/1" },
"features": [
{ "type": "geometry", "model": "geom/1", "value": { "l": 412, "w": 306, "h": 218, "volume_cm3": 27493, "ratios": [1.346, 1.404] },
"tolerance": { "mm": 3 }, "quality": 0.98, "stability": "high" },
{ "type": "weight", "model": "weight/1", "value": { "g": 3840, "tolerance_g": 5, "scale_class": "calibrated" }, "quality": 1.0, "stability": "high" },
{ "type": "shape3d", "model": "pcd-desc/1", "dim": 256, "dtype": "float16", "vector": "base64…", "quality": 0.91, "stability": "medium" },
{ "type": "texture_patch", "model": "paper-fp/1", "patch": "A", "face": "top", "pos_mm": [30, 30], "size_mm": 25, "dim": 512, "dtype": "uint8", "vector": "base64…", "quality": 0.87, "stability": "high" },
{ "type": "texture_patch", "model": "paper-fp/1", "patch": "B", "face": "top", "pos_mm": [382, 30], "size_mm": 25, "dim": 512, "dtype": "uint8", "vector": "base64…", "quality": 0.84, "stability": "high" },
{ "type": "texture_patch", "model": "paper-fp/1", "patch": "C", "face": "front", "pos_mm": [30, 30], "size_mm": 25, "dim": 512, "dtype": "uint8", "vector": "base64…", "quality": 0.80, "stability": "high" },
{ "type": "texture_patch", "model": "paper-fp/1", "patch": "D", "face": "right", "pos_mm": [30, 30], "size_mm": 25, "dim": 512, "dtype": "uint8", "vector": "base64…", "quality": 0.78, "stability": "high" },
{ "type": "tape", "model": "tape-path/1", "value": { "faces": ["top", "bottom"], "polyline_mm": [[0, 153], [412, 153]], "width_mm": 48, "overlaps": 1, "color": "brown" }, "quality": 0.9, "stability": "high_until_opened" },
{ "type": "label_layout", "model": "label-geo/1", "value": { "face": "top", "bbox_mm": [110, 40, 210, 148], "rotation_deg": 0.8, "barcodes": 2, "print_defects": 3 }, "quality": 0.93, "stability": "high_until_relabel", "note": "geometry only, never the content" },
{ "type": "appearance", "model": "box-emb/1", "views": ["top", "perspective"], "dim": 512, "dtype": "float16", "vector": "base64…", "quality": 0.9, "stability": "medium" },
{ "type": "damage_map", "model": "damage/1", "value": { "items": [ { "face": "front", "bbox_mm": [300, 150, 360, 210], "kind": "dent", "severity": 0.3 } ] }, "quality": 0.85, "stability": "changes_informatively" }
],
"hash": "sha256:9b2d…"
}
6.2 Rules
modelversions the algorithm that produced the feature; two features are compared only if they sharemodelor a declared adapter exists. An old signature is never recomputed: a new capture (sighting) with the new models is added.quality∈ [0,1] is the quality of the feature’s capture (focus, occlusion, coverage).stabilitydescribes how the feature ages.- Weighted fusion: the comparison (§8) scores per feature and then globally; the weight of each feature depends on its
qualityin both captures, on itsstabilityand on the threshold profile calibrated for the pair of capture classes. - Zero personal data:
label_layoutstores box, rotation, number of codes and print defects. Including OCR text, decoded barcodes or label crops in the signature is forbidden. OCR, if done, lives in the operator’s customer account, not in the registry.
6.3 Features by capture class (parcel profile)
| Feature | station | mobile_sdk | third_party_device | api |
|---|---|---|---|---|
| geometry | measured (point cloud) | estimated (rulers/ARKit/ARCore) | depends on device | declared |
| weight | calibrated scale | no (or declared) | depends on device | declared |
| shape3d | yes | partial | depends on device | no |
| texture_patch | 4 patches, 2 cameras | 2–4 patches, lower resolution | depends on device | no |
| tape, label_layout, appearance, damage_map | yes | yes | depends on device | no |
6.4 Fixed positions of the texture patches
The patches are taken at fixed coordinates relative to the origin corner (0·0·0: the one that rests in the angle of the rulers at the station; on mobile, the lower-left corner of the top face as seen from the label). 25 × 25 mm patch: A top face at (30, 30) mm; B top face at (L − 30, 30); C front face at (30, 30); D right face at (30, 30). If a position falls on a label or tape, it is shifted to the nearest free point and the actual pos_mm is recorded. In this way the same box yields comparable patches in different captures and the texture separates factory-identical boxes.
6.5 Unit profiles
The physical signature carries unit_profile next to capture_class. The parcel profile is the one defined in §6.1–6.4. For pallet_load, container_load, tote, bag and crate, v0.1 accepts the generic features (geometry, weight, appearance, damage_map, label_layout) and leaves their own features and fixed patch positions for v0.2: stretch film and stacking pattern on the loaded pallet; grain, nails and block stamps on wooden assets; zips, handles and fabric texture on luggage. Until then those profiles do not go beyond level 2 (DECISION 9).
7. Records: format, hash, signatures, timestamp
7.1 Canonicalisation and hash
- Canonical JSON according to RFC 8785 (JCS): sorted keys, no whitespace, numbers in ES6 format, UTF-8. Binaries go in base64; hashes as
sha256:+ lowercase hex. Number restriction to avoid ambiguity between implementations: only integers up to 2^53 or decimals below 10^9 with at most 6 decimal places; any other number is rejected. record_hash = SHA-256(canonical bytes of the record without the "signatures" and "timestamp" fields).
7.2 Signatures
- From the device or client (optional, raises the level): Ed25519 over
capture_hash= SHA-256 of the canonical sub-object the device controls (pid,captured_at,capture_class,device,measurements,signature_hash,evidence,liveness). The device cannot sign the full record because it does not knowreceived_ator the assigned level; since the record includescapture_hash, the registry signature overrecord_hashalso covers what the device signed. The signature is computed over the 32 bytes of the digest.kid=sha256:of the public key, first 16 bytes in hex. Station keys are registered at device enrolment with the operator; SDK keys, per installation (Play Integrity / App Attest / WebAuthn attestation where available). - From the registry (always): Ed25519 with the key published at
/.well-known/parcid(kidof the formreg-2026-1), overrecord_hash. It proves that the registry accepted the record as it stands. - Sequence and chain:
device.sequencemonotonic per key;prev_record_hashchains the records of one device. Repeated or regressing sequences are rejected (quarantine).
7.3 Record ledger, daily anchor and Bitcoin (DECISION 3)
- Record ledger (append-only). Every sealed record —enrolment, lineage, sighting, status change, key rotation, reservation— enters the ledger with a global order number
seqand the ledger day on which it was sealed. The day is the UTC day of sealing, unless that day is already closed, in which case it is the first open day: no record can ever fall into an already anchored day (sealing takes a shared ledger lock and closing a day takes an exclusive one). - Daily tree (RFC 6962, SHA-256). The leaves are the 32 bytes of each
record_hashof the day inseqorder.leaf = SHA-256(0x00 ‖ record_hash),node = SHA-256(0x01 ‖ left ‖ right), empty tree =SHA-256(""). Inclusion proofs are verified with the algorithm of RFC 9162 §2.1.3.2. - Chained daily statement (
parcid.anchor/1), RFC 8785 canonical JSON:{ schema, registry, day, tree:"rfc6962-sha256", leaf:"record_hash", leaf_count, first_seq, last_seq, merkle_root, prev_statement_hash, registry_kid }.statement_hash = SHA-256(canonical); the registry signs those 32 bytes with Ed25519. Each statement carries the hash of the previous day’s: days without records are anchored too (empty tree) and a gap in the chain is, by itself, an alarm. - Bitcoin through OpenTimestamps. Each day’s
statement_hashis sent to several public calendars (by defaulta.pool.opentimestamps.org,b.pool.opentimestamps.org,a.pool.eternitywall.com) and one standard.otsproof per calendar is kept; once the calendar confirms it in a block, the proof is completed with the branch up to the Bitcoin header. Free, no tokens, no wallets. Anyone verifies with the official client (ots verify) or withtools/verify: the message in the attestation is the block’s Merkle root. - Confirmed in Bitcoin means the registry checked, against a configured block explorer, that the block’s Merkle root is the attestation’s message; the calendar’s word is not enough. Calendar URIs that are followed come from a closed list, with no redirects and a size cap.
- Per-unit proof.
GET /parcels/{PID}/proofreturns, for each of the unit’s records:record_hash, day,leaf_index,tree_size,audit_path,merkle_root, the statement with its signature and its.otsproofs. With that and the public key of/.well-known/parcideverything is verified without querying the registry’s database. - RFC 3161 (optional):
timestamp.rfc3161.token= DER TimeStampToken in base64 overrecord_hash, withtsaandgen_time, from an eIDAS qualified TSA for operator records that need evidential value in the EU. It does not change the assurance level: time is fixed by the daily anchor. - No NFTs and no owned tokens. Only hashes go on chain; the owner key stays off chain. DECISION 12 (optional, pending): a second layer on an Ethereum L2 publishing
PID + record_hashpairs in batches, so that each ID can be looked up on chain without downloading the export.
7.4 Example enrolment record (enrolment)
{
"schema": "parcid.record/1",
"type": "enrolment",
"pid": "PID-1-7QC3-Z79D-G6RZ-8E",
"captured_at": "2026-11-18T09:40:58Z",
"received_at": "2026-11-18T09:41:07Z",
"capture_class": "station",
"assurance_level": 3,
"device": { "kid": "sha256:7f3a9c1e2b4d6f8091a2b3c4d5e6f708", "class": "station", "model": "packnsign-60", "sequence": 18233, "prev_record_hash": "sha256:11d0…", "attestation": "operator_registered", "nonce": "b64:Q3Z…" },
"measurements": { "dimensions_mm": { "l": 412, "w": 306, "h": 218, "tolerance_mm": 3 }, "weight_g": { "value": 3840, "tolerance_g": 5, "scale_class": "calibrated" } },
"signature_hash": "sha256:9b2d…",
"evidence": [
{ "role": "top", "mime": "image/jpeg", "bytes": 2418833, "sha256": "sha256:0c7e…" },
{ "role": "perspective", "mime": "image/jpeg", "bytes": 2601120, "sha256": "sha256:51aa…" },
{ "role": "pointcloud", "mime": "application/vnd.ply", "bytes": 8120044, "sha256": "sha256:e3f9…" }
],
"liveness": { "level": "high", "signals": ["device_attested", "scene_physics_ok", "nonce_in_frame", "multisensor_coherent"] },
"links": [ { "kind": "sscc", "value": "003412345678901238", "visibility": "public" } ],
"consent": { "no_personal_data": true, "terms_version": "2026-10" },
"record_hash": "sha256:4c3f1a…",
"signatures": [
{ "by": "device", "alg": "Ed25519", "kid": "sha256:7f3a9c1e2b4d6f8091a2b3c4d5e6f708", "sig": "base64…" },
{ "by": "registry", "alg": "Ed25519", "kid": "reg-2026-1", "sig": "base64…" }
],
"timestamp": { "rfc3161": { "tsa": "tsa.example", "gen_time": "2026-11-18T09:41:09Z", "token": "base64…" }, "anchor": { "day": "2026-11-18", "merkle_root": "sha256:a91e…", "proof_url": "https://parcid.com/api/v1/parcels/PID-1-7QC3-Z79D-G6RZ-8E/proof" } }
}
(The signatures and tokens in the example are illustrative; the hashes are abbreviated.)
7.5 Change records
Every change to a unit is a signed record and enters the ledger, chained to the enrolment record (unit_record_hash):
status:{ schema, type:"status", pid, spec, at, unit_record_hash, from, to, actor:"owner"|"registry", reason_code?, registry }. Issued by the holder (retired,lost), by lineage (superseded) and by the registry (revoked, §11).rotation:{ …, type:"rotation", owner_key_commitment }when the owner key is rotated.owner_key_commitment = "sha256:" + hex(SHA-256("parcid-owner-key-v1|" + hex(SHA-256(key)))): it reveals nothing about a 260-bit key and lets the audit check that the current key is the one of the last sealed rotation (or of the enrolment, which carries the same field).reservation:{ schema, type:"reservation", reservation_id, device_kid, count, pids_sha256, expires_at, request_hash, at, registry }.pids_sha256is the hash of the list of reserved IDs (one per line); only the device receives the list.
7.6 What a record asserts and what it does not
capture_class_verified:trueonly if the capture class is backed by an approved device of that class that signed (or if it isapi, which is declarative). Astationcapture without an approved station is declared.device.attestation:operator_registeredonly with a valid signature from an approved device; otherwiseunverified.owner_key_commitment: see §7.5.timestampis not part of the hash: time is fixed by the/proofevidence (ledger day, tree and anchor).
8. Sightings
A sighting is a new capture of the same parcel claiming an ID, with the result of the 1:1 comparison against the enrolment signature (or that of the last accepted sighting) and an explanation. It is a record (§7) of type sighting. The public part (date, class, level, result) appears in the resolution; the detail only with the key.
{
"schema": "parcid.record/1",
"type": "sighting",
"pid": "PID-1-7QC3-Z79D-G6RZ-8E",
"captured_at": "2026-11-21T16:02:20Z",
"capture_class": "station",
"assurance_level": 3,
"device": { "kid": "sha256:2a…", "class": "station", "model": "packnsign-60", "sequence": 902 },
"compared_to": { "record_hash": "sha256:4c3f1a…", "signature_hash": "sha256:9b2d…" },
"match": {
"profile": "station-station/v1",
"score": 0.94,
"decision": "match",
"thresholds": { "match": 0.85, "review": 0.65 },
"per_feature": [
{ "type": "geometry", "score": 0.99, "note": "±2 mm" },
{ "type": "weight", "score": 0.98, "note": "−6 g" },
{ "type": "texture_patch", "patch": "A", "score": 0.93 },
{ "type": "texture_patch", "patch": "B", "score": 0.91 },
{ "type": "tape", "score": 0.97 },
{ "type": "damage_map", "score": 0.70, "note": "new dent on front face, severity 0.3" }
],
"explanation": "Same geometry and weight; the texture of patches A and B matches; the tape is the same; there is new damage on the front face."
},
"liveness": { "level": "high", "signals": ["device_attested", "scene_physics_ok", "nonce_in_frame", "multisensor_coherent"] },
"custody": { "holder_class": "warehouse", "holder_ref": "opaque:mde-vlc-01" },
"record_hash": "sha256:77be…",
"signatures": [ { "by": "device", "alg": "Ed25519", "kid": "sha256:2a…", "sig": "base64…" }, { "by": "registry", "alg": "Ed25519", "kid": "reg-2026-1", "sig": "base64…" } ],
"timestamp": { "rfc3161": { "tsa": "tsa.example", "gen_time": "2026-11-21T16:02:35Z", "token": "base64…" } }
}
decision∈match,review,no_match. Ano_matchis also recorded (it is information: someone presented this ID with a different box).- Third-party sightings without capture (carrier events via the operator’s tracking service) are recorded as
sightingwithcapture_class: "api",assurance_level: 0and nomatch; they inform about the route, not about identity.
9. Assurance levels
| Level | Name | Requirements | How it is shown |
|---|---|---|---|
| 0 | unverified |
enrolment by API without device signature or verified evidence | “Registered (unverified)” |
| 1 | signed |
Ed25519 signature from the client’s key, valid sequence, at least 2 pieces of evidence with hash, dimensions or weight | “Signed” |
| 2 | attested |
the above + device attestation (SDK, once the registry verifies Play Integrity / App Attest) or a device enrolled in the registry’s trusted-device list + freshness nonce + physical signature with texture patches | “Attested” |
| 3 | station |
the above at a registered station with normalised geometry, calibrated scale, point cloud and multisensor coherence (time is fixed by the daily anchor; the RFC 3161 stamp is optional) | “Station” |
The level is that of enrolment; each sighting carries its own. A parcel enrolled at level 1 that passes through a station obtains a level 3 sighting (attach), and the resolution shows “best level reached: 3”.
10. Free tier, limits and abuse
| Item | Value (DECISION 4, decided; reviewed with real usage data) |
|---|---|
| Enrolments without developer key | 100 / month per IP address and per device key |
| Enrolments with free developer key (verified email) | 1,000 / month |
| Public resolution | 60 / min per IP; 600 / min with key |
GET /verify |
600 / min per IP |
| Raw evidence in the free tier | 30 days encrypted (XChaCha20-Poly1305 in chunks, per-parcel key wrapped with the registry master key); afterwards only hashes. Long-term custody storage is an operator service |
| Physical signature and record | kept indefinitely |
| Size per enrolment | 25 MB per image, 200 MB video, 50 MB point cloud; 300 MB in total |
- Enrolments without device signature remain at level 0 and count against stricter limits.
- Source reputation: each device key, developer key and IP accumulates a score; many orphan enrolments (without sightings or links within 90 days) or incoherent ones lower the maximum level that source can obtain. Public in aggregate, not per source.
- The operator’s paid quotas (minimum €300/month per customer) apply to sightings with comparison, proof of liveness, 1:1 and 1:N comparison and custody storage, never to enrolment or resolution.
10.0 Abuse: what the registry prevents
- Disk: without a developer key or an approved device, raw video and point clouds are not stored (only their hashes), with a cap of 1 GB per month per IP and 5 GB per day overall; below 10 GB free no raw evidence is stored (507). IPv6 counts per /64.
- Images: dimensions are read from the header before decoding; more than 40 megapixels, 413.
- Ledger: each unit accepts at most 100 holder operations and 5 key rotations per day;
/proofis paginated by 100; the daily tree is built in streaming, with constant memory. - Reservations: the same signed request cannot be replayed; daily caps per device and per developer key.
- Sightings: only recorded by an operator with the service (developer key with sightings; the unit key goes in
X-Parcid-Owner-Key). - Website counter: same origin only, with a cap on distinct rows per day.
- Real IP: the proxy header is trusted only when the connection comes from a trusted proxy.
- Revoked unit: its evidence is not served; revocation for illegal content destroys the raw files at once.
10.1 Measurement without personal data
- Technical: count per minute, route, method and HTTP status, with sum, maximum and cumulative latency histogram (≤10, 50, 100, 250, 500, 1000, 5000 ms) and bytes served. Kept per minute for 14 days.
- Business and website: events per day with two dimensions: enrolments by class and profile, levels, resolutions, sightings, reservations, status changes, limits hit, errors, scheduled jobs, page views by route and language, and referring domain. Routes containing a PID are counted together, never per ID.
- Nothing is ever stored or counted per person: no IP addresses (limits use an HMAC with the registry’s salt in counters that expire after 40 days; units keep nothing about who enrolled them), no cookies, no browser fingerprint. The website honours
Do Not TrackandGlobal Privacy Controland sends nothing in that case. - Aggregate public exposition at
GET /stats; full exposition for the operator atGET /metrics(Prometheus, with a token).
11. Revocation and data governance
- The registry revokes (
revoked) only for demonstrated abuse (mass junk enrolments, illegal content in evidence, device impersonation). Revocation is public, motivated by a code (abuse,illegal_content,device_compromised) and keeps the record: a revoked ID continues to resolve with its state. - The holder may request deletion of the raw evidence at any time (right over images that might contain personal data). The hashes and the physical signature are not deleted: they are not personal data and they underpin third-party verifiability.
- There is no “correction” of a record: another one is added that amends it, and the old one is marked
superseded_by.
12. Export, independent verification and permanence
- Full daily export (
parcid.export/1, JSON Lines + gzip, CC0) atGET /export/{file}, indexed atGET /export. Lines, in this order:export_header(registry, day, licence, public keys) · oneunitper unit (public part only:pid_tag,pid_salt, status, profile, class, levels,record_hash, registry signature, anchor day, lineage bypid_tagand public links) · onerecordper ledger entry (seq, day,record_hash, type, the unit’spid_tag) · oneanchorper day (statement, signature and.otsproofs) ·export_manifest(counts,content_sha256of all previous lines,manifest_hashand the registry’s Ed25519 signature). From a single file every daily root, the chain of statements and every signature can be recomputed (tools/verify/cli.mjs export). - Export versus enumeration (DECISION 7, decided 23/10/2026; format corrected after the security review). The export never carries the plain PID. Each unit carries its own random 16-byte salt and its tag:
pid_salt(hex) andpid_tag = "sha256:" + hex(SHA-256(bytes(pid_salt) ‖ canonical PID in ASCII)); lineage is expressed with the parents’ and children’spid_tag. Whoever holds a PID finds its unit by computing one SHA-256 per unit (tools/verifyfindInExport). With an unsalted hash, the list of PIDs could be brute-forced once the registry held millions of units (2⁶⁰/N attempts per PID); with a per-unit salt each one costs 2⁵⁹ attempts on average and there is no shortcut. Volume is published as an aggregate figure (§10.1). - With the enrolment record, the registry’s public key and the inclusion proof in the anchor, anyone can verify without querying the registry: recompute the
record_hashover the canonical JSON, check the Ed25519 signatures, follow the Merkle path up to the published root and verify the OpenTimestamps proof against the Bitcoin block header (and the RFC 3161 token against the TSA chain, if present). - Permanence beyond the operator (DECISION 11, decided 22/10/2026). The daily public export (CC0) is also published on permanent pay-once storage (Arweave); the code of the resolver, the API and the verification tool is archived in Software Heritage; every version of this specification is deposited in Zenodo with a DOI. With the export, the registry’s public key and the Bitcoin proofs, anyone can rebuild the public registry without the operator.
- Database backup: every day, a consistent logical dump, compressed and encrypted in chunks (XChaCha20-Poly1305) with a one-time key sealed to the backup public key (X25519). The server does not hold the private key: whoever breaks into the server cannot read the backups. Rotation 7 daily, 5 weekly, 12 monthly, copy to external storage and an automated restore drill (
registry/tests/restore-drill.mjs). - Raw evidence: it is not part of the export. The operator offers perpetual custody as a paid service at cost price, encrypted with the owner key; without that service the free-tier expiry applies (§10).
13. Namespace governance
- The current operator (Know Your Parcel, a division of MDE HUB SL) publicly commits to hand over the
PIDnamespace, the specification, the resolver and the export to a non-profit entity when one of these conditions is met (DECISION 5, decided): three external operators issuing enrolments, or one million active IDs, or 24 months since public launch, or the continuity switch below. - Continuity switch (DECISION 11): if the operator stops publishing the daily anchor for 90 consecutive days, any mirror may continue the registry from the last export and the published rotated keys, and that situation counts as an automatic hand-over condition.
- In the meantime: separate accounting of the cost of the free registry, an open technical committee for specification changes (semantic versions; changes to the ID format only with a new version symbol), publication of the registry keys with rotation date, and the code of the resolver, the API and the verifier under Apache-2.0 in a public repository so that anyone can run a mirror (DECISION 6); the operator’s comparison models stay outside: the signature format is public, the engine belongs to the operator.
14. Compatibility with the operator’s platform
- The registry has its own database (migrations in
registry/sql/), separate from the operator’s: so it can be handed over, mirrored and audited as a whole without carrying the operator’s data. The operator is just another API client. On its platform it only stores thepid(and the owner key, encrypted) next to its own shipments and records. - The operator’s tracking service contributes sightings of class
api, level 0. - The operator (Know Your Parcel, a GS1/AECOC member with its own company prefix) issues SSCCs for the units it handles and prints them next to the PID on the same label. The registry never issues SSCCs: GS1 forbids sharing company prefixes; the registry only accepts them as an entry key (§1, §3.3).
- The operator’s “Parcel Match” becomes the 1:1 comparison of §8, calibrated with the pilot (phase 4 of this thread).
15. Decisions (summary)
Decided by Damián Guerschuny (“all good, go ahead”, 23/10/2026, on the proposals in this specification):
Bits: 60-bit payload + 2 check symbols, 23 characters (§2.2).Host:parcid.com.Timestamping: daily anchor in Bitcoin with OpenTimestamps; RFC 3161 optional (§7.3).Free-tier limits: those in the table of §10; reviewed with real usage data.Handover condition: the one in §13 (three external operators, one million active IDs, 24 months after public launch, or the continuity switch).Licences: CC BY 4.0 (specification), CC0 (reference code, verifier and data), Apache-2.0 (resolver and API).Export: no plain PIDs; each unit identified bySHA-256(own salt ‖ PID)(§12).Reserved blocks:POST /reservationsfor approved devices or devices with a developer key; expired IDs are burned (§2.4).Scope: units in transit with the profiles of §1.1; profiles other thanparcelcapped at level 2 until v0.3 (§6.5).Name: PARCID; identifier prefixPID.Permanence: Arweave, Software Heritage, Zenodo, perpetual custody of evidence at cost price, 90-day switch (§12, §13).
Pending:
12. Optional: a second layer on an Ethereum L2 with PID + record_hash pairs in batches (§7.3).
16. History
- v0.1 · 22/10/2026 · first complete draft (identifier, resolution, free API with owner key, physical signature, records, sightings, levels, limits, governance).
- v0.1 · 22/10/2026 · scope widened to units in transit: principle 6, unit profiles (§1.1, §6.5),
unit_profilein record, API and resolution,bic/seal/grai/bag_taglinks,vehiclecustodian, OpenTimestamps in §7.3, decisions 9 and 10. - v0.1 · 22/10/2026 · Damián’s decisions: the registry is a layer on top of the SSCC (first-class entry key, §1, §3.3, §5.2, §14); DECISION 3 closed with a Bitcoin anchor via OpenTimestamps (§7.3); DECISION 6 closed with Apache-2.0 for resolver, API and verifier; DECISION 11 permanence (Arweave, Software Heritage, Zenodo, perpetual custody, 90-day switch, §12, §13); DECISION 12 new (optional L2).
- v0.2 · 23/10/2026 · name PARCID and host
parcid.com; record ledger with ledger day and closing lock, RFC 6962 tree, chained and signed daily statement, OpenTimestamps per calendar and/proof(§7.3); change recordsstatus,rotation,reservation(§7.5); measurement without personal data and routes/stats,/health,/metrics,/beacon(§4, §10.1); export formatparcid.export/1withpid_sha256(§12); backup encrypted to a public key (§12); the registry’s own database (§14); decisions 1, 2, 4, 5, 7, 8, 9 and 10 closed (§15). - v0.2 · 23/10/2026 · after an independent security review: export with a per-unit salt (
pid_tag,pid_salt) instead ofsha256(PID); signature and sequence mandatory withdevice;capture_class_verifiedandowner_key_commitmentin records (§7.6);claimon GS1 (§3.3); public lineage with counts only; sightings by operators only; “confirmed in Bitcoin” verified against the block; abuse limits (§10.0).
Comments? The specification is open to the technical committee: see Governance. →