import { Callout } from "zudoku/ui/Callout";

# Pdf - Sign

Codeunit `5523677` `bdev.Pdf - Sign` signs a PDF document digitally. A signature proves who issued the document and that nobody changed it afterwards - which is what makes a PDF invoice acceptable where a wet signature used to be required.

<Callout type="info" title="Version">
`bdev.Pdf - Sign` has been introduced with 365 business PDF **20.6**. Before that, signing from AL was only available on the obsolete [bdev.Pdf API](pdf-api.mdx), although its obsoletion message already named `Pdf - Sign` as the replacement.
</Callout>

```pascal
    pdfSign: Codeunit "bdev.Pdf - Sign";
```

There are two ways to state which certificate to sign with:

- **a PDF Signing Configuration**, which holds the certificate and its PIN inside Business Central. The certificate is maintained once, by whoever is allowed to, and your code never touches it.
- **a certificate of your own**, passed as a `Temp Blob` together with its PIN.

Prefer the configuration. It keeps the certificate out of your code and out of your extension's data, and it is the same configuration a report selection uses, so a document you sign yourself carries the same signature as one the app signed during printing.

## SignDocument(Codeunit, Record)

Signs a document with the certificate of a PDF Signing Configuration.

```pascal
    procedure SignDocument(var document: Codeunit "Temp Blob"; pdfSigningConfig: Record "bdev.Pdf Signing Config.")
```

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `document` | Codeunit "Temp Blob" | The PDF document. It is replaced by the signed document. |
| `pdfSigningConfig` | Record "bdev.Pdf Signing Config." | The signing configuration holding the certificate. |

### Example

```pascal
    procedure SignContract(var document: Codeunit "Temp Blob")
    var
        pdfSigningConfig: Record "bdev.Pdf Signing Config.";
        mySetup: Record "My Setup";
        pdfSign: Codeunit "bdev.Pdf - Sign";
    begin
        mySetup.Get();
        mySetup.TestField("Signing Configuration Code");
        pdfSigningConfig.Get(mySetup."Signing Configuration Code");

        pdfSign.SignDocument(document, pdfSigningConfig);
    end;
```

## SignDocument(Codeunit, Code)

Signs a document with the certificate of the PDF Signing Configuration with the given code.

```pascal
    procedure SignDocument(var document: Codeunit "Temp Blob"; pdfSigningConfigCode: Code[20])
```

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `document` | Codeunit "Temp Blob" | The PDF document. It is replaced by the signed document. |
| `pdfSigningConfigCode` | Code[20] | Code of the signing configuration. |

<Callout type="caution" title="An unknown configuration leaves the document unsigned">
When no signing configuration exists for the code, the document is returned unchanged and no error is raised - the same behavior the app shows during report processing, where a missing configuration must not break the print. Where the signature is the point of the operation, test it with [SigningConfigExists](#signingconfigexistscode) first.
</Callout>

## SignDocument(Codeunit, Codeunit, Text)

Signs a document with a certificate of your own.

```pascal
    procedure SignDocument(var document: Codeunit "Temp Blob"; certificate: Codeunit "Temp Blob"; certificatePin: Text)
```

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `document` | Codeunit "Temp Blob" | The PDF document. It is replaced by the signed document. |
| `certificate` | Codeunit "Temp Blob" | The certificate file. |
| `certificatePin` | Text | The PIN of the certificate. |

```pascal
    procedure SignWithOwnCertificate(var document: Codeunit "Temp Blob")
    var
        mySetup: Record "My Setup";
        pdfSign: Codeunit "bdev.Pdf - Sign";
        certificate: Codeunit "Temp Blob";
    begin
        mySetup.Get();

        certificate.FromRecord(mySetup, mySetup.FieldNo("Certificate File"));

        pdfSign.SignDocument(document, certificate, mySetup."Certificate PIN");
    end;
```

<Callout type="caution" title="The certificate leaves Business Central">
The certificate and its PIN are sent to the PDF service to perform the signature. That is true for both ways of signing, but a certificate stored in a signing configuration at least never passes through your extension. Keep a certificate of your own out of ordinary fields - and out of your telemetry.
</Callout>

## SigningConfigExists(Code)

States whether a PDF Signing Configuration exists for the code.

```pascal
    procedure SigningConfigExists(pdfSigningConfigCode: Code[20]): Boolean
```

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `pdfSigningConfigCode` | Code[20] | Code of the signing configuration. |

**Returns** `true` when the configuration exists.

Use it to turn the silent no-op above into an error of your own, with a message that names your setup field rather than ours:

```pascal
    if (not pdfSign.SigningConfigExists(mySetup."Signing Configuration Code")) then
        Error(SigningConfigurationMissingErr, mySetup."Signing Configuration Code", mySetup.FieldCaption("Signing Configuration Code"));
```

## Signing during report processing

You do not need this codeunit to sign a printed report: a signing configuration on the report selection does that. Two properties of the report path are worth knowing when you compare the two.

- The app does **not** sign when the print intent is `Print`. A signature on a document that goes to a printer serves no purpose, and the app skips it. This codeunit signs whatever you hand it.
- The report path signs after stationery, concatenation and document attachments have been applied, so that the signature covers the finished document. When you sign yourself, sign last for the same reason - any change after the signature invalidates it.

## See also

- [365 business PDF - Overview](readme.mdx)
- [Pdf API (obsolete)](pdf-api.mdx)
- [Extensibility Events](extensibility-events.mdx)
- [Documentation - Signing](../../en-us/365-business-pdf/signing.md)
