Password-protect XLSX API
Send a workbook and an EncryptPassword to POST /v2/convert/xlsx/to/protect and get the same workbook back encrypted, so it can't be opened without the password. The sample's 10,832-byte file returns as a 16,384-byte encrypted container.
- Endpoint
- POST /v2/
convert/ xlsx/ to/ protect - Accepts
- xlsx
- Sample timing
- 34 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/xlsx/to/protect \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@tool-library-loans.xlsx \
--form-string EncryptPassword=Maple-Loans-2026 \
-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/xlsx/to/protect",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("tool-library-loans.xlsx", "rb"))],
data={
"EncryptPassword": "Maple-Loans-2026",
},
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 = "tool-library-loans.xlsx";
form.append("File", new Blob([await readFile(file)]), file);
form.append("EncryptPassword", "Maple-Loans-2026");
const url = "https://api.pdfconversionapi.com/v2/convert/xlsx/to/protect";
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.034,
"Files": [
{
"FileName": "tool-library-loans.xlsx",
"FileExt": "xlsx",
"FileSize": 16384,
"FileData": "0M8R4KGxGuEAAAAAAAAAAAAA…"
}
]
}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
- tool-library-loans.xlsx (11 KB)
- Output
- tool-library-loans.xlsx (16 KB)
- Source
- A fictional tool library's September loans workbook (three sheets, one of them hidden, with formulas and a chart) that we wrote for this site (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 |
|---|---|
EncryptPasswordstring | The password needed to open the file. Required: leaving it out or sending it empty returns 400 "EncryptPassword is required". Up to 255 characters; 256 returns 400. Letters outside ASCII work: a workbook locked with Grüße-✓-2026 opened again with that password.Values: 1–255 characters |
FileNamestring | Name of the returned file; the extension stays .xlsx. FileName=loans-locked returns loans-locked.xlsx. |
What carries over, and what doesn't
Kept
- The workbook itself, unchanged inside the encryption: opened with its password, the sample converted to the same 2,902 bytes of JSON as the unencrypted original
- The .xlsx name and extension, so the recipient opens it like any other workbook and is asked for the password
- Office's agile encryption, version 4.4, the format Excel 2010 and later use for a password to open: AES with a 256-bit key in CBC mode, SHA-512 and 100,000 hashing rounds
- A random 16-byte salt per request, so locking the same file twice with the same password gives different bytes
Lost or not yet supported
- Editing restrictions are not added: there is no sheet protection, workbook structure lock or read-only recommendation, only the password to open.
- The output is an encrypted container, not a ZIP package, so tools that read XLSX without supporting passwords can't open it.
- Passwords are case-sensitive, and there is no recovery: with
maple-loans-2026instead ofMaple-Loans-2026the file stays closed.
Limits
- XLSX only. There are no
xls/to/protectorxlsb/to/protectroutes (404); convert an XLS with/v2/convert/xls/to/xlsxfirst. A file that is not a workbook package returns 422 "the input file could not be read: this is not a XLSX file". - An already encrypted workbook needs its current password as
Password: without it the answer is 422 "the input file is password-protected". With it, the workbook is opened and locked again with the newEncryptPassword, which changes its password. - Requests up to 10 MB on the Free plan or 100 MB on paid plans; 120 seconds per conversion before a 504.
Where teams use it
Sending a workbook with salaries or customer data by email
Encrypt the file before it leaves your system and share the password through another channel. Anyone who intercepts the attachment sees only an encrypted container.
A different password for each recipient
Generate the report once, then call the route once per recipient with that person's password, so each copy opens only with its own.
Encrypting exports at the end of a reporting job
Lock the XLSX files your job writes before they are stored on a shared drive or uploaded to a portal.
Questions
How do I open the protected file in my own code?
Any converter here that reads XLSX takes the password as Password. /v2/convert/xlsx/to/json with Password=Maple-Loans-2026 read the sample's encrypted output; with the wrong letter case it returned 422.
Which encryption is used?
ECMA-376 agile encryption, the scheme Excel itself writes: the file's EncryptionInfo is version 4.4 and names AES with a 256-bit key, CBC chaining, SHA-512 hashing with 100,000 rounds and a 16-byte salt, plus an integrity check over the encrypted data.
Is `Password` the same as `EncryptPassword`?
No. Password opens a file that is already protected; EncryptPassword sets the new one. On this route a request with only Password returns 400 "EncryptPassword is required".
How do I remove the password again?
Send the protected file with its Password to /v2/convert/xlsx/to/xlsx; the workbook comes back without encryption.
Convert your first XLSX file in a minute.