DS Server

PDF Documents

Topic

Converting and merging already return PDF when you ask for it. For a PDF that has to meet more requirements, such as PDF/A for an archive, a title and keywords for a document management system, passwords and permissions, a digital signature or attached files, the DocumentProcessing Web API has the pdf/create endpoint. Two more endpoints read an existing PDF: its XMP metadata and the files embedded in it. The sections below show all three with curl and with the .NET package.

How Creating a PDF Works

The endpoint is POST /documentprocessing/pdf/create:

Part of the requestContent
BodyA JSON object, the PDFCreationSettings, with the content type application/json. Its property documentData holds the source document as a Base64 string and is required; all other properties are optional
returnFormatPDF or PDFA. The default is PDF
ResponseThe PDF document as a Base64 string in a JSON string

The source can be any document that DS Server loads, for example a DOCX file or a document in the TX format that the merge endpoint created. When DS Server runs on Linux, the Core build supports DOCX, HTML, PDF and XLSX only, as Limits on Linux lists.

Every request needs an access token, as Authentication describes.

PDF or PDF/A

PDF/A is the PDF format for long-term archiving. DS Server creates one PDF/A conformance level: PDFA creates PDF/A-3b, as the .NET API reference describes the value PDFA of the PDFFormat enumeration. There is no parameter for another level.

You needUse
A PDF or PDF/A with default settingsThe returnFormat PDF or PDFA of Converting Documents, Merging Templates or Appending Documents
Document properties, passwords, permissions, a signature, attached files or JavaScriptpdf/create
A merged document with any of theseMerge with returnFormat=TX, then send the result to pdf/create

The last row is the workflow the Text Control blog describes for a digitally signed PDF in DS Server 1.1 Released: PDF and Barcodes: the merge endpoint returns the document in the TX Text Control format, and pdf/create turns it into the final PDF with all settings. On Linux, the Core build doesn't support the TX format; merge with returnFormat=DOCX there instead.

Create a PDF/A Document With curl

The following commands create a PDF/A document with a title, an author and keywords from document.docx:

DS=http://localhost:5000
TOKEN="<access_token>"

# Build the PDFCreationSettings object around the Base64 string of the document
base64 -w 0 document.docx | jq -Rs '{
  documentData: .,
  documentTitle: "Invoice 4711",
  author: "Accounting",
  documentKeywords: ["invoice", "2026"]
}' > pdf-settings.json

curl --request POST "$DS/documentprocessing/pdf/create?returnFormat=PDFA" \
  --header "Authorization: Bearer $TOKEN" \
  --header "Content-Type: application/json" \
  --data-binary @pdf-settings.json \
  --output pdf.json

# Decode the Base64 string of the response
jq -r . pdf.json | base64 -d > invoice.pdf

The commands work as follows:

  • jq -Rs reads the Base64 text as one string, ., and builds the JSON object around it. Writing the body to a file keeps large documents out of the command line.
  • returnFormat=PDFA creates PDF/A-3b. Leave it out, or set PDF, for a plain PDF.
  • The response is a JSON string. jq -r . removes its quotes, and base64 -d decodes it into the PDF file.

Create a PDF/A Document With .NET

The package TXTextControl.DocumentServices.DocumentProcessing has the PDF methods in its PDF property. The settings are a PDFSettings object, in the namespace TXTextControl.DocumentServices.DocumentProcessing.PDF:

using TXTextControl.DocumentServices.DocumentProcessing;
using TXTextControl.DocumentServices.DocumentProcessing.OAuth;
using TXTextControl.DocumentServices.DocumentProcessing.PDF;

var oauthSettings = new OAuthSettings("<client ID>", "<client secret>");
var documentProcessing = new DocumentProcessing("http://localhost:5000", oauthSettings);

byte[] document = File.ReadAllBytes("document.docx");

var settings = new PDFSettings
{
    DocumentTitle = "Invoice 4711",
    Author = "Accounting",
    DocumentKeywords = new[] { "invoice", "2026" }
};

byte[] pdfA = await documentProcessing.PDF.Create(document, settings, PDFFormat.PDFA);
File.WriteAllBytes("invoice.pdf", pdfA);

The code works as follows:

  • The DocumentProcessing constructor takes the service URL and the credentials of a security profile, and requests an access token.
  • PDFSettings holds the settings of the PDF. It inherits the document properties DocumentTitle, DocumentSubject, Author, CreatorApplication, CreationDate, LastModificationDate and UserPassword from DocumentSettings.
  • PDF.Create takes the document as a byte array, the settings and a PDFFormat value, PDF or PDFA, and returns the PDF as a byte array.

The classes are listed in the DocumentProcessing namespace of the .NET API.

Set the PDF Options

The properties of the JSON body and of PDFSettings correspond:

JSON propertyPDFSettingsContent
documentTitle, documentSubjectDocumentTitle, DocumentSubjectThe title and the subject, each up to 2,000 characters in a PDF
documentKeywordsDocumentKeywordsThe keywords, as an array of strings
author, creatorApplicationAuthor, CreatorApplicationThe author and the application that created the document
creationDate, lastModificationDateCreationDate, LastModificationDateThe dates saved in the document, in JSON as date-time strings such as "2026-09-29T10:00:00Z"
userPasswordUserPasswordThe password a reader needs to open the document
masterPasswordMasterPasswordThe password that protects the access permissions
documentAccessPermissionsDocumentAccessPermissionsWhat a reader may do with the document, see Protect a PDF With Passwords
imageCompressionQualityImageCompressionQualityThe compression quality of images, from 1 to 100
documentLevelJavaScriptActionsDocumentLevelJavaScriptActionsJavaScript actions embedded in the PDF, as an array of strings
embeddedFilesEmbeddedFilesFiles attached to the PDF, see Read the Embedded Files for their properties
digitalSignatureDigitalSignatureThe certificate to sign the PDF with, see Sign the PDF

The attached files go in embeddedFiles, an array, and their dates are date-time strings. DS Server ignores a property it doesn't know without an error, so a misspelled name such as embeddedFile leaves the PDF without attachments.

Protect a PDF With Passwords

A reader needs the user password to open the document. The master password protects the access permissions, which only have an effect when a master password is set. The permissions and their values are:

ValueNumberAllows
None0None of the permissions
AllowAuthoring1Adding comments and filling in form fields, including signature fields
AllowAuthoringFields2Filling in existing form fields, including signature fields
AllowContentAccessibility4Extracting content for the visually impaired only
AllowDocumentAssembly8Inserting, rotating and deleting pages and creating bookmarks and thumbnails
AllowExtractContents16Copying or otherwise extracting text and graphics
AllowGeneralEditing32Changing the content of the document
AllowHighLevelPrinting64Printing, fully allowed
AllowLowLevelPrinting128Printing, low-level
AllowAll255All of the permissions

In JSON, documentAccessPermissions is a number: add the numbers of the permissions you allow. A name such as "AllowAll" is refused with 400 and the error "The JSON value could not be converted". The following body creates a PDF that everyone can open and print, but not change:

base64 -w 0 document.docx | jq -Rs '{
  documentData: .,
  masterPassword: "<owner password>",
  documentAccessPermissions: 68
}' > pdf-settings.json

68 is AllowHighLevelPrinting (64) plus AllowContentAccessibility (4). Send the file to pdf/create as in Create a PDF/A Document With curl. In C#, combine the values of the DocumentAccessPermissions enumeration, which is in the PDF namespace, with the | operator:

var settings = new PDFSettings
{
    MasterPassword = "<owner password>",
    DocumentAccessPermissions = DocumentAccessPermissions.AllowHighLevelPrinting |
                                DocumentAccessPermissions.AllowContentAccessibility
};

byte[] pdf = await documentProcessing.PDF.Create(document, settings, PDFFormat.PDF);

Add a userPassword or UserPassword to require a password for opening the document as well.

Sign the PDF

pdf/create signs the PDF with an X.509 certificate that you send with the request:

  • JSON. digitalSignature is an object with x509Certificate2, the certificate as a string, password, the password of the certificate, and the optional timeServerURL, the URL of a time server.
  • .NET. PDFSettings.DigitalSignature takes a DigitalSignature object with the properties Certificate, an X509Certificate2, Password and TimeServerURL.

The certificate and its password travel to DS Server with every request, so send them over HTTPS only, as HTTPS sets it up.

Read the Metadata of a PDF

POST /documentprocessing/pdf/metadata returns the metadata of a PDF document as a JSON string. In the example of the endpoint reference, the string is an XMP packet, the XML format of PDF metadata:

base64 -w 0 invoice.pdf | jq -Rs . > invoice.json

curl --request POST "$DS/documentprocessing/pdf/metadata" \
  --header "Authorization: Bearer $TOKEN" \
  --header "Content-Type: application/json" \
  --data-binary @invoice.json \
  | jq -r . > metadata.xml

The body is the PDF as a Base64 string in a JSON string. jq -r . turns the JSON string into the XML text. A PDF without metadata is answered with 400 Bad Request. In C#, PDF.GetMetaData returns the same string:

string metadata = await documentProcessing.PDF.GetMetaData(File.ReadAllBytes("invoice.pdf"));

Read the Embedded Files

POST /documentprocessing/pdf/embeddedfiles returns the files attached to a PDF, such as the XML invoice data of an electronic invoice. The body is the PDF as a Base64 string, and the response an array of EmbeddedFile objects:

PropertyContent
fileNameThe file name of the attachment
dataThe content of the file. In the example of the endpoint reference, it is a Base64 string and dataType is BASE64BINARY
dataTypeThe type of data
mimeTypeThe MIME type, such as application/pdf
descriptionThe description of the attachment
relationshipThe relationship of the file to the PDF
creationDate, lastModificationDateThe dates of the file
metadataThe metadata of the file

The following commands save each attachment of invoice.pdf under its file name:

curl --request POST "$DS/documentprocessing/pdf/embeddedfiles" \
  --header "Authorization: Bearer $TOKEN" \
  --header "Content-Type: application/json" \
  --data-binary @invoice.json \
  --output attachments.json

count=$(jq length attachments.json)
for i in $(seq 0 $((count - 1))); do
  name=$(jq -r ".[$i].fileName" attachments.json)
  jq -r ".[$i].data" attachments.json | base64 -d > "$(basename "$name")"
done

In C#, PDF.GetEmbeddedFiles returns an array of EmbeddedFile objects, in the PDF namespace:

byte[] pdf = File.ReadAllBytes("invoice.pdf");
EmbeddedFile[] files = await documentProcessing.PDF.GetEmbeddedFiles(pdf);

foreach (EmbeddedFile file in files)
{
    Console.WriteLine($"{file.FileName} ({file.MIMEType})");
    File.WriteAllBytes(Path.GetFileName(file.FileName), Convert.FromBase64String(file.Data));
}

Path.GetFileName and basename keep a file name from the PDF from writing outside the current folder. A PDF whose attachments your application doesn't know is outside input; check the names and types before you use the files.

Next Steps