> ## Documentation Index
> Fetch the complete documentation index at: https://docs.signsealship.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Closing Passport: sealed evidence manifests per room

> How the Closing Passport works: a versioned, KMS-sealed evidence manifest per room with canonical JSON, hash chain, public verification, and coverage statement.

A **Closing Passport** is a room-level, versioned, sealed evidence manifest: one artifact that rolls up everything cryptographically true about the transaction at a point in time. Any party — or a downstream authority years later — can verify it at a public link without trusting SignSealShip.

You mint one with a single call:

```bash Seal the next passport version theme={null}
curl -X POST https://signsealship.com/api/rooms/{roomCode}/passport \
  -H "Authorization: Bearer sss_pk_your_key_here"
```

```json Response theme={null}
{
  "version": 3,
  "verifyCode": "b7e2c4a1d9f0e8b6a5c3d2e1f0a9b8c7",
  "verifyUrl": "/v/room/b7e2c4a1d9f0e8b6a5c3d2e1f0a9b8c7",
  "manifestSha256": "9d377b10ce778c4938b3c7e2c63a229a33884810d7743fbe4b5f2b7657b706da",
  "prevManifestSha256": "5f2b7657b706da9d377b10ce778c4938b3c7e2c63a229a33884810d7743fbe4b",
  "sealedSha256": "4f9a1c2b3d4e5f60718293a4b5c6d7e8f90123456789abcdef0123456789abcd",
  "createdAt": "2026-07-13T18:03:11Z"
}
```

## Versions, not overwrites

Every call mints the **next version** — a dated snapshot, never a mutation of an earlier one. Sealing after two more documents complete gives you v2 alongside v1; both remain verifiable forever. This is deliberate: an evidence artifact that can be silently replaced is not evidence.

* Versions are numbered per room, starting at 1.
* Quota: 20 versions per room.
* The room's public view and `GET /api/rooms/{roomCode}` always point at the latest version; older versions stay reachable by their own verify codes.

## The canonical manifest

The manifest is JSON serialized canonically — sorted object keys, no insignificant whitespace, UTF-8, invariant culture, lowercase hex hashes — so the same facts always produce byte-identical output and therefore the same SHA-256. Determinism is the whole point: it is what makes the hash, and the chain built on it, meaningful.

The manifest has three parts:

```json Manifest structure (illustrative) theme={null}
{
  "coverage": {
    "covers": [
      "cryptographic hashes of sealed artifacts attached to this room at snapshot time",
      "envelope verify codes and custody-certificate hashes where they exist"
    ],
    "doesNotCover": [
      "payment state",
      "delivery confirmation (unless a delivered shipment hash exists)",
      "any document not attached to this room at snapshot time"
    ]
  },
  "documents": [
    {
      "custodyCertSha256": "…",
      "envelopeVerifyCode": "…",
      "label": "Seller deed package",
      "orderCode": "…",
      "originalSha256": "…",
      "sealedSha256": "…",
      "statusAtSnapshot": "Completed"
    }
  ],
  "passport": {
    "generatedAtUtc": "2026-07-13T18:03:11Z",
    "prevManifestSha256": "…",
    "reference": "TC-88412",
    "roomCode": "…",
    "roomName": "1428 Maple St - Refinance",
    "version": 3
  }
}
```

Two honesty rules shape the `documents` array:

* **Hash fields appear only when the artifact exists.** A document with no sealed artifact simply has no `sealedSha256` key — the manifest never pads absence with placeholders.
* **`statusAtSnapshot` is a labeled attestation, not evidence.** It records what our systems said at snapshot time. The hashes are independently verifiable; the status is our word, and the manifest says so.

The `coverage` block enumerates what the passport does and does not speak to. It is rendered verbatim on the public verify page — the artifact carries its own limits.

## The hash chain

Each version's manifest embeds `prevManifestSha256` — the SHA-256 of the previous version's manifest (null for v1). That forms a per-room chain:

```text Chain theme={null}
v1: manifestSha256 = H(manifest_1), prev = null
v2: manifestSha256 = H(manifest_2), manifest_2 contains prev = H(manifest_1)
v3: manifestSha256 = H(manifest_3), manifest_3 contains prev = H(manifest_2)
```

Rewriting any historical version would change its hash and break every later link. When you verify a passport, the API recomputes the chain on that request — it re-hashes the stored manifest and checks the previous link against the prior version's stored hash — and reports the result as `chainOk`. The verdict is never a stored flag; it is earned on every view.

## The sealed artifact

Alongside the manifest, each version produces a Closing Passport certificate PDF: the room header, the version and chain line, a per-document hash table, the coverage statement, and the manifest SHA-256. The PDF is sealed with the same Google Cloud KMS signature that seals first-party orders — the private key never leaves KMS — so it verifies in any standard PDF signature viewer on its own, offline, with no SignSealShip involvement.

## Verifying a passport

Every version has a public verification page:

```text Verify page theme={null}
https://signsealship.com/v/room/{verifyCode}
```

The page shows the SEALED badge, a manifest summary, the chain status, the coverage statement verbatim, and a download link for the sealed PDF. The same facts are available as JSON:

```bash Verify over the API theme={null}
curl https://signsealship.com/api/verify/room/{verifyCode}
```

```json Response theme={null}
{
  "manifest": { "...": "the full parsed manifest" },
  "manifestSha256": "9d377b10ce778c4938b3c7e2c63a229a33884810d7743fbe4b5f2b7657b706da",
  "sealedSha256": "4f9a1c2b3d4e5f60718293a4b5c6d7e8f90123456789abcdef0123456789abcd",
  "version": 3,
  "prevManifestSha256": "5f2b7657b706da9d377b10ce778c4938b3c7e2c63a229a33884810d7743fbe4b",
  "chainOk": true,
  "branding": null,
  "createdAt": "2026-07-13T18:03:11Z",
  "downloadUrl": "/api/verify/room/{verifyCode}/pdf"
}
```

The manifest is returned parsed **alongside** its hash so you can check it yourself:

<Steps>
  <Step title="Re-hash the manifest">
    Re-canonicalize the returned manifest (sorted keys, no whitespace, UTF-8) and SHA-256 it. It must equal `manifestSha256`.
  </Step>

  <Step title="Walk the chain">
    Fetch the prior version by its verify code and confirm its `manifestSha256` equals this version's `prevManifestSha256`.
  </Step>

  <Step title="Check the sealed PDF">
    Download the PDF from `downloadUrl`, confirm its SHA-256 equals `sealedSha256`, and open it in a PDF signature viewer to validate the KMS signature independently.
  </Step>

  <Step title="Cross-check document hashes">
    Any sealed document you hold can be hashed locally and compared against its `sealedSha256` entry in the manifest.
  </Step>
</Steps>

<Check>
  None of these steps require trusting SignSealShip. The artifact proves itself.
</Check>

## Honest coverage — what a passport does not say

A Closing Passport is strong evidence with stated limits, and the limits are part of the artifact:

* **Statuses are attestation.** `statusAtSnapshot` values are our records at snapshot time, explicitly labeled as not being independent evidence.
* **No payment claims.** The passport says nothing about whether anyone was paid.
* **No delivery claims** unless a delivered shipment's hash is actually on record.
* **Nothing about absent documents.** A document never attached to the room is simply outside the passport's world — the coverage statement says so.

<Note>
  The verify code is a bearer credential for the passport, like the room link is for the room. Unknown or malformed codes return an identical generic not-found response, so codes cannot be enumerated.
</Note>

## Related

<Columns cols={2}>
  <Card title="Passports API reference" icon="square-terminal" href="/api-reference/passports">
    Full request and response shapes for sealing and verifying Closing Passports.
  </Card>

  <Card title="Evidence model" icon="shield-check" href="/evidence-model">
    The locked vocabulary behind SEALED and RECORDED, and what each cryptographically means.
  </Card>
</Columns>
