Notary API
Guide Reference
Search Press ESC to dismiss
  • Introduction
  • Overview
    • Location
    • Authentication
    • Request quotas
    • Status and error codes
  • Getting started
    • Setting up the Python environment
    • Starting the Python shell and configuring its session
    • Accessing the API
    • Notarizing a file and verifying its authenticity
      • Code examples
  • Notarizing files
    • Notarizing a file by uploading it to the notary storage
    • Notarizing a file by sending it to the notary service
    • Notarizing a file by its hash without metadata
    • Notarizing a file by its hash with metadata
  • Signing files electronically
    • Signing an individual file
    • Signing a file available by a permanent link
    • Checking the status of signing process
    • Resending signature request
    • Working with embedded signatures
      • Fetching signed and converted PDF files
      • Generating PDF annotations
      • Managing templates of e-sign documents
        • Creating a template of e-sign document
        • Creating an e-sign document from template
        • Fetching the templates of e-sign documents
        • Adding PDF annotations to existing template
        • Updating a template of e-sign document
        • Deleting a template of e-sign document
  • Verifying the authenticity of the files
    • Verifying the authenticity of a file by sending it to the notary service
    • Verifying the authenticity of multiple files by sending them to the notary service
    • Verifying the authenticity of a file by its hash
    • Verifying the authenticity of multiple files by their hashes
  • Managing files in the notary storage
    • Fetching the information about files
    • Fetching the information about a file
    • Downloading a file
    • Deleting multiple files
    • Deleting a file
  • Index
  • Legal
  • Privacy
Last updated on Jun 13, 2023. Copyright © Acronis International GmbH
2003-2023
  • Guide
  • Signing files electronically
  • Signing a file available by a permanent link

Signing a file available by a permanent link

  1. Start the Python shell and configure its session.

    The following variables should be available now:

    >>> base_url  # the base URL of the API
    'https://eu2-cloud.acronis.com/api/notary/v2'
    >>> auth  # the 'Authorization' header value with the access token
    {'Authorization': 'Bearer 8770b34b74f9e4d9424eff50c38182bb4ae7f5596582ae61900b1b6a23e3ec58'}
    
  2. Define a variable named file_path, and then assign the path to your file to this variable:

    >>> file_path = '<path to file>'
    

    Important

    If the path contains backslashes, remember to escape them with an additional backslash.

  3. Define a variable named file_link, and then assign the permanent link to the file to this variable:

    >>> file_link = 'https://www.example.com/loremipsum'
    
  4. Open the file for reading in binary mode:

    >>> file = open(file_path, 'rb')
    
  5. Calculate the hash value of the file contents by using the SHA-256 algorithm:

    >>> sha256 = hashlib.sha256()
    >>> chunk = file.read(128 * sha256.block_size)
    >>> while chunk:
    ...     sha256.update(chunk)
    ...     chunk = file.read(128 * sha256.block_size)
    >>> file_hash
    '2c7c3d5f244f1a40069a32224215e0cf9b42485c99d80f357d76f006359c7a18'
    

    A correctly calculated hash value of the file contents may help signees to prove, via the API, that the file they see in an email message with the signature request is indeed being signed by using the notary service.

  6. Close the file:

    >>> file.close()
    
  7. Fetch the size of the file:

    >>> file_size = os.path.getsize(file_path)
    >>> file_size
    446
    
  8. Fetch the file name from the file path:

    >>> file_name = os.path.basename(file_path)
    
  9. Define a variable named file_info, and then assign the information about the file to this variable:

    >>> file_info = {
    ...     'link': file_link,
    ...     'name': file_name,
    ...     'size': file_size,
    ...     'hash': file_hash
    ... }
    
  10. Define a variable named file_owner, and then assign the information about the signing initiator who is considered to be the file owner to this variable:

    >>> file_owner = {
    ...     'email': 'john.doe@example.com',
    ...     'full_name': 'John Doe'
    ... }
    
  11. Define a variable named file_data, and then assign an object with the following JSON parameters to this variable:

    >>> file_data = {
    ...     'file': file_info,
    ...     'owner': file_owner,
    ...     'exclude_me': False,
    ...     'lang': 'en'
    ... }
    

    The exclude_me key defines whether to exclude the signing initiator from the list of signees.

    The lang key defines the language that will be used in email messages sent by the notary service during the signing and in the generated signature certificate file.

    Available values:

    • da - Danish

    • de - German

    • en - English

    • es - Spanish

    • fr - French

    • hu - Hungarian

    • it - Italian

    • ja - Japanese

    • ru - Russian

    • tr - Turkish

  12. [Optional] To sign the file with embedded signatures of the signees, add the embedded key and set its value to true:

    >>> file_data['embedded'] = True
    

    Note

    In order to sign the file with embedded signature, it must comply with the following requirements:

    1. The file must be either in PDF or in one of the following file types that will be converted to PDF by the notary service:

      • .doc/.docx

      • .xls/.xlsx

      • .ppt/.pptx

      • .txt

    2. Maximum file size limit is 32 MB.

    3. The file must not be protected by password.

    4. If the uploaded file is in PDF, “Changing the Document” and “Commenting” permissions must be set to “Allowed”.

    5. The link must be publicly accessible in order to be downloaded by the notary service.

  13. Convert the file_data object to a JSON text:

    >>> file_data = json.dumps(file_data, indent=4)
    
  14. Send a POST request with the JSON text to the /documents endpoint:

    >>> response = requests.post(
    ...     f'{base_url}/documents',
    ...     headers={'Content-Type': 'application/json', **auth},
    ...     data=file_data,
    ... )
    
  15. Check the status code of the response:

    >>> response.status_code
    200
    

    Status code 200 means that the notary service has received the object and created an e-sign document for it.

    A different status code means that an error has occurred. For the details, refer to “Status and error codes”.

    Also, the response body contains an object containing the ID of the document formatted as a JSON text. When converted to an object, it will look as follows:

    >>> pprint.pprint(response.json())
    {
        "document_id": "8592b052a9979f8d651618092bb3ac8472beebc66d52ab980deb4d320e26b0cb"
    }
    
  16. Convert the JSON text that the response body contains to an object, and then fetch the ID of the e-sign document:

    >>> doc_id = response.json()['document_id']
    >>> doc_id
    '8592b052a9979f8d651618092bb3ac8472beebc66d52ab980deb4d320e26b0cb'
    
  17. Define a variable named signees, and then assign an object containing the list of signees’ email addresses in the emails key to this variable:

    >>> signees = {
    ...     'emails': ['john.smith@example.com', 'john.doe@example.com']
    ... }
    

    If you want to sign this file, include your email address in this list.

    Warning

    It will not be possible to change the list of signees after sending the initial list to the notary service.

  18. [Optional] If you chose to embed the signee signatures in the file:

    1. Follow the Generating PDF annotations procedure to fetch the list of PDF annotations.

    2. Add the annotations key and assign it with the list of PDF annotations:

      >>> signees['annotations'] = [
      ...     "{\"bbox\":[129.81423950195312,216.01904296875,200,50], ...}",
      ...     "{\"bbox\":[186.60797119140625,409.7261962890625,200,50], ...}"
      ... ]
      
  19. Convert the signees object to a JSON text:

    >>> signees = json.dumps(signees, indent=4)
    >>> print(signees)
    {
        "emails": [
            "john.smith@example.com",
            "john.doe@example.com"
        ]
    }
    
  20. Send a POST request with the JSON text to the /documents/{doc_id}/signees endpoint:

    >>> response = requests.post(
    ...     f'{base_url}/documents/{doc_id}/signees',
    ...     headers={'Content-Type': 'application/json', **auth},
    ...     data=signees,
    ... )
    
  21. Check the status code of the response:

    >>> response.status_code
    200
    

    Status code 200 means that the notary service has initiated the signing and sent email messages with the signature request to the signees. To check the signing status, refer to Checking the status of signing process.

    A different status code means that an error has occurred. For the details, refer to “Status and error codes”.

Full code example

  1#!/usr/bin/env python3
  2
  3import requests  # Will be used for sending requests to the API.
  4import hashlib   # Will be used for calculating hash values.
  5import os.path   # Will be used for path-related operations.
  6import pprint    # Will be used for formatting the output of JSON objects received in API responses.
  7import json      # Will be used for converting dictionaries into JSON text
  8
  9# Define variables named "LOGIN" and "PASSWORD" and then assign them with your account credentials
 10LOGIN = '<your login>'        # Change login here
 11PASSWORD = '<your password>'  # Change password here
 12
 13# Define a variable named "cloud_url" and then assign it with the URL of the cloud platform
 14cloud_url = 'https://cloud.acronis.com'
 15
 16# Fetch the URL of the data center where your account is located by sending a GET request to the "/api/1/accounts" endpoint
 17response = requests.get(
 18    f'{cloud_url}/api/1/accounts',
 19    params={'login': LOGIN}
 20)
 21response.raise_for_status()
 22
 23# Convert the JSON text that the response body contains to a dictionary and store the data center URL
 24# in a variable that will be used in further requests
 25server_url = response.json()['server_url']
 26
 27# Define a variable named "account_creds", and then assign the username and password to this variable
 28account_creds = {
 29    'username': LOGIN,
 30    'password': PASSWORD
 31}
 32
 33# Generate a token by sending a POST request to the "/api/2/idp/token" with your account credentials to the cloud platform
 34response = requests.post(
 35    f'{server_url}/api/2/idp/token',
 36    headers={'Content-Type': 'application/x-www-form-urlencoded'},
 37    data={'grant_type': 'password', **account_creds}
 38)
 39response.raise_for_status()
 40
 41# Convert the JSON text that the response body contains to a dictionary and then assign it to a variable named "token_info"
 42token_info = response.json()
 43
 44# Define a variable named "auth" and then assign it with a dictionary with "Authorization" key containing
 45# token string formatted as "Bearer <access_token>"
 46auth = {
 47    'Authorization': 'Bearer ' + token_info['access_token']
 48}
 49
 50# Define a variable named "base_url", and then assign the API base URL using the data center URL
 51# to this variable
 52base_url = f'{server_url}/api/notary/v2'
 53
 54# Define a variable named "file_id" and then assign it with the ID of the file
 55file_path = '<path to file>'  # Change path to file here
 56
 57# Define a variable named "file_link" and then assign it with the link to the file
 58file_link = 'https://www.example.com/loremipsum'
 59
 60# Open the file for reading in binary mode
 61file = open(file_path, 'rb')
 62
 63# Calculate the SHA-256 hash of the file
 64sha256 = hashlib.sha256()
 65chunk = file.read(128 * sha256.block_size)
 66while chunk:
 67    sha256.update(chunk)
 68    chunk = file.read(128 * sha256.block_size)
 69file_hash = sha256.hexdigest()
 70
 71# Close the file
 72file.close()
 73
 74# Fetch the size of the file and then assign its value to the "file_size" variable
 75file_size = os.path.getsize(file_path)
 76
 77# Fetch the name of the file and then assign its value to the "file_name" variable
 78file_name = os.path.basename(file_path)
 79
 80# Define a variable named "file_info", and then assign the information about the file to this variable
 81file_info = {
 82    'link': file_link,
 83    'name': file_name,
 84    'size': file_size,
 85    'hash': file_hash
 86}
 87
 88# Define a variable named "file_owner", and then assign the information about the signing initiator who is
 89# considered to be the file owner to this variable
 90file_owner = {
 91    'email': 'john.doe@example.com',
 92    'full_name': 'John Doe'
 93}
 94
 95# Define a variable named file_data, and then assign a dictionary with the following JSON parameters to this variable
 96file_data = {
 97    'file': file_info,
 98    'owner': file_owner,
 99    'exclude_me': False,
100    'lang': 'en'
101}
102
103# Convert the "file_data" dictionary to a JSON text
104file_data = json.dumps(file_data, indent=4)
105
106# Send the file for signing by sending a POST request to the "/documents" endpoint
107response = requests.post(
108    f'{base_url}/documents',
109    headers={'Content-Type': 'application/json', **auth},
110    data=file_data,
111)
112response.raise_for_status()
113
114# Convert the JSON text that the response body contains to a dictionary and fetch the ID of the created document
115doc_id = response.json()['document_id']
116
117# Define a variable named "signees"
118# and then assign it with a dictionary with "emails" key containing an array of the emails of the signees
119signees = {
120    'emails': ['john.smith@example.com', 'john.doe@example.com']
121}
122
123# Convert the "signees" dictionary to a JSON text
124signees = json.dumps(signees, indent=4)
125
126# Send the list of signees to the notary service by sending a POST request to the "/documents/{doc_id}/signees" endpoint
127response = requests.post(
128    f'{base_url}/documents/{doc_id}/signees',
129    headers={'Content-Type': 'application/json', **auth},
130    data=signees,
131)
132response.raise_for_status()
Previous Next
  • Legal
  • Privacy
Last updated on Jun 13, 2023. Copyright © Acronis International GmbH
2003-2023
Back to top