Your PDF never leaves your systems: delegated sealing in SDK v0.3.0
There has always been an asymmetry in how sigill.ai handles your documents. Timestamping: hash-only, your file stays with you. Universal (CAdES) and JSON (JAdES) seals: hash-only, your file stays with you. But an embedded PDF seal — the kind that opens and validates in any PDF reader — meant uploading the PDF, because assembling a PAdES signature requires modifying the document itself.
As of SDK v0.3.0, that asymmetry is gone.
from sigill_sdk import SigillClient
client = SigillClient(api_key="sigill_...")
pdf = open("contract.pdf", "rb").read()
result = client.seal_pades(pdf, certificate_id=CERT_ID, qualified=True)
open("contract_sealed.pdf", "wb").write(result.sealed_pdf)
print(result.format) # "pades-b-lta"
That call produces a sealed PDF with the seal embedded — the full archival ladder: signature, qualified timestamp, revocation evidence, document timestamp. And the only thing that crossed the wire to sigill.ai was a 32-byte digest.
How it works
A PAdES seal lives inside the PDF: the document gains a signature field with a byte range declaring exactly what is covered, and a cryptographic container (CMS) embedded in a reserved slot. Traditionally, whoever builds that structure needs the whole document — hence the upload.
Delegated sealing splits the work along a cleaner line:
- Your machine (the SDK) appends the signature structure to the PDF locally, computes the digest of the declared byte ranges, and sends the digest — nothing else.
- Sigill signs the digest with the certificate's key, which never leaves a hardware-backed KMS, obtains an RFC 3161 timestamp from an independent authority, and returns the signature container plus the certificate-chain and revocation data.
- Your machine embeds the container, writes the long-term validation store, and adds the archival document timestamp — again sending only a digest to be timestamped.
The result is byte-for-byte the same kind of artifact the upload path produces: a standard PAdES-B-LTA PDF, verifiable by anyone, forever, with no Sigill software. What changed is only where the document bytes live during the process: with you, the whole time.
A guarantee, not a setting
We wanted this to be stronger than a privacy preference, so it's enforced in the SDK's structure:
- Hash-only is the default and the only automatic behaviour. If the SDK encounters a PDF its local parser can't handle, it throws — before any network call. It does not quietly fall back to uploading.
- The upload fallback exists, but you must switch it on (
allow_upload_fallback=True/AllowUploadFallback = true). Under a strict data-residency policy, you simply never set it, and the SDK is physically incapable of transmitting your document. - The code that touches your PDF is open source. Both SDKs are Apache-2.0 on GitHub (sigill-python, sigill-dotnet), with no third-party crypto or PDF dependencies. You don't have to take our word for what leaves your machine — you can read it, or watch it on the wire.
And on our side of the wire, there is nothing to leak: sigill.ai stores the digest and operation metadata, and the sealed PDF exists only on your machine. We don't offer document storage — not as a disabled default, but at all.
Some honesty about what's new here
Signing a hash instead of a document is not our invention — it's an established pattern in the digital-signature world, and standards work like the Cloud Signature Consortium API describes it well. If you have a PKI team and a PDF library budget, you could always build this flow yourself.
What we haven't seen offered is the whole flow, done for you, in the open: the local PDF assembly, the long-term validation store, the archival timestamp — through the full B-LTA level — in one SDK call, with no licence-encumbered PDF library underneath and the privacy guarantee enforced by default rather than left as an exercise. Most hash-signing offerings hand you an endpoint and wish you luck with the client half. We think the private path should be the easy path, so we built the client half and gave it away.
Trust, but verify — so we had it verified
A privacy claim about sealing is only useful if the seals hold up. Before this release, we ran SDK-produced seals — sealed on one machine, with only digests transmitted, qualified timestamps throughout — through the EU Commission's DSS reference validator, the conformance tool of the ETSI standards world. Verdict: PAdES-BASELINE-LTA, TOTAL_PASSED, with both the signature timestamp and the archival timestamp recognised as qualified against the EU trust lists. Independent open-source validators (pyHanko, poppler) agree.
The same output, in other words, as our server-side sealing has always produced — which is the point. You give up nothing by keeping your documents.
Every format, one privacy model
With v0.3.0, the platform's privacy posture is finally symmetrical:
| Operation | What crosses the wire |
|---|---|
| Timestamping | a digest |
| CAdES seal (any file) | a digest |
| JAdES seal (JSON) | a digest |
| PAdES seal (embedded in PDF) | a digest |
The upload path still exists — it powers the web app, where dragging a file into a browser is the right experience — but for integrations, the hash-only path is now the recommended default across the board.
pip install --upgrade sigill-sdk · dotnet add package Sigill.Sdk — and the delegated flow is documented in the API reference if you'd rather integrate it directly.