# Find and Replace

> Fill templates that have text markers instead of merge fields with document/findandreplace: search and replacement pairs, stored templates, curl and .NET.

- **Product:** ReportingCloud
- **Section:** Documentation
- **Kind:** Topic
- **Path:** ReportingCloud > Document Processing > Find and Replace
- **2248 words**
- **Web URL:** https://docs.textcontrol.com/reporting-cloud/document-processing/find-replace/
- **LLMs URL:** https://docs.textcontrol.com/reporting-cloud/document-processing/find-replace/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/reporting-cloud/document-processing/find-replace/llms-full.txt

---

Some templates mark the places to fill with plain text, such as `%%CustomerName%%`, instead of merge fields, for example templates that come from an older application. `POST /v1/document/findandreplace` fills such a template without redesigning it: you send a list of text pairs, and ReportingCloud replaces every occurrence of each search text with its replacement, in the main text, the headers and footers and the text frames, and returns the result in the format you choose.

### How Find and Replace Works

The endpoint is [POST /v1/document/findandreplace](https://docs.textcontrol.com/reporting-cloud/reference/web-api/document/findandreplace/post/llms-full.txt). It takes three query parameters:

| Parameter | Content |
|---|---|
| `returnFormat` | Optional. The format of the result: `PDF`, `PDFA`, `RTF`, `DOC`, `DOCX`, `HTML`, `TXT` or `TX`, in any letter case. Without it, the result is PDF |
| `templateName` | Optional. The name of a template in your template storage. Without it, the template travels in the body |
| `test` | Optional. `true` sends a test run, which creates a document with a "TEST MODE" watermark and, on a trial account, counts against the document quota. [Test mode](https://docs.textcontrol.com/reporting-cloud/overview/licensing/#test-mode) is not available with a Free account |

Its JSON body, the `FindAndReplaceBody`, has three properties:

| Property | Content |
|---|---|
| `findAndReplaceData` | Required. An array of pairs, each an array of two strings: the text to find and the text that replaces it |
| `template` | The template as a Base64 string, in the format RTF, DOC, DOCX, TX, HTML, PDF, XLSX or plain text. Required when `templateName` is not set |
| `mergeSettings` | Optional. Properties of the result, described in [Set the Document Properties](#set-the-document-properties) |

The search ignores letter case and also finds a search text inside a word, so choose placeholders that occur nowhere else in the text, such as `%%CustomerName%%`. An empty replacement deletes the search text, and an empty search text is refused.

The response is the changed document as a Base64 string in a JSON string. The Web API answers `400 Bad Request` when the body has no data, when neither a template nor a template name is given, or when the named template is not in the storage.

Every successful request adds one document to the document quota; [Plans and Licensing](https://docs.textcontrol.com/reporting-cloud/overview/licensing/llms-full.txt) lists the quota of each plan. Every request also needs the `Authorization` header that [Authentication](https://docs.textcontrol.com/reporting-cloud/document-processing/authentication/llms-full.txt) describes.

### Find and Replace or Merge

Both endpoints fill a template with data. Which one fits depends on the template:

|  | findandreplace | merge |
|---|---|---|
| Placeholders in the template | Any text | Merge fields, merge blocks and image placeholders |
| Data | Pairs of strings | JSON records with nested objects and arrays |
| Repeating sections, such as table rows | No | Merge blocks |
| Documents per request | One | One per record, or all records appended into one |

Use find and replace for existing documents with text placeholders, and [Mail Merge](https://docs.textcontrol.com/reporting-cloud/mail-merge/llms-full.txt) for templates designed with merge fields in the template editor.

### Replace Text With curl

*contract.docx* contains the placeholders `%%CustomerName%%` and `%%Date%%`. The following commands send the document with the replacements and save the result as *contract.pdf*:

```bash
# Build the FindAndReplaceBody from the document and the text pairs
jq -n \
  --rawfile template <(base64 -w 0 contract.docx) \
  '{
    template: $template,
    findAndReplaceData: [
      ["%%CustomerName%%", "Joey Montana"],
      ["%%Date%%", "October 2, 2026"]
    ]
  }' > replace.json

curl "https://api.reporting.cloud/v1/document/findandreplace?returnFormat=PDF" \
  -H "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @replace.json \
  --output replaced.json

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

The commands work as follows:

- `--rawfile template` reads the Base64 string of the document into the variable `$template`.
- `findAndReplaceData` lists the pairs. The first string of each pair is the text to find, and the second is its replacement.
- `jq -r .` removes the quotes of the response, and `base64 -d` decodes the PDF.

### Use a Template From the Storage

A template that you use again and again can stay in your template storage. Upload it once, in the portal or with the upload endpoint that [Managing Templates](https://docs.textcontrol.com/reporting-cloud/document-processing/templates/llms-full.txt) describes, and name it in `templateName`. A stored template is RTF, DOC, DOCX or TX. The body then holds the pairs alone:

```bash
curl "https://api.reporting.cloud/v1/document/findandreplace?templateName=contract.docx&returnFormat=PDF" \
  -H "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"findAndReplaceData": [["%%CustomerName%%", "Joey Montana"], ["%%Date%%", "October 2, 2026"]]}' \
  --output replaced.json
```

The template in the storage stays unchanged: the replacements apply to the document that the request returns. When a request names a stored template and also sends one in the body, the stored template is used.

### Replace Text With .NET

In the .NET SDK, the NuGet package `TXTextControl.ReportingCloud`, the pairs are a list of string arrays in a `FindAndReplaceBody`:

```csharp
using TXTextControl.ReportingCloud;

ReportingCloud rc = new ReportingCloud(
    Environment.GetEnvironmentVariable("REPORTINGCLOUD_API_KEY"));

FindAndReplaceBody body = new FindAndReplaceBody
{
    Template = File.ReadAllBytes("contract.docx"),
    FindAndReplaceData = new List<string[]>
    {
        new[] { "%%CustomerName%%", "Joey Montana" },
        new[] { "%%Date%%", "October 2, 2026" }
    },
    MergeSettings = new MergeSettings { DocumentTitle = "Contract" }
};

// No template name: the template travels in the body
byte[] pdf = rc.FindAndReplaceDocument(body, null, ReturnFormat.PDF);
File.WriteAllBytes("contract.pdf", pdf);
```

The code works as follows:

- `Template` takes the document as a byte array; the SDK encodes it. For a template from the storage, leave `Template` empty and pass the name as the second argument, `rc.FindAndReplaceDocument(body, "contract.docx", ReturnFormat.PDF)`.
- `FindAndReplaceData` holds the pairs, each a `string[]` with the text to find and its replacement.
- `MergeSettings` sets the title of the result, as the next section describes.
- `FindAndReplaceDocument` returns the changed document as a byte array. A fourth argument, `test`, sends a test run. A refused request throws an `ArgumentException` whose message is the response body.

The PHP SDK has the same call as `findAndReplaceDocument($findAndReplaceData, $returnFormat, $templateName, $templateFilename, $mergeSettings)`. It takes the pairs as an associative array, `['%%CustomerName%%' => 'Joey Montana']`, and either a template name or the path of a template file.

### Set the Document Properties

`mergeSettings` takes the `MergeSettings` object of the merge endpoint. Its document properties set the properties of the result: `author`, `documentTitle`, `documentSubject`, `creatorApplication`, `creationDate`, `lastModificationDate` and `userPassword`, the password a user must enter to open the document. The setting `mergeHtml` works with the merge endpoint only. [Merge Settings](https://docs.textcontrol.com/reporting-cloud/mail-merge/settings/llms-full.txt) describes every setting of the object.

The following body creates a document with a title and a password:

```bash
jq -n \
  --rawfile template <(base64 -w 0 contract.docx) \
  '{
    template: $template,
    findAndReplaceData: [["%%CustomerName%%", "Joey Montana"]],
    mergeSettings: {documentTitle: "Contract", userPassword: "<password>"}
  }' > replace.json
```

### Next Steps

- [Mail Merge](https://docs.textcontrol.com/reporting-cloud/mail-merge/llms-full.txt): fill templates with merge fields and repeating merge blocks.
- [Managing Templates](https://docs.textcontrol.com/reporting-cloud/document-processing/templates/llms-full.txt): upload a template to the storage and use it by name.
- [Appending Documents](https://docs.textcontrol.com/reporting-cloud/document-processing/appending/llms-full.txt): add the filled document to other documents.
- [Errors and Status Codes](https://docs.textcontrol.com/reporting-cloud/document-processing/errors/llms-full.txt): what to do when a request is refused.

---

## Nearby

- **Previous:** [Appending Documents](https://docs.textcontrol.com/reporting-cloud/document-processing/appending/llms-full.txt)
- **Next:** [Thumbnails](https://docs.textcontrol.com/reporting-cloud/document-processing/thumbnails/llms-full.txt)
