Docs

Docs / Guides / Evidence and certificates

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.

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.

LevelWhat it proves
email_linkA link we emailed to this address was used: control of the inbox.
sms_linkA link we texted to this number was used: control of the phone.
email_otp / sms_otpAs 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_personThe 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.
linkA 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_applicationThe 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_linkWhen 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