Secure Your Documents: Batch Password Protection for GDPR Compliance
Under GDPR, emailing unprotected payslips or medical records is a compliance risk. A single data breach can result in fines up to 4% of annual revenue. The solution? Automatically encrypt each document with a user-specific password before sending.
In this tutorial, we will use the Apdf Security API to batch-protect sensitive PDFs with individual passwords. Each employee gets their payslip locked with their employee ID. Each patient gets their records locked with their date of birth.
The Quick Solution
const data = new FormData();
data.append('file', 'https://your-server.com/payslip.pdf');
data.append('owner_password', 'admin-secret-123');
data.append('user_password', 'EMP-4521'); // Employee ID as password
fetch('https://apdf.io/api/pdf/security/add', {
headers: {
'Authorization': 'Bearer YOUR_API_TOKEN',
'Accept': 'application/json'
},
method: 'POST',
body: data
})
.then(response => response.json())
.then(result => {
console.log('Protected PDF:', result.file);
});
The API returns a URL to the password-protected PDF. Simple as that.
Understanding Owner vs User Password
PDF encryption supports two password types:
- Owner Password (required) - Used for encryption and setting restrictions. Keep this secret on your server.
- User Password (optional) - Required to open and view the PDF. This is what you share with the recipient.
For GDPR compliance, always set a user_password. Without it, the PDF
can still be opened by anyone who gets the link.
Step 1: Get Your API Token
- Sign up at Apdf (it is free).
- Copy your API Token from the dashboard.
Step 2: Batch Processing Multiple Documents
Real-world payroll processing means protecting hundreds of documents at once. Here is a complete Node.js script that processes an array of employees:
const API_TOKEN = 'YOUR_API_TOKEN_HERE';
const API_URL = 'https://apdf.io/api/pdf/security/add';
const OWNER_PASSWORD = 'company-admin-secret-2025';
// Employee data - in production, this comes from your HR system
const employees = [
{ id: 'EMP-4521', name: 'John Smith', payslipUrl: 'https://your-server.com/payslips/john.pdf' },
{ id: 'EMP-4522', name: 'Jane Doe', payslipUrl: 'https://your-server.com/payslips/jane.pdf' },
{ id: 'EMP-4523', name: 'Bob Wilson', payslipUrl: 'https://your-server.com/payslips/bob.pdf' }
];
async function protectPayslip(employee) {
const data = new FormData();
data.append('file', employee.payslipUrl);
data.append('owner_password', OWNER_PASSWORD);
data.append('user_password', employee.id); // Employee ID as password
const response = await fetch(API_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Accept': 'application/json'
},
body: data
});
if (!response.ok) {
throw new Error(`Failed for ${employee.name}: HTTP ${response.status}`);
}
return response.json();
}
async function processBatch() {
console.log(`Processing ${employees.length} payslips...\n`);
for (const employee of employees) {
try {
const result = await protectPayslip(employee);
console.log(`[OK] ${employee.name}`);
console.log(` Password: ${employee.id}`);
console.log(` Protected PDF: ${result.file}\n`);
} catch (error) {
console.error(`[FAILED] ${employee.name}: ${error.message}\n`);
}
}
console.log('Batch processing complete.');
}
processBatch();
Note: The protected PDF URLs are valid for 1 hour. Download or email them promptly after generation.
Real-World Example: Medical Records
For healthcare, use the patient's date of birth as the password. It is something they know, and it is unique enough for document security:
const patients = [
{ name: 'Alice Brown', dob: '1985-03-15', recordUrl: 'https://clinic.com/records/alice.pdf' },
{ name: 'Charlie Green', dob: '1990-07-22', recordUrl: 'https://clinic.com/records/charlie.pdf' }
];
// Password format: DDMMYYYY (European) or MMDDYYYY (US)
function formatPassword(dob) {
const [year, month, day] = dob.split('-');
return `${day}${month}${year}`; // Returns "15031985" for 1985-03-15
}
async function protectMedicalRecord(patient) {
const data = new FormData();
data.append('file', patient.recordUrl);
data.append('owner_password', 'clinic-admin-secret');
data.append('user_password', formatPassword(patient.dob));
const response = await fetch('https://apdf.io/api/pdf/security/add', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Accept': 'application/json'
},
body: data
});
return response.json();
}
API Response
The API returns the URL of the protected PDF along with its expiration time:
{
"file": "https://apdf-files.s3.eu-central-1.amazonaws.com/a1b2c3d4.pdf",
"expiration": "2025-01-15T14:30:00.000000Z"
}
The protected PDF can be opened only by entering the user password you specified.
GDPR Compliance Checklist
Password-protecting documents is just one part of GDPR compliance. Here is a quick checklist:
- Encryption: Always use the
user_passwordparameter. - Unique Passwords: Use employee IDs, patient IDs, or dates of birth - not generic passwords.
- Secure Transmission: Share passwords through a separate channel (SMS, secure portal).
- Audit Trail: Log when documents were protected and sent.
Conclusion
Automating PDF password protection removes human error from your compliance workflow. With the Apdf Security API, you can process hundreds of sensitive documents in minutes, each with its own unique password.
No more manual encryption. No more compliance anxiety. Just secure documents, automatically.
Next Steps
- Split Bulk Documents First: If your payslips come in a single bulk PDF, use the Split endpoint to separate them before protection.
- Add Watermarks: Mark documents as "Confidential" using the Overlay endpoint.
Related tutorials
Password-Protect PDFs in an Agent Workflow
Encryption as a step the agent runs, not a desktop-tool detour: lock a client statement with owner and user passwords, have the agent probe the result to prove the lock held (encrypted: true, everything else hidden), and unlock the archive copy in the same conversation.
Search a PDF From Your Editor
The integration spec is a PDF and your questions arrive mid-function. With the editor connected over MCP, 'what's the retry policy?' comes back with the exact line and page — and a regex search turns 'list every error code' into one call with three cited matches.
Watermark Draft PDFs via Claude Before Sharing
The draft that leaks is the one you didn't stamp. Conversationally it's one message: the agent designs the translucent DRAFT — CONFIDENTIAL stamp itself with the PDF generator, overlays it across every page, renders a page to prove it looks right — and mints one named copy per reviewer.
Your code made the PDF.
Then it went dark.
Opened, read, re-read, dropped on page 4 — you never see any of it. Share the PDFs you generate through Apdf recipient links, and every signal becomes something you can act on: ping Slack, update the CRM, let an agent follow up. Same account, same API token, one more call.
API · Webhook · MCP