# Appending Documents

> Put a cover letter in front of an invoice or join reports into one PDF with the append endpoint: AppendDocument, section dividers and document properties.

- **Product:** DS Server
- **Section:** Documentation
- **Kind:** Topic
- **Path:** DS Server > Document Processing > Appending Documents
- **2144 words**
- **Web URL:** https://docs.textcontrol.com/ds-server/document-processing/appending/
- **LLMs URL:** https://docs.textcontrol.com/ds-server/document-processing/appending/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/ds-server/document-processing/appending/llms-full.txt

---

A cover letter in front of an invoice, terms and conditions after a contract, a set of reports in one PDF: the append endpoint of the DocumentProcessing Web API combines several documents into one. You list the documents in order, choose for each how it is separated from the one before it, and receive the combined document in the format you need.

### How Appending Works

The endpoint is [POST /documentprocessing/document/append](https://docs.textcontrol.com/ds-server/reference/web-api/documentprocessing/document-append/post/llms-full.txt). Its JSON body, the `AppendBody`, has two properties:

| Property | Content |
|---|---|
| `documents` | An array of `AppendDocument` objects in the order they are appended. Required |
| `documentSettings` | Optional. The document properties of the result, listed in [Set the Document Properties](#set-the-document-properties) |

Each `AppendDocument` has these properties:

| Property | Content |
|---|---|
| `document` | The document as a Base64 string. Required |
| `documentDivider` | Optional. What separates this document from the one before it, as a number: `1` nothing, `2` a new paragraph, `3` a new section |

The query parameter `returnFormat` sets the format of the result: `PDF`, `PDFA`, `DOCX`, `DOC`, `RTF`, `HTML`, `TX` or `TXT`, with `PDF` as the default. The response is the combined document as a Base64 string in a JSON string. A body without documents is refused with `400`.

Every request needs an access token, as [Authentication](https://docs.textcontrol.com/ds-server/document-processing/authentication/llms-full.txt) describes. The samples use the service URL `http://localhost:5000` and the token in the variable `TOKEN`.

### Append Documents With curl

The following commands put *document.docx*, a cover letter, in front of *invoice.pdf* and start the invoice in a new section:

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

# Build the AppendBody from the two documents
jq -n \
  --rawfile first <(base64 -w 0 document.docx) \
  --rawfile second <(base64 -w 0 invoice.pdf) \
  '{documents: [{document: $first}, {document: $second, documentDivider: 3}]}' > append.json

curl --request POST "$DS/documentprocessing/document/append?returnFormat=PDF" \
  --header "Authorization: Bearer $TOKEN" \
  --header "Content-Type: application/json" \
  --data-binary @append.json \
  --output appended.json

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

The commands work as follows:

- Each `--rawfile` reads the Base64 string of one file into a `jq` variable, and the filter writes the `documents` array with them to *append.json*.
- The first document needs no divider. `documentDivider: 3` on the second one inserts a new section before it.
- `jq -r .` removes the quotes of the response, and `base64 -d` decodes the combined document.

### Append Documents With .NET

In the package `TXTextControl.DocumentServices.DocumentProcessing`, the body is an `AppendBody` with an array of `AppendDocument` objects:

```csharp
using TXTextControl.DocumentServices.DocumentProcessing;
using TXTextControl.DocumentServices.DocumentProcessing.OAuth;

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

var appendBody = new AppendBody
{
    Documents = new[]
    {
        new AppendDocument { Document = await File.ReadAllBytesAsync("document.docx") },
        new AppendDocument
        {
            Document = await File.ReadAllBytesAsync("invoice.pdf"),
            DocumentDivider = DocumentDivider.NewSection
        }
    }
};

byte[] combined = await documentProcessing.Append(appendBody, ReturnFormat.PDF);
await File.WriteAllBytesAsync("combined.pdf", combined);
```

The code works as follows:

- `AppendDocument.Document` takes a document as a byte array; the package encodes it.
- `DocumentDivider` takes the values `None`, `NewParagraph` and `NewSection` of the enumeration of the same name.
- `Append` returns the combined document as a byte array. The overload without a `ReturnFormat` takes the `AppendBody` alone and creates PDF.

### Choose the Divider

The divider decides how a document continues the one before it:

| `documentDivider` | .NET value | Effect |
|---|---|---|
| `1` | `DocumentDivider.None` | No divider is inserted between the documents |
| `2` | `DocumentDivider.NewParagraph` | A new paragraph is inserted between the documents |
| `3` | `DocumentDivider.NewSection` | A new section is inserted between the documents |

A section is a part of a document with its own page settings, such as the page size, the margins and the headers and footers. [Sections](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/sections/llms-full.txt) of TX Text Control .NET Server explains how sections divide a document.

### Set the Document Properties

The optional `documentSettings` object sets the properties of the combined document:

| Setting | Effect |
|---|---|
| `documentTitle` | The title. In PDF, limited to 2,000 characters |
| `documentSubject` | The subject. In PDF, limited to 2,000 characters |
| `author` | The author |
| `creatorApplication` | The application that created the document |
| `creationDate`, `lastModificationDate` | The dates saved in the document, as ISO 8601 date strings such as `"2026-09-29"` |
| `userPassword` | The password needed to open the document |

Add the object to the filter of the `jq` command:

```bash
jq -n \
  --rawfile first <(base64 -w 0 document.docx) \
  --rawfile second <(base64 -w 0 invoice.pdf) \
  '{
    documents: [{document: $first}, {document: $second, documentDivider: 3}],
    documentSettings: {documentTitle: "Invoice", author: "Sales Department"}
  }' > append.json
```

In C#, set the `DocumentSettings` property of the `AppendBody` to a `DocumentSettings` object with the properties `DocumentTitle`, `DocumentSubject`, `Author`, `CreatorApplication`, `CreationDate`, `LastModificationDate` and `UserPassword`:

```csharp
appendBody.DocumentSettings = new DocumentSettings
{
    DocumentTitle = "Invoice",
    Author = "Sales Department"
};
```

### Combine Merged Documents

The documents to append can come from other endpoints. For example, merge a template with the [merge endpoint](https://docs.textcontrol.com/ds-server/document-processing/mail-merge/llms-full.txt) in the `TX` format, then append a cover letter in front of the merged document and create the PDF in the same request. Each document in the response of the merge endpoint is a Base64 string, so it goes into the `document` property of an `AppendDocument` as it is.

### Next Steps

- [Merging Templates](https://docs.textcontrol.com/ds-server/document-processing/mail-merge/llms-full.txt): create the documents to combine from a template and data.
- [Converting Documents](https://docs.textcontrol.com/ds-server/document-processing/converting/llms-full.txt): convert a single document to another format.
- [Thumbnails](https://docs.textcontrol.com/ds-server/document-processing/thumbnails/llms-full.txt): render page images of the combined document.
- [Errors and Status Codes](https://docs.textcontrol.com/ds-server/document-processing/errors/llms-full.txt): what to do when a request is refused.

---

## Nearby

- **Previous:** [Merging Templates](https://docs.textcontrol.com/ds-server/document-processing/mail-merge/llms-full.txt)
- **Next:** [Find and Replace](https://docs.textcontrol.com/ds-server/document-processing/find-replace/llms-full.txt)
