Evidence and certificates
Somebody disputing a signature three years from now does not get a database. They get a PDF and a claim.
Watch it done: What the evidence pack proves (1:42) · Every agreement, on one trail (1:09)
When a document completes, a certificate is issued: the document and its hash, every signer with the method and value of their signature, and the whole event chain with the address, the browser, the language and the device at each step. It is frozen at issue and hashed.
Where the address was, the certificate prints as Network region (approximate): what the network edge in front of us resolved it to, and only when the request provably crossed that edge. A caller who reaches the API directly cannot supply it, so a signer cannot choose the place printed on their own certificate; nothing is looked up from anybody else either.
Frozen, and checked against the live record
Freezing sounds like the wrong instinct — a derived value that has drifted is the one somebody quotes. But a certificate is evidence, and evidence says what was true at a moment. Deriving it later means the document somebody holds and the document we render can differ with nothing to compare.
So both properties are kept. The payload is frozen and hashed at issue, and verification re-derives it from the live record and reports any divergence:
{
"certificate_found": true,
"document_matches": true,
"still_matches_record": false,
"divergence": "The document text has changed since this certificate was issued."
}
A divergence is a finding, not a correction. We report it and change nothing. A verification service that quietly re-derived would be unable to answer the one question it exists for.
What the signer was told, and how the link reached them
A certificate does not only say that consent was given. For each
signer it carries the consent disclosure in the words that were on the page,
with its SHA-256 and a version reference (consent/1, plus the
template's own consent wording when the business wrote one), the address and
browser the agreement came from, and the statement that stood above the
signature, hashed and versioned the same way. What the person agreed to is on
the record, not reconstructed from a later copy of the page.
Each signer also carries an assurance level: what the signature proves about who was at the keyboard. None of these is an identity check, and the printed certificate says so in each case.
| Level | What it proves |
|---|---|
email_link | A link we emailed to this address was used: control of the inbox. |
sms_link | A link we texted to this number was used: control of the phone. |
email_otp / sms_otp | As above, and a one-time code sent to the same address or number was entered before consent: control of that inbox or phone at the moment of signing, not only when the link arrived. |
in_person | The signing was started by a tablet you paired, using that tablet's own credential: our record of which device opened it, not anything the signer's browser said. |
link | A link handed over some other way — a public form, a QR code, your own application — was used: possession of the link. Also what a signature says when the link used was one shown at the gate or put in a frame after an email went out: an inbox proves nothing about who scanned a code. |
external_application | The business’s own application, whose key it registered, vouched that this person (by the application’s id for them) signed in to it and approved this exact text. SignSealer checked the application’s signed approval, not the person: how they signed in, and the address and device the application gave, are printed as the application’s statements. |
party_link | When everybody in a booking's party signs: a link the person who booked was given to hand over — to somebody they added with no email address, or a number that has not agreed to your texts — was used. Possession of the link, which the person who booked also had; the signature's event names them (handed_out_by), and the printed certificate says the link was handed out by them. Anybody in the party with an email address is sent their own link, and the person who booked never sees it. |
The one-time code is a choice each business makes under Settings ("Ask
signers for a code"). It applies to signers a link was delivered to; somebody
signing at the counter is not asked. It comes with the membership: on Free no
code is asked, and a choice made on the membership is kept for when it starts
again. Over the API the step is
POST /v1/sign/{token}/code and /verify. Certificates
issued before these fields existed carry the times and addresses they always
did, and nothing invented.
ID Evidence
A business may ask the people it sends a link to for a photograph of a
government-issued ID, and optionally of themselves, after consent and
before the signature (Settings → "Ask signers for ID evidence"). The
image is resized on the way in, kept encrypted under a key derived for
that business, shown only to its team from the document's page (each
look is audited), and dropped after thirty days or with a redaction. The
certificate carries each capture by kind, SHA-256, type, size, time and
the words the person was told, with "verified": false beside
it and "not verified against anything" in print: it is evidence that
somebody held that ID up when they signed, not a verification of who they
are, and a certificate issued before the image is dropped still matches
its record after. At the counter the tablet offers the same photo, and the
customer may take it or skip it. ID Evidence comes with the membership: on Free
nobody is asked, and a choice made on the membership is kept for when it starts
again.
The sealed PDF
GET /v1/documents/{id}/pdf returns the certificate as a PDF
sealed with a detached digital signature (PAdES) and an RFC 3161 timestamp — over
the signature, not over the document, which is what lets a reader tell when
the seal was applied rather than when the file was made.
It is sealed once, when the document completes, and kept. Every download — from the API, the dashboard, the signer's own page or the completion email — is that file, byte for byte, so two copies of one agreement are the same copy, and a later change to the business's logo or to how we draw a certificate does not reach one already made. Its SHA-256 is recorded, and is what public verification compares a file with (below). A document that completed before copies were kept is sealed no later than its first download, and that copy is kept the same way.
The seal is self-issued, and the PDF's last page says so. It proves the file has not changed since it was sealed: alter a byte and a reader reports the signature as broken. It does not prove who produced the file — no certificate authority stands behind it, and a reader will show the sealer's identity as unverified. Identity is established by the verification code and the record it points to, not by the seal. If a counterparty requires a seal that validates as trusted in Adobe Reader (an AATL certificate), ask; it is not something SignSealer sells today.
The photographs
When a document asked for photographs as answers (a field of kind
photo), the sealed PDF prints them on pages after the
certificate: each with its question, who took it and when, and its SHA-256,
under the same seal as the rest of the file. A JPEG is embedded exactly as it
was kept, so extracting it from the PDF and hashing it gives the fingerprint on
the certificate; a PNG is redrawn into the PDF's own image format and says so.
The images are decrypted only while the file is made. A business can leave them
out for a template (photos_in_copy: false, or Templates in the
dashboard); the certificate carries every hash either way, and a redacted
document prints none. ID evidence is not among them: it is dropped after thirty
days and stays off the signed copy.
The evidence bundle
GET /v1/documents/{id}/bundle returns the same sealed PDF with
the evidence package printed after the audit trail: every message sent about
the document and whether it arrived, every webhook delivered to your systems,
what an AI review flagged before it was sent (when the business ran one, and
that it was sent anyway), and the record's state when the file was made —
voided, redacted, still matching. The package's SHA-256 is on the last page, so the JSON and the PDF
can be tied together if both are produced. One file, sealed as one, for an
insurer, an adjuster or a court; the JSON stays the machine-readable form and
is available before the document completes, when the bundle is not.
Public verification
Every certificate carries a sixteen-character code, printable and typable:
no I, L, O or U, because those are the four that get mistyped as 1, 1, 0 and V.
Anybody holding the document can check the certificate without an account:
the code alone confirms it exists, who issued it, when it completed, how many
signed and that the record still matches. Add the SHA-256 of the sealed PDF you
were sent — shasum -a 256 the-file.pdf — and, when it is the file we
issued, the page says so and names the signers and shows the trail; the SHA-256
of the document's text is accepted too, as it always was. Over the API,
GET /v1/verify/{code}?sha256= answers copy_matches when
it was the file and document_matches for either. A copy handed out
before copies were kept was never recorded, so its SHA-256 cannot match; its
code still verifies. Email addresses are never on the public page; they are in
the sealed PDF and your evidence package.
Ready to build? An API key takes a minute in the portal, and the free plan covers the first 10 agreements a month.
Get an API key