LOG to DOCX API
POST /v2/convert/log/to/docx turns a log file into a Word document, one paragraph per log line, so people can highlight, comment on and redact entries in Word. The sample's 23 lines become 24 paragraphs; the last one is empty, after the final line break.
- Endpoint
- POST /v2/
convert/ log/ to/ docx - Accepts
- log
- Sample timing
- 29 ms median of 5 runsHow we measure
- Request size
- Up to 10 MB on the Free plan or 100 MB on paid plans, all files together
Request and response
Every sample below ran against the API before this page was published. Set PDFCONVERSIONAPI_KEY to your key and run it as is.
curl -sS -X POST \
https://api.pdfconversionapi.com/v2/convert/log/to/docx \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@invoice-worker.log \
-o response.json
# FileData is base64. Save the first file in converted/,
# or print the JSON error.
if jq -e '.Files' response.json > /dev/null; then
mkdir -p converted
name=$(jq -r '.Files[0].FileName' response.json)
jq -r '.Files[0].FileData' response.json \
| base64 --decode > "converted/$name"
else
cat response.json
fiimport base64
import os
import requests
key = os.environ["PDFCONVERSIONAPI_KEY"]
response = requests.post(
"https://api.pdfconversionapi.com/v2/convert/log/to/docx",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("invoice-worker.log", "rb"))],
timeout=180,
)
result = response.json()
if not response.ok:
raise SystemExit(f"{result['Code']}: {result['Message']}")
os.makedirs("converted", exist_ok=True)
for file in result["Files"]:
path = os.path.join("converted", file["FileName"])
with open(path, "wb") as out:
out.write(base64.b64decode(file["FileData"]))
print(path, file["FileSize"], "bytes")
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
const form = new FormData();
const file = "invoice-worker.log";
form.append("File", new Blob([await readFile(file)]), file);
const url = "https://api.pdfconversionapi.com/v2/convert/log/to/docx";
const key = process.env.PDFCONVERSIONAPI_KEY;
const response = await fetch(url, {
method: "POST",
headers: { Authorization: `Bearer ${key}` },
body: form,
});
const result = await response.json();
if (!response.ok) {
throw new Error(`${result.Code}: ${result.Message}`);
}
await mkdir("converted", { recursive: true });
for (const file of result.Files) {
const path = join("converted", file.FileName);
await writeFile(path, Buffer.from(file.FileData, "base64"));
console.log(path, file.FileSize, "bytes");
}
{
"ConversionCost": 1,
"ConversionTime": 0.029,
"Files": [
{
"FileName": "invoice-worker.docx",
"FileExt": "docx",
"FileSize": 7439,
"FileData": "UEsDBBQAAAAIAAAAIQB4NDMq…"
}
]
}Response from our test run on 2026-11-03. ConversionTime shows the median of 5 runs. FileData is shortened here; the real response carries the whole file as base64.
The sample, converted
The same file the code sends. Download the input and the output and compare them yourself.

- Input
- invoice-worker.log (2.1 KB)
- Output
- invoice-worker.docx (7.3 KB)
- Source
- A log from a fictional invoice service, written by us: 23 lines with a stack trace and a long JSON line (CC0-1.0). How it was made
- Made by
- 2026-11-04, API build
9eeeb0640aba
Parameters
Send these as form fields next to the file. Names are case-insensitive. If you set one of the documented options below that we don't support yet, the request fails with a 400 that names it instead of returning a file made without it.
| Parameter | What it does |
|---|---|
FileNamestring | Base name of the DOCX; without it the log's name is used, as in invoice-worker.docx. |
StoreFileboolean, default false | Answer with a 3-hour download link instead of the document. |
What carries over, and what doesn't
Kept
- Each log line as its own paragraph, in order, with nothing merged or dropped
- Leading spaces, kept as typed: ' at RenderPool.acquire (render/pool.js:88:13)' keeps its 4 spaces
- Long lines as single paragraphs; the 216-character line with the JSON event is one paragraph that Word wraps on screen
- Characters such as € from the UTF-8 log
- Letter paper with 1 in margins
Lost or not yet supported
- A fixed-width font. The default font is Aptos 12 pt, so fields that line up in a terminal do not line up in Word.
- Log structure: timestamps, levels and messages are plain text in Normal paragraphs, not table columns, and ERROR lines are not highlighted.
- Compactness: Word's default 8 pt space after each paragraph applies to every log line.
Limits
- Options for page size, fonts or PDF are not read on this route and are ignored.
- One log per request, up to 10 MB on the Free plan or 100 MB on paid plans with all fields. A conversion can run for up to 120 seconds; after that the API returns 504.
Where teams use it
Annotating logs in a review
Put a log in front of reviewers who work in Word: they can highlight the failing request, add comments and track changes, which a .log file can't hold.
Redacting before sharing
Remove account numbers or addresses from an entry in Word, then send the edited document, or a PDF of it, to a customer or vendor.
Questions
Will each log entry be one paragraph?
Each line is. A multi-line entry, like an exception with a stack trace, becomes one paragraph per line: the sample's ERROR entry and its three stack frames are four paragraphs.
Can I get the log as a table with columns?
Not from this route. Logs have no column markup the converter could rely on, so every line stays a paragraph. Parse the log in your code and build a CSV, then convert it with /v2/convert/csv/to/xlsx if you need columns.
Which encodings work?
UTF-8, with or without a byte order mark, and UTF-16 with one. A log in an older code page is recognized from its bytes rather than assumed to be Windows-1252: our test logs in Windows-1252 (café, €), Windows-1251 (Russian) and Windows-1250 (Polish) all came through as written.
Convert your first LOG file in a minute.