Seal a passport version
POST /api/rooms/{roomCode}/passport
Requires your partner key; the room must be yours. Each call mints the next version — a dated snapshot, never an overwrite. Repeated calls create new versions by design, capped at 20 versions per room. Rate limited with partner-write (60/min per key).
Sealing also builds a certificate PDF carrying the manifest’s facts, seals it with the same Google Cloud KMS seal every first-party envelope gets, and archives it for the public download endpoint.
Your room’s code.
The new version number, starting at 1 and incrementing per room.
The public verification code for this version — 26 lowercase base32
characters encoding 128 bits of entropy. Possession of the code is the
authorization to verify.
Root-relative path to the public verification page,
/v/room/{verifyCode}.
Prefix with https://signsealship.com before sharing.SHA-256 (lowercase hex) of the canonical manifest’s UTF-8 bytes.
The prior version’s
manifestSha256 — the hash-chain link. null on
version 1.SHA-256 (lowercase hex) of the sealed certificate PDF.
ISO 8601 sealing time.
200 OK
404 {"error": "Room not found."} for a room that is not yours, 400 {"error": "Passport version quota reached (20 versions per room)."} at the cap.
Verify a passport (public)
GET /api/verify/room/{verifyCode}
Public — the verify code is the bearer. Rate limited with public-read (30/min per IP). Malformed and unknown codes return the identical generic 404, {"verdict": "unknown"}, so codes cannot be enumerated.
The manifest is returned parsed alongside its hash so any verifier can re-canonicalize and re-hash independently.
The passport’s 26-character verification code.
The stored canonical manifest, parsed. See the manifest
below for its full shape.
SHA-256 (lowercase hex) of the canonical manifest bytes.
SHA-256 (lowercase hex) of the sealed certificate PDF.
This passport’s version number.
The prior version’s manifest hash, or
null on version 1.Recomputed on every call — never a stored verdict.
true only when both
hold: the stored manifest re-hashes to manifestSha256, and the chain link
is intact — on version 1, prevManifestSha256 is null; on later versions
it equals the prior version’s stored manifestSha256. false means the
stored manifest or its lineage does not check out; do not rely on the
passport.The owning partner’s branding block (
brandName, accentColor,
logoUrl), or null. Rendered as attribution only — the SignSealShip
identity and disclosures always remain.ISO 8601 sealing time of this version.
Root-relative path to the sealed certificate PDF,
/api/verify/room/{verifyCode}/pdf.The manifest
The manifest is canonical JSON: object keys sorted ordinally, no insignificant whitespace, invariant culture, UTF-8, hashes in lowercase hex, non-ASCII characters escaped as\uXXXX, and generatedAtUtc in ISO 8601 at second precision, always UTC. The same inputs always produce byte-identical output — that determinism is what makes manifestSha256 meaningful.
Manifest structure
passport
Room identity and lineage:roomCode, roomName, reference (or null), version, prevManifestSha256 (or null on version 1), and generatedAtUtc.
documents
One entry per attached order, sorted byorderCode (ordinal). Two rules keep it honest:
statusAtSnapshotis an attestation object, not a bare string. It always carriesbasis: "platform_attestation", the verbatimnoteshown above, and the order’s status invalue. The status is what SignSealShip’s records said at snapshot time — it is labeled as such precisely because it is not cryptographic evidence.- Hash and code fields appear only when the artifact exists.
originalSha256,sealedSha256,envelopeVerifyCode, andcustodyCertSha256are omitted entirely — nevernull— when there is no artifact behind them. A missing key means no evidence is claimed; a reader can never mistake an empty slot for proof.
coverage
The manifest enumerates what its hashes actually prove (covers) and what they do not (doesNotCover), verbatim as shown above. Delivery confirmation is always listed as not covered: the platform records carrier scans but holds no delivered-shipment artifact hash.
Verifying independently
Recompute the manifest hash
Serialize the manifest with ordinally sorted keys, no insignificant
whitespace, and non-ASCII escaped as
\uXXXX; SHA-256 the UTF-8 bytes and
compare the lowercase hex to manifestSha256.Check the chain
Fetch the prior version’s verify record and confirm
prevManifestSha256
equals its manifestSha256. The verify endpoint does both checks for you
on every call and reports them as chainOk.Download the sealed certificate (public)
GET /api/verify/room/{verifyCode}/pdf
Streams the sealed Closing Passport certificate as application/pdf (filename signsealship-closing-passport-v{version}.pdf). The verify code is the bearer; rate limited with public-read. An unknown code — or a passport whose archived PDF is unavailable — returns the same generic {"verdict": "unknown"} 404.
curl
Sealing a passport also emits a
room.passport_sealed event to subscribed
webhooks — see webhooks.