Skip to main content
Your platform submits a finished, signed PDF. It comes back sealed with Google Cloud KMS, timestamped by independent authorities, and wrapped in a public verification URL — the same trustworthy artifact SignSealShip’s own notarize-and-ship orders produce. One endpoint, real evidence, nothing you can’t independently check.

What a passport holds

  • Tamper-evident seal — an asymmetric signature whose private key never leaves Google Cloud KMS: a CMS/PKCS#7 signature visible in any PDF reader’s signature panel, with /ByteRange tamper-evidence. Change one byte after sealing and every verifier can tell.
  • Independent time — a trusted-timestamp token from an independent RFC 3161 time-stamping authority over the sealed document’s SHA-256. An archivable attestation that the sealed bytes existed at that moment — not SignSealShip’s word for it.
  • Bitcoin anchor — the sealed hash is submitted to public OpenTimestamps calendars, producing a detached proof anyone can verify or upgrade with standard tooling. It is honestly reported as pending until a Bitcoin block confirms it — never a claim that hasn’t been earned.
  • Chain of custody — a 128-bit random verification code plus a custody record: the pre-seal document hash, the post-seal hash, and when it was sealed. Possession of the code (or the sealed file) is the authorization to see it.
  • Public verification — a URL anyone can check without a SignSealShip account and without trusting you. The artifact proves itself.

What it is not

  • A signing tool — you bring the already-executed document; SignSealShip seals and proves it.
  • A legal opinion — the evidence is cryptographic fact, not advice on your document’s legal sufficiency.
  • A place your customers’ data lives — passport rows hold hashes and a verify code, never document content or PII. The upload is never retained beyond producing the sealed artifact.

Seal a document

POST /api/passport/seal Requires your partner key. Send the executed PDF as a multipart form part named file, up to 35 MB. The bytes are checked for PDF magic bytes, streamed into memory (never to disk), and discarded after sealing. Rate limited at 12 requests per minute per IP.
file
file
required
The executed PDF, as the multipart part named file. Maximum 35 MB.
curl -X POST https://signsealship.com/api/passport/seal \
  -H "Authorization: Bearer sss_pk_your_key" \
  -F "file=@executed.pdf"
import { readFile } from "node:fs/promises";

const form = new FormData();
form.append(
  "file",
  new Blob([await readFile("executed.pdf")], { type: "application/pdf" }),
  "executed.pdf",
);

const res = await fetch("https://signsealship.com/api/passport/seal", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.SSS_PARTNER_KEY}` },
  body: form,
});
const passport = await res.json();
console.log(passport.verifyUrl);
import os
import requests

with open("executed.pdf", "rb") as f:
    res = requests.post(
        "https://signsealship.com/api/passport/seal",
        headers={"Authorization": f"Bearer {os.environ['SSS_PARTNER_KEY']}"},
        files={"file": ("executed.pdf", f, "application/pdf")},
    )
passport = res.json()
print(passport["verifyUrl"])
passportId
string
The passport’s id (UUID). Use it with GET /api/passport/{id}.
verifyCode
string
The 128-bit public verification capability code.
verifyUrl
string
Absolute public verification URL, https://signsealship.com/api/passport/verify/{verifyCode}.
docSha256
string
SHA-256 (hex) of the exact bytes you uploaded — the pre-seal hash.
sealedSha256
string
SHA-256 (hex) of the sealed PDF SignSealShip produced and stored.
status
string
"sealed" once the KMS seal is applied and stored.
timestamps
object
Independent timestamp evidence over the sealed hash. Either member is null when that authority could not be reached — the response never fakes evidence it didn’t gather.
200 OK
{
  "passportId": "0d5e2f6a-1b3c-4d7e-8f90-a1b2c3d4e5f6",
  "verifyCode": "abcdefghijklmnopqrstuvwxyz",
  "verifyUrl": "https://signsealship.com/api/passport/verify/abcdefghijklmnopqrstuvwxyz",
  "docSha256": "5f6e...1a2b",
  "sealedSha256": "8c9d...3e4f",
  "status": "sealed",
  "timestamps": {
    "rfc3161": {
      "authority": "https://timestamp.example",
      "timestampedAtUtc": "2026-07-12T18:30:12+00:00"
    },
    "openTimestamps": {
      "calendar": "https://calendar.example",
      "submittedAtUtc": "2026-07-12T18:30:13+00:00",
      "status": "pending"
    }
  }
}
Errors: 400 {"error": "Expected a multipart 'file' PDF part up to 35MB."} for a missing, oversized, or non-multipart upload, 400 {"error": "Uploaded bytes are not a PDF."} when the magic bytes don’t match, 401 for a bad key. A signed passport.sealed webhook fires on sealing if you have registered one — see webhooks.

Fetch a passport

GET /api/passport/{id} Requires your partner key. Partner isolation is enforced: a passport is visible only to the partner that created it.
id
string
required
The passport’s UUID from the seal response.
curl
curl https://signsealship.com/api/passport/{id} \
  -H "Authorization: Bearer sss_pk_your_key"
Returns the same fields as the seal response minus timestamps, plus createdAt:
200 OK
{
  "passportId": "0d5e2f6a-1b3c-4d7e-8f90-a1b2c3d4e5f6",
  "verifyCode": "abcdefghijklmnopqrstuvwxyz",
  "verifyUrl": "https://signsealship.com/api/passport/verify/abcdefghijklmnopqrstuvwxyz",
  "docSha256": "5f6e...1a2b",
  "sealedSha256": "8c9d...3e4f",
  "status": "sealed",
  "createdAt": "2026-07-12T18:30:11+00:00"
}
Unknown ids — including another partner’s — return 404 {"error": "No such passport."}.

Verify a passport (public)

GET /api/passport/verify/{code} Public and self-contained: possession of the code is the authorization. Never exposes the partner identity or any other passport. Rate limited at 12 requests per minute per IP. Malformed and unknown codes return the identical generic {"verdict": "unknown"} 404.
code
string
required
The 26-character verify code.
curl
curl https://signsealship.com/api/passport/verify/{code}
verdict
string
"verified" when the code resolves to a sealed passport.
verifyCode
string
Echo of the code.
sealedSha256
string
SHA-256 (hex) of the sealed PDF — compare against a file in hand.
docSha256
string
SHA-256 (hex) of the original uploaded bytes.
sealedAtUtc
string
When the passport was sealed.
source
string
"proof_passport_api" — this record came through the partner API.
certificateAvailable
boolean
Whether the sealed artifact is archived and downloadable below.

Download the sealed document (public)

GET /api/passport/verify/{code}/document Streams the byte-identical sealed PDF as application/pdf. Any holder of the code can fetch it; the file also verifies on its own in any PDF reader’s signature panel — no SignSealShip involvement required. Unknown codes and missing artifacts return the generic {"verdict": "unknown"} 404.
curl
curl -L -o sealed.pdf \
  https://signsealship.com/api/passport/verify/{code}/document

Register a passport webhook

POST /api/passport/webhooks Requires your partner key. Registers an https endpoint for passport.sealed events; the signing secret is returned exactly once — only its hash is stored. Full payload and signature verification details are on the webhooks page.
url
string
required
Your https webhook endpoint.
curl
curl -X POST https://signsealship.com/api/passport/webhooks \
  -H "Authorization: Bearer sss_pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/hooks/signsealship" }'
200 OK
{
  "webhookId": "7a1b2c3d-4e5f-6071-8293-a4b5c6d7e8f9",
  "url": "https://example.com/hooks/signsealship",
  "signingSecret": "sss_whsec_shown_exactly_once",
  "signatureHeader": "SignSealShip-Signature",
  "verification": "HMAC-SHA256 over \"{t}.{rawBody}\" using key = lowercase_hex(sha256(signingSecret)); compare against the v1= value and reject timestamps older than 5 minutes."
}
Store signingSecret immediately — it is never shown again. SignSealShip keeps only its SHA-256 hash.