Skip to main content
A Closing Passport is a room-level, versioned, KMS-sealed evidence manifest: a canonical, deterministic snapshot of every attached document’s cryptographic facts — original and sealed hashes, envelope verify codes, custody-certificate hashes — hash-chained to the versions before it and verifiable by anyone at a public link, without trusting SignSealShip. Its honest limits, spelled out in every manifest’s own coverage statement: document statuses in the manifest are a platform attestation at snapshot time, not independent evidence, and the passport says nothing about payment state, delivery confirmation, or any document that was not attached to the room.

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.
roomCode
string
required
Your room’s code.
curl -X POST https://signsealship.com/api/rooms/{roomCode}/passport \
  -H "Authorization: Bearer sss_pk_your_key"
const res = await fetch(
  `https://signsealship.com/api/rooms/${roomCode}/passport`,
  {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.SSS_PARTNER_KEY}` },
  },
);
const passport = await res.json();
console.log(`https://signsealship.com${passport.verifyUrl}`);
import os
import requests

res = requests.post(
    f"https://signsealship.com/api/rooms/{room_code}/passport",
    headers={"Authorization": f"Bearer {os.environ['SSS_PARTNER_KEY']}"},
)
passport = res.json()
print(f"https://signsealship.com{passport['verifyUrl']}")
version
integer
The new version number, starting at 1 and incrementing per room.
verifyCode
string
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.
verifyUrl
string
Root-relative path to the public verification page, /v/room/{verifyCode}. Prefix with https://signsealship.com before sharing.
manifestSha256
string
SHA-256 (lowercase hex) of the canonical manifest’s UTF-8 bytes.
prevManifestSha256
string
The prior version’s manifestSha256 — the hash-chain link. null on version 1.
sealedSha256
string
SHA-256 (lowercase hex) of the sealed certificate PDF.
createdAt
string
ISO 8601 sealing time.
200 OK
{
  "version": 2,
  "verifyCode": "zyxwvutsrqponmlkjihgfedcba",
  "verifyUrl": "/v/room/zyxwvutsrqponmlkjihgfedcba",
  "manifestSha256": "9d3c...e1f0",
  "prevManifestSha256": "4b7a...c2d9",
  "sealedSha256": "71aa...0b3e",
  "createdAt": "2026-07-12T20:01:00+00:00"
}
Errors: 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.
verifyCode
string
required
The passport’s 26-character verification code.
curl https://signsealship.com/api/verify/room/{verifyCode}
const res = await fetch(
  `https://signsealship.com/api/verify/room/${verifyCode}`,
);
if (res.ok) {
  const check = await res.json();
  console.log(check.chainOk, check.manifest.coverage.doesNotCover);
}
import requests

res = requests.get(f"https://signsealship.com/api/verify/room/{verify_code}")
if res.ok:
    check = res.json()
    print(check["chainOk"], check["manifest"]["coverage"]["doesNotCover"])
manifest
object
The stored canonical manifest, parsed. See the manifest below for its full shape.
manifestSha256
string
SHA-256 (lowercase hex) of the canonical manifest bytes.
sealedSha256
string
SHA-256 (lowercase hex) of the sealed certificate PDF.
version
integer
This passport’s version number.
prevManifestSha256
string
The prior version’s manifest hash, or null on version 1.
chainOk
boolean
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.
branding
object
The owning partner’s branding block (brandName, accentColor, logoUrl), or null. Rendered as attribution only — the SignSealShip identity and disclosures always remain.
createdAt
string
ISO 8601 sealing time of this version.
downloadUrl
string
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
{
  "coverage": {
    "covers": [
      "sha-256 hashes of document artifacts held by signsealship for the listed orders at snapshot time",
      "the room passport version chain via prevManifestSha256"
    ],
    "doesNotCover": [
      "payment or refund state",
      "delivery confirmation (no delivered-shipment artifact hash exists)",
      "documents or orders not attached to the room at snapshot time",
      "statusAtSnapshot values, which are platform attestations rather than evidence",
      "anything that happened after generatedAtUtc"
    ]
  },
  "documents": [
    {
      "custodyCertSha256": "b2c4...9e0a",
      "envelopeVerifyCode": "abcdefghijklmnopqrstuvwxyz",
      "label": "Seller deed package",
      "orderCode": "an-order-public-code",
      "originalSha256": "5f6e...1a2b",
      "sealedSha256": "8c9d...3e4f",
      "statusAtSnapshot": {
        "basis": "platform_attestation",
        "note": "platform attestation by signsealship at snapshot time; not cryptographic evidence",
        "value": "NotarizationComplete"
      }
    }
  ],
  "passport": {
    "generatedAtUtc": "2026-07-12T20:01:00Z",
    "prevManifestSha256": "4b7a...c2d9",
    "reference": "TC-88412",
    "roomCode": "3f1c9a7e5b2d8c4a6e0f9b1d3a5c7e9f2b4d6a8c",
    "roomName": "1428 Maple St — Refinance",
    "version": 2
  }
}

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 by orderCode (ordinal). Two rules keep it honest:
  • statusAtSnapshot is an attestation object, not a bare string. It always carries basis: "platform_attestation", the verbatim note shown above, and the order’s status in value. 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, and custodyCertSha256 are omitted entirely — never null — 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

1

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.
2

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.
3

Check the sealed certificate

Download the PDF below, SHA-256 it, and compare to sealedSha256. The KMS seal itself is a CMS signature visible in any PDF reader’s signature panel.

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
curl -L -o closing-passport.pdf \
  https://signsealship.com/api/verify/room/{verifyCode}/pdf
Sealing a passport also emits a room.passport_sealed event to subscribed webhooks — see webhooks.