Server API for Digital Signatures

PSPDFKit Server supports reading and applying digital signatures to PDF documents.

A digital signature is an electronic fingerprint uniquely identifying the signing person. A digital signature on a PDF document is both reliable proof of the document’s origin and protection against modification by third parties.

For a general overview, please consult our guide on how to add a digital signature.

PSPDFKit Server exposes a few endpoints for applying and reading digital signatures, both for documents and for individual Instant layers:

Signing a Document

To sign a document, PSPDFKit Server requires you to set up a companion signing service and set the SIGNING_SERVICE_URL environment variable. Please also check the configuration guide for other instance-wide options you can change to customize the digital signature metadata.

Request

To sign a document, you can use the /api/documents/:document_id/sign endpoint, optionally passing a JSON request body containing the signing options:

POST /api/documents/:document_id/sign
Content-Type: application/json
Authorization: Token token="<secret token>"

{
  "signingToken": "my-signing-token"
}
$ curl -XPOST http://localhost:5000/api/documents/my-document/sign \
   -H "ContentType: application/json" \
   -H "Authorization: Token token=<secret token>" \
   -d '{"signingToken": "my-signing-token"}'

Response

In the case of success, PSPDFKit Server will respond with the status 200 and the JSON body containing information about the newly generated signature:

{
  "data": {
    "signature": {
      "certificateChainValidationStatus": "ok_but_self_signed",
      "creationDate": "2020-01-17T10:01:53Z",
      "documentIntegrityStatus": "ok",
      "documentModifiedSinceSignature": false,
      "isExpired": false,
      "isSelfSigned": true,
      "isTrusted": false,
      "signatureFormFQN": "Signature-61b574ae-8057-45f1-91a3-59f08b88120d",
      "signatureValidationStatus": "warning",
      "type": "pspdfkit/signature-info",
      "validFrom": "2019-11-06T12:44:04Z",
      "validUntil": "2020-11-05T12:44:04Z"
    }
  }
}

In the case of error, PSPDFKit Server will return:

  • A 400 status code when either the request is malformed or the signing server responds with a status code in the 4xx range.

  • A 500 status code when the signing server responds with a status code in the 3xx or 5xx error range.

Signing a Layer

You can apply a signature to a specific Instant layer. This lets you maintain independent versions of the same document with separate signatures. For example, if you’re working on a contract, you can maintain two layers: one for the original document, and one for a copy that will be digitally signed.

Request

You can sign an Instant layer using the parent document ID and the layer name. If you use a layer name that maps to a non-existing layer, it will be copied automatically from the document base layer and then signed:

POST /api/documents/:document_id/layers/my-layer/sign
Content-Type: application/json
Authorization: Token token="<secret token>"

{
  "signingToken": "my-signing-token"
}
$ curl -XPOST http://localhost:5000/api/documents/my-document/layers/my-layer/sign \
   -H "ContentType: application/json" \
   -H "Authorization: Token token=<secret token>" \
   -d '{"signingToken": "my-signing-token"}'

Response

In the case of success, PSPDFKit Server will respond with the status 200 and the JSON body containing information about the newly generated signature:

{
  "data": {
    "signature": {
      "certificateChainValidationStatus": "ok_but_self_signed",
      "creationDate": "2020-01-17T10:01:53Z",
      "documentIntegrityStatus": "ok",
      "documentModifiedSinceSignature": false,
      "isExpired": false,
      "isSelfSigned": true,
      "isTrusted": false,
      "signatureFormFQN": "Signature-61b574ae-8057-45f1-91a3-59f08b88120d",
      "signatureValidationStatus": "warning",
      "type": "pspdfkit/signature-info",
      "validFrom": "2019-11-06T12:44:04Z",
      "validUntil": "2020-11-05T12:44:04Z"
    }
  }
}

For more information about the properties of a digital signature, please see the [relevant guide][].

In the case of error, PSPDFKit Server will return:

  • A 400 status code when either the request is malformed or the signing server responds with a status code in the 4xx range.

  • A 500 status code when the signing server responds with a status code in the 3xx or 5xx error range.

Fetching a Document’s Digital Signature Status

A document’s digital signature status is computed by looking at all the digital signatures included in the document. For more information about its properties and the flow that determines its final value, please see our guide about the status of digital signatures.

PSPDFKit Server takes care of automatically updating the digital signature status of a document after each change (e.g. adding a new annotation).

The validity of a signature is determined by the signing certificate used to create it: If you’re using a custom certificate, you need to set up PSPDFKit Server to use a corresponding certificate store in order to identify the signature as valid. Please check our guide article on how to set up custom certificates for digital signature validation.

By default, the signature certificates are validated against the current time. This means that valid signatures with expired certificates validate as expired. You can modify the DIGITAL_SIGNATURE_CERTIFICATE_CHECK_TIME configuration option to signing_time if you wish to instead validate certificates against the signing time.

⚠ Warning: If you’re validating digital signature certificates against the signing time, special care should be taken: By default, there’s no way of knowing whether the creation time stored with the signature itself can be trusted. To solve this issue, digital signatures need to use a Time Stamping Authority to provide a signed timestamp to embed. Note that we don’t validate the timestamp token’s certificates — we always assume a valid proof of existence if it’s present. Thus, it’s expected that the timestamps will be validated independently by your client code.

Request

You can fetch a document’s digital signature status with the /api/documents/:document_id/signatures endpoint:

GET /api/documents/:document_id/signatures
Content-Type: application/json
Authorization: Token token="<secret token>"
$ curl http://localhost:5000/api/documents/my-document/signatures \
   -H "ContentType: application/json" \
   -H "Authorization: Token token=<secret token>"

Response

In the case of success, PSPDFKit Server will respond with the status 200 and the JSON body containing the digital signature status of the document:

{
  "data": {
    "checkedAt": "2020-01-17T10:28:10.507Z",
    "documentModifiedSinceSignature": false,
    "signatures": [
      {
        "certificateChainValidationStatus": "ok_but_self_signed",
        "creationDate": "2020-01-17T10:01:53Z",
        "documentIntegrityStatus": "ok",
        "documentModifiedSinceSignature": false,
        "isExpired": false,
        "isSelfSigned": true,
        "isTrusted": false,
        "signatureFormFQN": "Signature-61b574ae-8057-45f1-91a3-59f08b88120d",
        "signatureValidationStatus": "warning",
        "type": "pspdfkit/signature-info",
        "validFrom": "2019-11-06T12:44:04Z",
        "validUntil": "2020-11-05T12:44:04Z"
      }
    ],
    "status": "warning"
  }
}

Please note that the response includes a checkedAt timestamp, which represents the exact time used by PSPDFKit Server to check the digital signature certificate’s validity. We strongly recommend never storing the digital signature status of a layer and always requesting it from PSPDFKit Server to have a reliable and up-to-date value.

Fetching a Layer’s Digital Signature Status

For a general overview of this endpoint, please check out the Fetching a Document’s Digital Signature Status section of this guide.

Request

You can fetch the digital signature status of an individual layer using the parent document ID and the layer name.

If you use a layer name that maps to a non-existing layer, PSPDFKit Server will report the status of the document base layer without creating a new one:

GET /api/documents/:document_id/layers/my-layer/signatures
Content-Type: application/json
Authorization: Token token="<secret token>"
$ curl http://localhost:5000/api/documents/my-document/layers/my-layer/signatures \
   -H "ContentType: application/json" \
   -H "Authorization: Token token=<secret token>"

Response

In the case of success, PSPDFKit Server will respond with the status 200 and the JSON body containing the digital signature status of the layer:

{
  "data": {
    "checkedAt": "2020-01-17T10:28:10.507Z",
    "documentModifiedSinceSignature": false,
    "signatures": [
      {
        "certificateChainValidationStatus": "ok_but_self_signed",
        "creationDate": "2020-01-17T10:01:53Z",
        "documentIntegrityStatus": "ok",
        "documentModifiedSinceSignature": false,
        "isExpired": false,
        "isSelfSigned": true,
        "isTrusted": false,
        "signatureFormFQN": "Signature-61b574ae-8057-45f1-91a3-59f08b88120d",
        "signatureValidationStatus": "warning",
        "type": "pspdfkit/signature-info",
        "validFrom": "2019-11-06T12:44:04Z",
        "validUntil": "2020-11-05T12:44:04Z"
      }
    ],
    "status": "warning"
  }
}

Please note that the response includes a checkedAt timestamp, which represents the exact time used by PSPDFKit Server to check the digital signature certificate’s validity. We strongly recommend never storing the digital signature status of a layer and always requesting it from PSPDFKit Server to have a reliable and up-to-date value.

Signing Options

The following options can be provided in the signing request’s JSON body:

  • signingToken (string) — An optional identifier of the signing operation. Its value is completely arbitrary, and it’ll be forwarded to the signing service in the exact same format. You can use it to verify the request, identify the signing user, or perform a specific authorization workflow.

  • flatten (Boolean) — When true, this flattens the document before signing it, which means that all existing annotations are permanently embedded into a document, making them no longer modifiable. Defaults to false.

  • signerDataSource — An advanced option needed to perform a signing operation.

  • estimatedSize (integer) — The estimated size of the signature (in bytes). The estimated size is the size for the signature that will be reserved in the PDF document before digitally signing it. By default, a reasonable default size will be used (8 KB, which will be around 16 KB in the signed PDF). The value of this property is clamped between 0 and 256 KB (262,144 bytes). This is an advanced property that you don’t need to be concerned about in most cases, since the default provided by PSPDFKit is generally large enough.

Example request:

POST /api/documents/:document_id/sign
Content-Type: application/json
Authorization: Token token="<secret token>"

{
  "signingToken": "my-signing-token",
  "flatten": true,
  "signerDataSource": { "estimatedSize": 16384 }
}
$ curl -XPOST http://localhost:5000/api/documents/my-document/sign \
   -H "ContentType: application/json" \
   -H "Authorization: Token token=<secret token>" \
   -d '{"signingToken": "my-signing-token", "flatten": true, "signerDataSource": { "estimatedSize": 16384 }}'

ℹ️ Note: The estimatedSize corresponds only to the /Contents field of the signature field — that is, the signature container. The size of the signature container mostly depends on the complexity of the certificates used for digital signatures. PSPDFKit will actually reserve a bigger space to make room for implementation details (e.g. the /ByteRange field, or the fact that a signature is hex-encoded in a PDF). A big estimated size will possibly make the signed document bigger than necessary, but a too small one will cause the signing process to fail with HTTP 400.