Request a seal

In addition to the use of seals in a transaction, we offer a standalone seal service.

With the standalone seal service, you can:

Before you can request a document to be sealed, you need to:

  1. Own a Certificate for Legal Person (LPC).
  2. Make sure the feature is activated on your account.

To request an LPC creation and/or activate the feature on your account, contact your account manager at Universign.

Note that when you use the standalone seal service, sealed documents are not stored. Documents are only stored when you seal a document within the transaction process.

Seal a PDF document

To seal a document, send a multipart/form-data request to POST /v1/seals and pass the document in the file argument as well as the seal id.

Note that we accept only PDF input format in a maximum size limit of 25MB.

curl
https://api.universign.com/v1/seals \
-F [email protected] \
-d seal_id=lpc_wa7ZVZGxzOq0 \
-d label="John DOE, CEO of the company"

You can pass optional parameters:

  • field_page: The page number on which you want to position the seal. Default value is 1.
  • field_x: The seal horizontal coordinate on the document page (in pixels). Default value is 0.
  • field_y: The seal vertical coordinate on the document page (in pixels). Default value is 0.
  • height: The height of the seal (expressed in PDF’s default user space units). Minimum value is 23, default value is 50 and height ratio must be 4 x width.
  • width: The width of the seal (expressed in PDF’s default user space units). Minimum value is 92, default value is 200 and height ratio must be 4 x width.

If you set only required parameters or if you do not set field_page, field_x, field_y, height and width parameters, the API returns a 200 response that contains a PAdES document seal with an invisible seal.

  • language: The language of the text in the seal cartridge (“Sealed by [sealname], on [sealdate]”). Expected input format is ISO 639-1. We currently support the following languages: French (fr), Bulgarian (bg), Catalan (ca), Dutch (nl), English (en), German (de), Italian (it), Norwegian (no), Polish (pl), Portuguese (pt), Romanian (ro), Spanish (es) and Swedish (sv). French (fr) is the default language.

  • custom_logo : The seal logo that will display on the document. We accept only JPEG and PNG formats in a maximum size limit of 2 MB.

Note: To guarantee high quality resolution, your logo dimensions should be 300px x 72px.

Note that the size of the seal is set to 200px x 50px and cannot be edited. Make sure the seal is well positioned in the document. If any edge of the seal exceeds the document limit, the API returns an error.

  • label: The label that will be displayed on the signature cartridge. Note that the label value will always be preceded by the expression Sealed by that is automatically generated by our system. The feature needs to be activated on your workspace.

  • compliance_policy: Set to pdfa to force the sealing operation to respect PDF/A standard. If not set, if you import a PDF/A document, it will be sealed but no longer PDF/A compliant.

  • signature_type : The type of signature for a standalone seal. Set to certification to apply a certification signature on the document. For more details, visit Certification signatures.
  • certification_permission: Defines which modifications are allowed after a certification signature is applied. Possible values are read_only, fill, annotate. Set only if signature_type is set to certification.

About certificate permissions

  • read_only: No changes to the document are permitted. Any change to the document shall invalidate the signature.

read only permission

  • fill: Permitted changes shall be filling in forms, instantiating page templates, and signing. Any other change shall invalidate the signature.

fill permission

Note that forms and signature fields must be already present in the document to be certified.

Built-in signature fields must have dimensions equal or bigger than 200x50px. If a built-in signature field is too small, the document is not accepted.

built-in field too small

  • annotate: Permitted changes are the same as for fill, as well as annotation creation, deletion, and modification. Any other change shall invalidate the signature.

Note that forms and signature fields must be already present in the document to be certified.

Annotate permission

Seal a document using a QCP-l-qscd certificate

You may need to seal a document using a QCP-l-qscd certificate for legal person (LPC). As it is a higher level certificate, the use of the seal needs to be authorized by setting the PIN code previsouly initialized for the certificate.

To do so, you need to pass the PIN code of the certificate in the auth_data[].value argument, as in the request example below:

Request example

curl
https://api.universign.com/v1/seals \
-F [email protected] \
-d seal_id=lpc_wa7ZVZGxzOq0 \
-d auth_data[atm_Bw3e].value=12345678
  • auth_data[ ].value: Set only to authorize the use of a QCP-l-qscd certificate for legal person (LPC) to seal a document. You must specify the PIN code related to the certificate. The value of the authentication means must be appended to the auth_data[ ].value argument between brackets (for example auth_data[atm_Bw3e].value). Note that you can retrieve the authentication means ID from the Certificates section of your workspace.

Seal a PDF/A document

PDF/A is an ISO standardized format (ISO 19005) with strict rules to eliminate anything that could break over time.

PDF/A is commonly required when documents must be archived, exchanged, or legally preserved.

You may need to seal a PDF/A document and guarantee the same level of compliance once sealed. To do so, send a multipart/form-data request to POST /v1/seals and pass the document in the file argument, the certificate seal_id, as well as the compliance_policy argument.

curl
https://api.universign.com/v1/seals \
-F file=@MyPDF_A.pdf \
-d seal_id=lpc_wa7ZVZGxzOq0 \
-d compliance_policy=pdfa

The API returns a 200 response that contains the PDF/A document sealed and bearing the same level of compliance.

The illustrations below show the PDF/A document compliance check before and after sealing.

PDF/A document check

PDF/A Check

Sealed PDF/A document check

Sealed PDF/A Check

Retrieve the certificate chain

Before signing a hash, you may need the ID of your LPC and the certificate chain of your sealer. The ID of your LPC (or sealer) is the same as the seal_id used to seal a PDF document (for example lpc_wa7ZVZGxzOq0).

To retrieve the certificate chain, send a GET request to GET /v1/sealers/{sealer_id}.

curl
https://api.universign.com/v1/sealers/lpc_wa7ZVZGxzOq0

The API returns a 200 response that contains a JSON object:

{
  "id": "lpc_wa7ZVZGxzOq0",
  "certificate_chain": [
    "MIIGyjCCBLKgAwIBAgIRAJZpvFJjhgMj...",
    "MIIF...",
    "MIIFbDCCA1SgAwIBAgIUEAOYh64F0ICU..."
  ],
  "signature_algorithms": [
    "1.2.840.113549.1.1.10"
  ]
}
  • id: The ID of the sealer.
  • certificate_chain: The certificate chain of the LPC, base64-encoded. The signing certificate comes first, followed by the intermediate and root certificates.
  • signature_algorithms: The OIDs of the signature algorithms supported by the sealer. Read this list rather than hardcoding the OID, so that your integration keeps working when new algorithms are added.

Note that the certificate chain is returned even when the certificate is expired or revoked, so that you can check its status. However, signing with such a certificate is rejected.

Use the certificate chain to build your signature container after a hash signature, or to verify a signature.

Note that the LPC must be linked to your workspace. Otherwise, the API returns a 404 error.

Sign a hash

You may need to sign data that is not a PDF or an XML document, or to build your own signature container (for example with the DSS library). In this case, you can compute the hash of your data on your side and send only the hash to be signed with your sealer.

Your data never leaves your system: you only send its hash. The API returns the raw signature value, that you integrate in your own signature container (CAdES, XAdES, JAdES, PAdES…).

1. Compute the hash of your data

The hash must be computed with the SHA-256 algorithm and sent as a binary file (32 bytes), not as a hexadecimal string.

openssl dgst -sha256 -binary MyDocument.pdf > hashvalue

For example, the SHA-256 hash 354BD98DA206B3A5650BBE4C6630D467AAF65A4E33590DD20E50C469104FE8A6 (hexadecimal representation) must be sent as the corresponding 32 bytes. If you already have the hash as a hexadecimal string, convert it to binary:

echo -n 354BD98DA206B3A5650BBE4C6630D467AAF65A4E33590DD20E50C469104FE8A6 | xxd -r -p > hashvalue

2. Sign the hash

Send a multipart/form-data request to POST /v1/sealers/{sealer_id}/sign-hash and pass the hash in the hash argument, as well as the signature and hash algorithms.

curl
https://api.universign.com/v1/sealers/lpc_wa7ZVZGxzOq0/sign-hash \
-F hash=@hashvalue \
-F signature_algorithm=1.2.840.113549.1.1.10 \
-F hash_algorithm=2.16.840.1.101.3.4.2.1 \
--output signature.bin
  • hash: The hash to sign, as a binary file. Its length must match the hash algorithm (32 bytes for SHA-256) and must not exceed 64 bytes.
  • signature_algorithm: The OID of the signature algorithm.
  • hash_algorithm: The OID of the hash algorithm used to compute the hash.
  • auth_data[ ].value: Set only to authorize the use of a QCP-l-qscd certificate for legal person (LPC). For more details, refer to Seal a document using a QCP-l-qscd certificate.

Supported algorithms

Only the following combination of algorithms is supported. Any other value is rejected with a 400 error.

Algorithm Name OID
Signature algorithm RSASSA-PSS 1.2.840.113549.1.1.10
Hash algorithm SHA-256 2.16.840.1.101.3.4.2.1

The API returns a 200 response with the application/octet-stream content type. The body contains the raw signature value (binary). It is not a JSON object nor a signature container: write it to a file or read it as a byte array, do not parse it as text.

3. Build your signature container

Use the raw signature value and the certificate chain returned by Retrieve the certificate chain to build your signature container.

You can check the signature value with OpenSSL, using the signing certificate (first certificate of the chain) saved as certificate.pem:

openssl x509 -in certificate.pem -pubkey -noout > publickey.pem

openssl pkeyutl -verify -pubin -inkey publickey.pem \
-in hashvalue -sigfile signature.bin \
-pkeyopt digest:sha256 \
-pkeyopt rsa_padding_mode:pss \
-pkeyopt rsa_pss_saltlen:32 \
-pkeyopt rsa_mgf1_md:sha256

Errors

The API returns a 400 error when:

  • the signature_algorithm or the hash_algorithm is missing, blank or not supported,
  • the hash is missing, or its length does not match the hash algorithm (for example The hash must be 32 bytes long, got 16),
  • the certificate does not support the requested combination of algorithms,
  • the certificate is expired or revoked,
  • the certificate requires an authorization and no auth_data[ ].value is provided.

The API returns a 403 error (seal.standalone_seal.unavailable) if the standalone seal service is not activated on your workspace, and a 404 error if the LPC does not exist or is not linked to your workspace.

Seal an XML document (XAdES)

You may need to seal an XML document, for example an invoice, a purchase order or any structured data exchanged with a partner. To do so, you can apply a XAdES seal on your XML document.

The API returns the same XML document with an enveloped signature at the XAdES-BASELINE-T level: the signature is added inside the root element of your document, and it contains a qualified timestamp. The root element of your document is preserved.

To seal an XML document, send a multipart/form-data request to POST /v1/sealers/{sealer_id}/xades and pass the document in the file argument.

Note that we accept only XML input format in a maximum size limit of 2MB.

curl
https://api.universign.com/v1/sealers/lpc_wa7ZVZGxzOq0/xades \
-F [email protected] \
--output MyDocument-sealed.xml
  • file: The XML document to seal. The document must be a well-formed XML document.
  • auth_data[ ].value: Set only to authorize the use of a QCP-l-qscd certificate for legal person (LPC). For more details, refer to Seal a document using a QCP-l-qscd certificate.

The API returns a 200 response with the application/xml content type. The body contains your sealed XML document.

Response example (excerpt)

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<PurchaseOrder xmlns="urn:example:purchaseorder:1.0" Id="doc-po-001">
  ...
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="id-dc0560ef...">
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1"/>
      <ds:Reference URI="">...</ds:Reference>
      <ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#xades-id-dc0560ef...">...</ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>...</ds:SignatureValue>
    <ds:KeyInfo>...</ds:KeyInfo>
    <ds:Object>
      <xades:QualifyingProperties Target="#id-dc0560ef...">
        <xades:SignedProperties>
          <xades:SignedSignatureProperties>
            <xades:SigningTime>2026-09-25T14:15:00Z</xades:SigningTime>
            <xades:SigningCertificateV2>...</xades:SigningCertificateV2>
          </xades:SignedSignatureProperties>
          <xades:SignedDataObjectProperties>...</xades:SignedDataObjectProperties>
        </xades:SignedProperties>
        <xades:UnsignedProperties>
          <xades:UnsignedSignatureProperties>
            <xades:SignatureTimeStamp>...</xades:SignatureTimeStamp>
          </xades:UnsignedSignatureProperties>
        </xades:UnsignedProperties>
      </xades:QualifyingProperties>
    </ds:Object>
  </ds:Signature>
</PurchaseOrder>

The XAdES seal uses the same algorithms as the hash signature: RSASSA-PSS with SHA-256. No other algorithm is available.

You can check your sealed XML document with the DSS validation tool of the European Commission.

Errors

The API returns a 400 error when:

  • the file is missing, or exceeds the maximum size limit,
  • the file is not an XML document, or is not a well-formed XML document,
  • the certificate is expired or revoked,
  • the certificate requires an authorization and no auth_data[ ].value is provided.

The API returns a 403 error (seal.standalone_seal.unavailable) if the standalone seal service is not activated on your workspace, and a 404 error if the LPC does not exist or is not linked to your workspace.

Other signature formats, such as JAdES (JSON) and CAdES, will be available soon with the standalone seal service.


Create a webhook endpoint
Transaction templates
Developer tools
Guides
Services
API reference