Short answer: Archive a monthly marketplace report only after checking its PDF digital signature against the exact bytes you will retain. A valid signature can establish that a particular signing key covered a particular revision and that the covered bytes have not changed. It cannot establish that a seller read the report, agreed to a contract, or authorized that key to act for them. Keep the delivery and acceptance record separate.
Those are different claims.
For a report attached to a contract-signing workflow, this distinction decides what gets shipped. Generate the PDF, sign the intended revision, verify the resulting artifact, then archive that artifact alongside evidence of who accepted what and when. A signature on a later revision is not automatically evidence about an earlier one.
What does a PDF digital signature prove about the archived report?
PDF signatures use a byte range to identify the signed portions of the file while excluding the signature value itself. A verifier needs to validate the cryptographic signature, inspect the covered revision, build an acceptable certificate path under an explicit trust policy, and report any subsequent changes. A visible signature appearance on a page is not the same check. Nor is an image of a handwritten name.
The signed byte range proves integrity only within that range; it doesn't explain why the report was generated or who approved the figures. If the seller disputes an adjustment, you need the source ledger and the report-generation inputs to explain the amount. If they dispute acceptance of new terms, you need the acceptance event. A digest of the final PDF binds these trails to the artifact, but a digest alone doesn't recreate a missing ledger or a missing click record. This is why a single green signature indicator is a poor audit schema: it compresses at least three questions, about bytes, identity, and intent, into one bit. Keep those questions separate in both the database and the review screen.
This matters when a monthly report is updated after signing. A PDF can contain incremental updates: new bytes may be appended without replacing the earlier signed revision. The earlier signature can still validate for that revision while the current displayed document contains later material. Ask the verifier for both results: was the signed revision intact, and is the current document the revision the signer intended to sign? Treat an unexpected later update as a review event, even if an interface shows a reassuring check mark.
Certificate identity needs its own decision. A mathematically valid signature says a key produced it. The certificate and your trust policy determine what identity, if any, you can associate with that key. Neither one establishes a person's authority to accept a marketplace contract. That authority comes from account controls and the acceptance workflow, with timestamps and evidence that can be reviewed independently.
Identity isn't authority.
Gate the archive on explicit evidence
The data flow is small: render one month's report from a fixed input snapshot, sign the final PDF, run a PDF-aware verifier, and record its result before writing the signed artifact to durable storage. The archive record should bind the report identifier and month to a digest of the actual stored bytes. Store the verifier's interpretation separately from the artifact; rerun verification when your trust policy changes.
The following TypeScript implements the archive decision, not PDF cryptography. verifyPdf is an injected, PDF-aware verifier that must check byte ranges, certificate policy, and the current revision. putImmutable is an injected storage operation; the example deliberately leaves both adapters to the deployment that owns them. The gate can be exercised with real adapters or a test double without treating a filename or a rendered signature image as proof.
import { createHash } from "node:crypto";
type Verification = {
signatureValid: boolean;
trustedSigner: boolean;
signedRevisionIsCurrent: boolean;
signerIdentity: string;
};
type Dependencies = {
verifyPdf: (pdf: Uint8Array) => Promise<Verification>;
putImmutable: (key: string, pdf: Uint8Array) => Promise<void>;
};
async function archiveReport(
reportId: string,
month: string,
signedPdf: Uint8Array,
deps: Dependencies,
) {
const result = await deps.verifyPdf(signedPdf);
if (!result.signatureValid || !result.trustedSigner ||
!result.signedRevisionIsCurrent) {
throw new Error("Report signature needs review before archival");
}
const sha256 = createHash("sha256").update(signedPdf).digest("hex");
const key = `${reportId}/${month}/${sha256}.pdf`;
await deps.putImmutable(key, signedPdf);
return { reportId, month, key, sha256, signerIdentity: result.signerIdentity };
}
const pdf = new TextEncoder().encode("test fixture, not a PDF");
archiveReport("market-42", "2026-08", pdf, {
verifyPdf: async () => ({
signatureValid: true,
trustedSigner: true,
signedRevisionIsCurrent: true,
signerIdentity: "fixture signer",
}),
putImmutable: async () => {},
}).then(console.log);
The fixture only tests the orchestration. It does not test a real signature. In production, reject incomplete verifier output instead of mapping unknown states to true. Keep the archived bytes available for independent revalidation; a stored Boolean is a decision made under an earlier trust policy, not permanent cryptographic evidence.
The limitation of this gate is deliberate: it cannot decide consent, and it cannot replace a PDF-aware signature verifier. Where there is no reliable signing identity or certificate trust policy, don't label the report as identity-verified; archive it as an unsigned artifact with a digest and keep the acceptance evidence separate. That gives up cryptographic signer attribution without pretending to have it.
Where does consent evidence belong?
Suppose the report shows payouts and adjustments for a seller, then the seller accepts revised terms. The report signature helps pin down the document version. The acceptance record must link an authenticated actor, the exact terms version, the action taken, and its time to that version. An email delivery event, a page view, and an affirmative acceptance are different events. Do not collapse them into a single signed: true field.
There is another timing trap. A signing timestamp asserted by the signer's local clock is not independent evidence that the signature existed at that time. If time matters for the retention or dispute policy, define which trusted timestamp evidence is required and preserve the validation material needed to check it later. A PDF signature without that evidence may still protect integrity while leaving the timing question open.
Time needs evidence too.
The exact legal effect of an electronic signature depends on the applicable jurisdiction and process. The engineering system should preserve inspectable evidence rather than infer legal consent from cryptography alone. For a marketplace, that also means keeping report access controls separate from signing rights: the party permitted to download a PDF is not necessarily the party empowered to accept contract terms.
Operating the pipeline without losing the trail
Make rendering repeatable from a versioned input snapshot, but archive the signed output as its own immutable object. A retry must not silently replace the previously referenced PDF with a newly rendered one under the same identifier. Use a content digest to detect mismatches; use a durable record to associate that digest with the month and seller. Record verification failures with a reason and correlation ID, without putting private report contents into logs.
Test three distinct cases before deployment: a modified byte in the signed range, an appended revision that changes the current document, and a valid signature from a signer outside your accepted trust policy. Add a retry test where storage succeeds but the archive record write fails. The repair path should reconcile by digest, so a second attempt cannot create two apparently authoritative monthly reports. These cases tell you more than a screenshot of a green validation icon.
Signing and verification add latency and operational work; do them at the report-finalization boundary, not on every download. The recurring costs are storage, validation material, and investigation time when trust status is ambiguous. A cheaper rendering path does little good if it leaves the archived revision or the consent event untraceable.
Before each monthly run, confirm the report period and input snapshot, lock the final PDF revision, check the signing identity against policy, validate the signed bytes and later revisions, then write the artifact and its digest-linked record. Review failures rather than filing them as successful archives. Keep acceptance events in their own audit trail and link them to the exact retained revision. That is the operational boundary: PDF integrity on one side, human authorization on the other.
Top comments (0)