DEV Community

PDF4me
PDF4me

Posted on

Five Platforms, Five Different Ways to Password-Protect the Same PDF

A PDF password feature sounds like it should take the same two inputs everywhere: a password, and a setting for what stays allowed once the file is open. PDF4me exposes that feature through five surfaces, the REST API and four no-code connectors, and no two of them ask for it the same way. Some split the password into two separate fields. Some list a different number of permission options, under different names, than the others. One drops the permission choice entirely. Build against one surface and assume a second is a thin wrapper around the same shape, and the first integration attempt will prove that assumption wrong.

Two locks on REST, and a naming gap worth catching early

Protect Document (POST /api/v2/Protect) takes a password, which gates whether the file opens at all, and a pdfPermission value, which gates what happens after it opens. They are separate locks doing separate jobs. The docs page flags pdfPermission as an allow-list rather than a deny-list: naming Fill Forms opens exactly that one door and closes every other one, printing and copying included, not just the specific action a developer meant to restrict. Check the request against the eight documented values (All, None, Copy, Annotate, Fill Forms, Support Disabilities, Assemble, Digital Print) rather than assuming a short list behaves like a checklist of things to block.

There is a second gap on this same endpoint, easy to miss and cheap to fix. The docs page's parameter table labels the async flag async, but the official Python sample in pdf4me-api-samples sends it as isAsync in the actual request payload. Code built against the table's field name instead of the sample's working payload will silently fail to trigger async processing. A call built from the verified payload shape looks like this:

import requests
import base64

with open("confidential.pdf", "rb") as f:
    doc_content = base64.b64encode(f.read()).decode()

payload = {
    "docContent": doc_content,
    "docName": "confidential.pdf",
    "password": "Str0ng-P@ss!",    "pdfPermission": "Fill Forms",
    "isAsync": False
}

response = requests.post(
    "https://api.pdf4me.com/api/v2/Protect",
    headers={
        "Content-Type": "application/json",
        "Authorization": "Basic YOUR_API_KEY"
    },
    json=payload
)

with open("protected.pdf", "wb") as f:
    f.write(response.content)
Enter fullscreen mode Exit fullscreen mode

A synchronous call returns the encrypted PDF as raw binary bytes, not a JSON wrapper, which is why the code above writes response.content straight to disk. Setting isAsync to true instead returns an HTTP 202 with a Location header to poll, worth using for larger files. The encryption itself is AES, at 128-bit or 256-bit strength depending on the PDF specification's own rules for the permission set chosen, applied automatically rather than picked by the caller. That is a capability fact, not a compliance claim: the endpoint encrypts the file and certifies nothing about how it is used afterward.

Unlock PDF (POST /api/v2/Unlock) is the other half of the pair, and PDF4me's own "Related actions" copy calls it exactly that: the inverse of Protect, for removing a password already known. It is not a recovery tool. Feed it the wrong password and it fails. Feed it the right one, whether that password was originally set as an opening password or a permissions password, and the returned PDF drops both kinds of restriction in one pass. The REST Unlock page is noticeably thinner than Protect's own: no "Important Facts" callout, no FAQ, and its API Tester page is a plain three-field form (docContent, docName, password) next to Protect's more built-out API Tester.

Five surfaces, five shapes

This is where the real divergence lives, and it is not documented anywhere as a single comparison.

Surface Password fields Permission enum
REST API 1 (password) 8 values
Power Automate 1 (Password) 9 values (adds "Print and Modify")
n8n 1 (Password) 7 values, renamed (no None, no Support Disabilities)
Make 2 (User + Owner) 8 values, matches REST exactly
Zapier 2 (User + Owner) none

Protect Document in Power Automate keeps REST's shape closely: one Password field, one permission selector. But that selector carries nine values instead of eight, adding Print and Modify as a preset that exists nowhere else in this feature's documentation. Unlock PDF in Power Automate mirrors REST's Unlock just as closely, again a single Password field.

n8n's Protect Document also keeps the single-password shape, but its permission list diverges by name, not just by count: All, Print, Copy, Edit, Fill Forms, Comment, Assemble. Seven values, no None, no Support Disabilities, and Print, Edit, and Comment do not map cleanly onto REST's Digital Print and Annotate wording. Unlock PDF in n8n answers a question the other platforms leave implicit, with a comparison table right on the page: Unlock removes existing protection using the current password, Protect applies a new one, and the two nodes are described explicitly as opposites meant to be chained in the same workflow, unlock first, process, then re-protect before the file leaves the system.

Make's Add Password to PDF is where the shape changes outright. Instead of one password field, it asks for two: a User Password that gates opening, and a separate Owner Password that gates permissions, the classic two-password model the PDF specification itself supports but that REST's single password field never surfaces. Make's own permission enum matches REST's eight values exactly, so the divergence here is entirely in the password structure. The unlock side carries its own naming quirk too: Make does not call it "Unlock," it calls it Remove Password from PDF, and its own documentation is explicit that a single correct password, user or owner, clears both restriction types in one pass.

Zapier's Protect PDF also splits into a User Password and an Owner Password, matching Make's structure. But it drops the permission enum entirely: there is no field to choose which specific actions get blocked. The Owner Password alone gates an unlabeled bundle of restrictions, with no way to select Fill Forms versus Copy the way REST, Power Automate, Make, and n8n all allow. Unlock PDF in Zapier needs only the file and the exact password, and its documentation makes the same point n8n's does: this removes a known password, it does not crack one.

Line the five surfaces up on two dimensions and no pair matches completely. REST, Power Automate, and n8n use one password field. Make and Zapier use two. REST's permission enum has eight values. Make matches it exactly. Power Automate adds a ninth. n8n renames and reduces to seven. Zapier has none at all. The underlying encryption is the same operation in every case. The interface a developer has to code against is not, and nothing in any single platform's own documentation says so, because each page only ever describes itself.

What actually matters when building against this

None of this is a documentation failure so much as five teams building the interface that felt most natural for their own platform's conventions, and none of it should be surprising once it is written down in one place. In practice: read the specific platform's own parameter table before assuming a REST integration guide transfers directly, because both the password structure and the permission vocabulary change underneath a feature name that stays constant. On any platform that does expose a permission enum, treat it as a full allow-list, not a place to name the one thing that should be blocked. If a form only needs Fill Forms access, decide up front whether print and copy access should genuinely disappear too, because that is what happens by default. The API Tester for Protect Document is the fastest way to see this directly: pick one permission value, send the request, and open the result to see exactly what stayed available and what silently did not.

Website: pdf4me.com
Documentation: docs.pdf4me.com
Developer portal: dev.pdf4me.com

Top comments (0)