> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formepdf.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Digital Certification

> Apply PKCS#7 digital certifications to PDFs — at render time or standalone — for contracts, compliance, and legal documents.

Digital certifications cryptographically prove that a PDF has not been tampered with since certification and identify the certifier. They are required or expected for contracts, regulatory filings, legal documents, and compliance workflows. Forme supports PKCS#7 detached signatures using X.509 certificates, implemented in pure Rust with no external signing service.

<Note>In 0.9.0, `signature` was renamed to `certification` and `signPdf()` to `certifyPdf()` to better reflect the cryptographic nature of the operation (PKCS#7 certification vs e-signatures). The old names still work as deprecated aliases. See the [migration guide](/guides/migrating-to-0-9).</Note>

***

## Certifying at Render Time

Pass the `certification` prop on the Document component to certify the PDF during rendering. You need an X.509 certificate and its corresponding RSA private key in PEM format.

```tsx theme={null}
import { readFileSync } from 'fs';
import { Document, Page, Text } from '@formepdf/react';
import { renderDocument } from '@formepdf/core';

const certificatePem = readFileSync('./cert.pem', 'utf-8');
const privateKeyPem = readFileSync('./key.pem', 'utf-8');

const pdfBytes = await renderDocument(
  <Document
    title="Service Agreement"
    certification={{
      certificatePem,
      privateKeyPem,
      reason: 'Approved',
      location: 'San Francisco, CA',
      contact: 'legal@acme.com',
    }}
  >
    <Page size="Letter" margin={54}>
      <Text style={{ fontSize: 24, fontWeight: 700 }}>Service Agreement</Text>
      <Text style={{ fontSize: 10, lineHeight: 1.6, marginTop: 12 }}>
        This agreement is entered into as of March 29, 2026...
      </Text>
    </Page>
  </Document>
);
```

### Certification Props

| Prop             | Type     | Required | Description                                                                          |
| ---------------- | -------- | -------- | ------------------------------------------------------------------------------------ |
| `certificatePem` | `string` | Yes      | X.509 certificate in PEM format.                                                     |
| `privateKeyPem`  | `string` | Yes      | RSA private key in PEM format (PKCS#8).                                              |
| `reason`         | `string` | No       | Reason for certification (e.g., "Approved", "Reviewed"). Shown in signature details. |
| `location`       | `string` | No       | Certification location (e.g., "San Francisco, CA").                                  |
| `contact`        | `string` | No       | Certifier contact information (e.g., email address).                                 |

<Note>The `signature` prop is still accepted as a deprecated alias for `certification`.</Note>

***

## Standalone Certification via `certifyPdf()`

Use `certifyPdf()` to certify an existing PDF without re-rendering it:

```tsx theme={null}
import { certifyPdf } from '@formepdf/core';
import { readFileSync, writeFileSync } from 'fs';

const pdfBytes = readFileSync('contract.pdf');
const certificatePem = readFileSync('./cert.pem', 'utf-8');
const privateKeyPem = readFileSync('./key.pem', 'utf-8');

const certifiedPdf = await certifyPdf(pdfBytes, {
  certificatePem,
  privateKeyPem,
  reason: 'Approved',
  location: 'San Francisco, CA',
  contact: 'legal@acme.com',
});

writeFileSync('certified-contract.pdf', certifiedPdf);
```

<Note>`signPdf()` is still exported as a deprecated alias for `certifyPdf()`.</Note>

***

## Certification via the Hosted API

Use `POST /v1/certify` to certify a PDF via the hosted API. You can pass inline PEM data or reference a [saved certificate](/concepts/credentials) by ID.

See the [Certify API reference](/api-reference/certify) for full details and code examples.

***

## Visible vs Invisible Signatures

By default, Forme applies an invisible signature. The signature is embedded in the PDF's metadata and can be verified in the signature panel of any PDF viewer, but nothing appears on the page itself.

To add a visible signature annotation, set `visible: true` and specify the position and size:

```tsx theme={null}
<Document
  certification={{
    certificatePem,
    privateKeyPem,
    reason: 'Approved',
    visible: true,
    x: 350,
    y: 700,
    width: 200,
    height: 50,
  }}
>
  {/* ... */}
</Document>
```

The visible annotation displays the signer's common name (from the certificate) at the specified position. Coordinates are in points from the bottom-left corner of the page.

| Prop      | Type      | Default | Description                                     |
| --------- | --------- | ------- | ----------------------------------------------- |
| `visible` | `boolean` | `false` | Whether to show a visible signature annotation. |
| `x`       | `number`  | `0`     | X coordinate in points from the left edge.      |
| `y`       | `number`  | `0`     | Y coordinate in points from the bottom edge.    |
| `width`   | `number`  | `200`   | Width of the visible signature in points.       |
| `height`  | `number`  | `50`    | Height of the visible signature in points.      |

<Note>Visible signature appearance text uses the built-in Helvetica font, limited to Latin characters. This is a PDF specification constraint on form field appearances.</Note>

***

## Known Limitations

* **RSA keys only.** Only RSA private keys are supported. ECDSA, Ed25519, and other key types are not supported. If you pass a non-RSA key, you will get a clear error message.
* **Leaf certificate only.** Only the signing certificate is embedded in the signature. Intermediate CA certificates are not included. PDF viewers may show "unknown signer" if they cannot build the full chain to a trusted root.
* **No timestamp authority (TSA).** Signatures do not include a trusted timestamp from a TSA server. The signing date is set from the server clock but is not cryptographically verified by a third party.
* **No Long-Term Validation (LTV).** CRL and OCSP responses are not embedded. Signature validity cannot be verified after the signing certificate expires.
* **One signature per render.** Each render operation applies a single signature. To apply multiple signatures (e.g., co-signers), certify sequentially using the `/v1/certify` endpoint.
* **Self-signed certificates show "unknown signer" in Acrobat.** This is expected. Acrobat only trusts certificates from its trusted root store. Self-signed certs are fine for testing and internal workflows.
* **Helvetica only in signature appearance text.** Visible signature annotations use the PDF built-in Helvetica font. Custom fonts are not supported in signature form field appearances.

***

## Related

* [Certify API](/api-reference/certify) — hosted API endpoint reference
* [Credentials & Certificates](/concepts/credentials) — generating, uploading, and managing certificates
* [Migrating to 0.9.0](/guides/migrating-to-0-9) — sign → certify rename details
