Skip to main content
Skip table of contents

8. Document Signing and Sealing

Document Signing and Sealing

This scenario demonstrates how to create a document, apply electronic signatures or seals, and download the completed file. Digital signatures and seals provide authenticity, integrity, and non-repudiation for your documents.

Key features:

  • Create a document from an uploaded PDF file

  • Apply an electronic seal (certification) to the document

  • Add a visual signature with positioning on specific pages

  • Download the signed or sealed document

  • Download the document's audit trail for compliance and verification purposes

Prerequisites

Before signing or sealing a document, you need:

  • A valid authentication token (see the "Authentication & Security" section for details)

  • A PDF file to upload and sign

  • Appropriate permissions to sign documents in your Circularo instance

  • For visual signatures, a signature image file already uploaded to your account

Step 1 - Upload a PDF file

Before creating a document, you need to upload the PDF file that will serve as the document content. This step uploads and stores a PDF file in the Circularo system.

  • The file is uploaded as a multipart/form-data request

  • The response includes the file ID that will be used in the document creation step

  • The response also includes storage quota information to help manage available space

The file upload is a separate step from document creation and signing.

Endpoint

CODE
POST /files/saveFile

Request

JSON
POST /files/saveFile?token=E7yTzUxBPDpwgj5sKGyfFjTf8ZJvxH6EA1M4jMGkTy8NmevThY3eifw5c5q96hAi

Content-Type: multipart/form-data

{
  "file": "blob",
  "fileName": "Contract Agreement"
}

Response

The response contains the following important properties:

  • fileHash - Located at file.id in the response.

    • Example value: iS8Gu6vWgX7bu34ywE0ObWmt8kwOoq4wz5RtCggJI7oaXRA5j4adGFvoB63rhNzR

The PDF file has been successfully uploaded and stored in the system. The response includes the file ID that will be used in the next step to create a document based on this file.

  • The file.id is the unique identifier for the uploaded file

  • This ID will be used in the document creation step to reference this file

  • The storage information shows your current usage and available quota

Store the file ID for use in the next step. This ID is required to create a document based on this file.

Step 2 - Create a document from the PDF file

This endpoint creates a new document in the Circularo system using the previously uploaded PDF file.

  • The documentType parameter specifies which metadata definition to use

  • The workflow parameter defines the workflow that will be applied to the document

  • The definitionType parameter is set to "ext" to indicate an external file-based document

  • The pdfFile.content parameter references the file ID from the previous step

The document must be created before it can be signed or sealed.

Endpoint

CODE
POST /documents

Request

JSON
POST /documents?token=E7yTzUxBPDpwgj5sKGyfFjTf8ZJvxH6EA1M4jMGkTy8NmevThY3eifw5c5q96hAi

Content-Type: application/json

{
  "body": {
    "documentType": "d_default",
    "documentTitle": "My Document",
    "pdfFile": {
      "content": "iS8Gu6vWgX7bu34ywE0ObWmt8kwOoq4wz5RtCggJI7oaXRA5j4adGFvoB63rhNzR"
    }
  },
  "definitionType": "ext",
  "workflow": "wf_archive"
}

Response

The response contains the following important properties:

  • documentId - Located at results[0].documentId in the response.

    • Example value: c77ac248-155b-4f6e-ac00-d2093162cb03

The document has been successfully created and is now available in the system.

  • The response includes the document ID which will be used for signing or sealing

  • The document is created with the specified metadata definition and workflow

  • The document is initially in the first state of the specified workflow

Store the document ID for use in the subsequent steps.

Step 3 - Retrieve document information

Before signing or sealing a document, you need to retrieve its current version. This step fetches the document information using the document ID.

  • The document ID uniquely identifies the document in the system

  • The response includes the current document version, which is required for signing operations

  • Version information prevents conflicts when multiple users are working with the same document

The document version is critical for signing operations. If you use an outdated version, the operation will fail with a 409 Conflict error.

Endpoint

CODE
GET /documents/:documentId

Request

JSON
GET /documents/c77ac248-155b-4f6e-ac00-d2093162cb03?token=E7yTzUxBPDpwgj5sKGyfFjTf8ZJvxH6EA1M4jMGkTy8NmevThY3eifw5c5q96hAi

Response

The response contains the following important properties:

  • documentVersion - Located at results[0]._version in the response.

    • Example value: 5

The response includes comprehensive information about the document, including its current version.

  • The _version field contains the current document version needed for signing operations

  • This version number changes whenever the document is modified

  • If a signing operation fails with a version mismatch error, retrieve the document again to get the updated version

If any signing operation fails with a 409 Conflict error, call this endpoint again to get the updated document version. Background tasks may change the document version after it is created.

Step 4A - Seal the document

This endpoint applies an electronic seal (certification) to the document. Sealing a document certifies its authenticity and integrity without adding a visual signature.

  • The documentVersion parameter must match the current version of the document

  • The id parameter specifies which document to seal

  • The certificate parameter set to true applies a digital certificate to the document

Sealing is appropriate when you need to certify a document's authenticity without adding a visual signature. It applies cryptographic protection to the entire document.

Endpoint

CODE
PUT /documents/seal/:documentVersion

Path parameters:

  • documentVersion - Document version taken from the previous step.

Request

JSON
PUT /documents/seal/5?token=E7yTzUxBPDpwgj5sKGyfFjTf8ZJvxH6EA1M4jMGkTy8NmevThY3eifw5c5q96hAi

Content-Type: application/json

{
  "id": "c77ac248-155b-4f6e-ac00-d2093162cb03",
  "certificate": true
}

The document has been successfully sealed with a digital certificate.

  • The document now has cryptographic protection that verifies its integrity

  • The seal is applied to the entire document

  • The document's workflow history is updated to reflect the sealing operation

Sealed documents can be verified by PDF readers that support digital signatures.

Step 4B - Sign the document

This endpoint applies a visual signature to the document at a specified position. Signing can add both a visual representation of your signature and cryptographic protection (depending on system settings).

  • The documentVersion parameter must match the current version of the document

  • The signatures array contains information about where and how to place the signature

  • The position object defines the exact placement of the signature on the page

  • The blob parameter references your signature image file

Endpoint

CODE
PUT /documents/sign/:documentVersion

Path parameters:

  • documentVersion - Document version taken from the previous step.

Request

JSON
PUT /documents/sign/5?token=E7yTzUxBPDpwgj5sKGyfFjTf8ZJvxH6EA1M4jMGkTy8NmevThY3eifw5c5q96hAi

Content-Type: application/json

{
  "signatures": [
    {
      "pages": [  //Page(s) where the signature should be placed
        1
      ],
      "position": {  //Position and size of the signature
        "percentX": 0.5336425978217023,
        "percentY": 0.2360980475986889,
        "percentWidth": 0.3910665378654381,
        "percentHeight": 0.1
      },
      "blob": "T1jzK5kcA8v2T89uwZQ6s4pDGti7xdeRo2dpk4z6CrdQGxVtmcJroSbDCEcqaN3y",  //Signature image file ID
      "decorationType": "empty",
      "type": "signature",  //Other possible types: initials, stamp, wacom, annotation, and image
      "timestamp": false  //If true, places timestamp under the signature
    }
  ],
  "id": "c77ac248-155b-4f6e-ac00-d2093162cb03"  //ID of the document you want to sign
}

The document has been successfully signed with your signature image.

  • The signature is visually placed at the specified position on the document

  • Depending on the system settings, the document now may have a cryptographic protection that verifies its integrity

  • The document's workflow history is updated to reflect the signing operation

You can add multiple signatures to a document by including more objects in the signatures array.

Step 5 - Retrieve updated document information after signing/sealing

After signing or sealing a document, the file ID (hash) changes because a new version of the document has been created. This step fetches the updated document information to get the new file hash needed for downloading.

  • The document ID remains the same, but the file content has been updated with signatures or seals

  • The response includes the new file hash (pdfFile.content) that must be used for downloading

  • This step is crucial because the original file hash no longer points to the signed/sealed version

Skipping this step will result in downloading the original unsigned document instead of the signed/sealed version.

Endpoint

CODE
GET /documents/:documentId

Request

JSON
GET /documents/c77ac248-155b-4f6e-ac00-d2093162cb03?token=E7yTzUxBPDpwgj5sKGyfFjTf8ZJvxH6EA1M4jMGkTy8NmevThY3eifw5c5q96hAi

Response

The response contains the following important properties:

  • fileHash - Located at results[0].pdfFile.content in the response.

    • Example value: iivep6vKkrnrt77yTR0K2pOgVWEKtyipPkBNeu6cEFu6JgNGHCidScg7H9y1v5QJ

The response includes the updated document information with the new file hash for the signed/sealed document.

  • The pdfFile.content field contains the new file hash for the signed/sealed document

  • This new hash is different from the original file hash used to create the document

  • The new hash must be used in the next step to download the signed/sealed version of the document

Always retrieve the document information after signing or sealing to get the updated file hash. The original file hash will only download the unsigned version of the document.

Step 6 - Download the signed or sealed document

This endpoint downloads the signed or sealed document file using the new file hash obtained in the previous step.

  • The hash parameter must be the new file hash obtained after signing/sealing

  • Using the original file hash would download the unsigned version of the document

  • The response is the binary content of the document file with signatures or seals applied

The downloaded document can be opened in any PDF reader. Digital signatures and seals can be verified in PDF readers that support this feature.

Endpoint

CODE
GET /files/loadFile/hash/:hash

Path parameters:

  • hash - The new file hash obtained after signing/sealing the document.

Request

JSON
GET /files/loadFile/hash/iivep6vKkrnrt77yTR0K2pOgVWEKtyipPkBNeu6cEFu6JgNGHCidScg7H9y1v5QJ?token=E7yTzUxBPDpwgj5sKGyfFjTf8ZJvxH6EA1M4jMGkTy8NmevThY3eifw5c5q96hAi

The signed or sealed document has been successfully downloaded.

  • The response contains the binary content of the document file with signatures or seals applied

  • The file includes all visual signatures and/or cryptographic protections that were applied

  • The document can be saved locally or processed further as needed

Step 7 - Download the audit trail

This endpoint downloads a PDF document containing the complete audit trail for the signed or sealed document. The audit trail provides a detailed record of all actions performed on the document, including creation, modifications, and signatures.

  • The audit trail is essential for compliance and verification purposes

  • It contains timestamps, user information, and details of all actions performed on the document

  • The audit trail is generated as a separate PDF document that can be stored alongside the signed document

  • This provides a complete chain of custody and evidence of the document's integrity

The audit trail is particularly important in regulated industries and for legally sensitive documents where proof of document handling may be required.

Endpoint

CODE
GET /documents/:documentId/audit

Request

JSON
GET /documents/c77ac248-155b-4f6e-ac00-d2093162cb03/audit?token=E7yTzUxBPDpwgj5sKGyfFjTf8ZJvxH6EA1M4jMGkTy8NmevThY3eifw5c5q96hAi

The audit trail PDF has been successfully downloaded.

  • The response contains the binary content of the audit trail PDF

  • This document provides a complete record of all actions performed on the document

  • The audit trail can be saved locally for record-keeping and compliance purposes

Store the audit trail alongside the signed document for a complete record of the document's lifecycle.


Document Signing and Sealing Summary

You have successfully learned how to create, sign or seal, and download documents in the Circularo system.

Key Concepts

  • Document Sealing: Applies certification to the entire document without visual elements

  • Document Signing: Adds a visual signature at specific locations with cryptographic protection (optional)

  • Version Control: Document version is required to prevent conflicts during signing operations

  • Digital Certificates: Cryptographic protection that verifies document integrity and authenticity

  • Audit Trail: Comprehensive record of all document activities for compliance and verification

Choosing Between Signing and Sealing

  • Use Sealing When: You need to certify a document's authenticity without visual signatures

  • Use Signing When: You need visual representation of signatures at specific locations

Example Implementation

See our OpenAPI documentation to learn about the full set of API endpoints and parameters.

Please use proper exception handling and function decomposition in your own code. The code is provided for illustrative purposes only and is not intended for production use.

JAVASCRIPT
// Document signing example
const URL = "https://sandbox.circularo.com";
const API_PATH = "/api/v1";
const TOKEN = "YOUR_AUTH_TOKEN"; // Obtained from login or API key
const SIGNATURE_IMAGE_ID = "YOUR_SIGNATURE_IMAGE_ID"; // File ID of your uploaded signature image

try {
    // Step 1: Upload a PDF file
    const formData = new FormData();
    formData.append('fileName', 'Contract Agreement');
    formData.append('file', fs.createReadStream('path/to/document.pdf'));   // Using Node.js fs module

    const uploadResponse = await fetch(`${URL}${API_PATH}/files/saveFile?token=${TOKEN}`, {
        method: 'POST',
        body: formData
    });
    if (!uploadResponse.ok) {
        throw new Error(`File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}`);
    }

    const uploadData = await uploadResponse.json();
    const fileId = uploadData.file.id;

    // Step 2: Create a document from the uploaded file
    const createResponse = await fetch(`${URL}${API_PATH}/documents?token=${TOKEN}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            body: {
                documentType: "d_default",
                documentTitle: "Contract Agreement",
                pdfFile: {
                    content: fileId
                }
            },
            definitionType: "ext",
            workflow: "wf_archive"
        })
    });
    if (!createResponse.ok) {
        throw new Error(`Document creation failed: ${createResponse.status} ${createResponse.statusText}`);
    }

    const createData = await createResponse.json();
    const documentId = createData.results[0].documentId;

    // Step 3: Get the document version
    const documentResponse = await fetch(`${URL}${API_PATH}/documents/${documentId}?token=${TOKEN}`);
    if (!documentResponse.ok) {
        throw new Error(`Failed to retrieve document: ${documentResponse.status} ${documentResponse.statusText}`);
    }

    const documentData = await documentResponse.json();
    const documentVersion = documentData.results[0]._version;

    // Step 4: Option A - Seal the document
    const sealResponse = await fetch(`${URL}${API_PATH}/documents/seal/${documentVersion}?token=${TOKEN}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            id: documentId,
            certificate: true
        })
    });
    if (!sealResponse.ok) {
        throw new Error(`Document sealing failed: ${sealResponse.status} ${sealResponse.statusText}`);
    }

    // OR Step 4: Option B - Sign the document
    /*
    const signResponse = await fetch(`${URL}${API_PATH}/documents/sign/${documentVersion}?token=${TOKEN}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            signatures: [{
                pages: [1],
                position: {
                    percentX: 0.5336425978217023,
                    percentY: 0.2360980475986889,
                    percentWidth: 0.3910665378654381,
                    percentHeight: 0.1
                },
                blob: SIGNATURE_IMAGE_ID,
                decorationType: "empty",
                type: "signature",
                timestamp: false
            }],
            id: documentId
        })
    });
    if (!signResponse.ok) {
        throw new Error(`Document signing failed: ${signResponse.status} ${signResponse.statusText}`);
    }
    */

    // Step 5: Get the updated document information to obtain the new file hash
    const updatedDocumentResponse = await fetch(`${URL}${API_PATH}/documents/${documentId}?token=${TOKEN}`);
    if (!updatedDocumentResponse.ok) {
        throw new Error(`Failed to retrieve updated document: ${updatedDocumentResponse.status} ${updatedDocumentResponse.statusText}`);
    }

    const updatedDocumentData = await updatedDocumentResponse.json();
    const newFileId = updatedDocumentData.results[0].pdfFile.content;

    // Step 6: Download the signed/sealed document using the new file hash
    const downloadResponse = await fetch(`${URL}${API_PATH}/files/loadFile/hash/${newFileId}?token=${TOKEN}`);
    if (!downloadResponse.ok) {
        throw new Error(`Document download failed: ${downloadResponse.status} ${downloadResponse.statusText}`);
    }

    // Save the document to disk or process it as needed
    const fileBlob = await downloadResponse.blob();
    const downloadLink = document.createElement('a');
    downloadLink.href = URL.createObjectURL(fileBlob);
    downloadLink.download = 'Signed_Contract.pdf';
    downloadLink.click();

    // Step 7: Download the audit trail
    const auditTrailResponse = await fetch(`${URL}${API_PATH}/documents/${documentId}/audit?token=${TOKEN}`);
    if (!auditTrailResponse.ok) {
        throw new Error(`Audit trail download failed: ${auditTrailResponse.status} ${auditTrailResponse.statusText}`);
    }

    // Save the audit trail to disk
    const auditTrailBlob = await auditTrailResponse.blob();
    const auditTrailLink = document.createElement('a');
    auditTrailLink.href = URL.createObjectURL(auditTrailBlob);
    auditTrailLink.download = 'Contract_Audit_Trail.pdf';
    auditTrailLink.click();

    console.log('Document and audit trail successfully downloaded');

} catch (error) {
    console.error('Error in document signing process:', error.message);
}

Digital signatures and seals have legal implications. Ensure you understand the legal requirements in your jurisdiction before implementing electronic signatures in production systems.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.