There are two PDF4me endpoints that sound like they do the same thing: GetPdfInformation and GetPdfMetadata. Both take a PDF and hand back facts about it before your code opens it, edits it, or moves it anywhere. The overview version of this piece covers when to reach for each one. This is the version with the actual requests: real field names, a full working script, and one behavior that only shows up once you read the sample code instead of the docs page.
Same idea, different keys
Here's the part that trips people up. The two endpoints don't even use the same JSON keys for the same data.
POST https://api.pdf4me.com/api/v2/GetPdfInformation
{"File Name":"document.pdf","File Content":"JVBERi0xLjQK..."}
POST https://api.pdf4me.com/api/v2/GetPdfMetadata
{"docContent":"JVBERi0xLjQK...","docName":"output.pdf","async":true}
Both fields hold the same thing (a filename and the file's Base64 content) but GetPdfInformation takes File Name / File Content, and GetPdfMetadata takes docContent / docName. Copy-pasting a payload from one endpoint to the other silently fails, because the fields it's expecting just aren't there. Worth checking the exact key names for whichever endpoint you're calling instead of assuming they match, even though the docs read like they should.
Both use the same header pattern:
Content-Type: application/json
Authorization: Basic {api_key}
A working script for GetPdfMetadata
This is adapted from PDF4me's own sample repository (MIT licensed), trimmed down to the request/response logic:
import base64
import requests
import time
api_key = "YOUR_API_KEY"
url = "https://api.pdf4me.com/api/v2/GetPdfMetadata"
def read_and_encode_pdf(file_path):
with open(file_path, "rb") as f:
return base64.b64encode(f.read()).decode("utf-8")
def get_pdf_metadata(file_path):
headers = {
"Content-Type": "application/json",
"Authorization": f"Basic {api_key}",
}
payload = {
"docContent": read_and_encode_pdf(file_path),
"docName": "output.pdf",
"async": True,
}
response = requests.post(url, headers=headers, json=payload, timeout=30)
if response.status_code == 200:
# Synchronous: metadata comes back in the response body
return response.json()
if response.status_code == 202:
# Asynchronous: poll the Location header until it's done
location_url = response.headers.get("Location")
for attempt in range(10):
time.sleep(10)
poll = requests.get(location_url, headers=headers)
if poll.status_code == 200:
return poll.json()
if poll.status_code != 202:
poll.raise_for_status()
raise TimeoutError("Metadata extraction did not complete in time")
response.raise_for_status()
metadata = get_pdf_metadata("sample.pdf")
print(metadata)
Two response codes to handle: 200 returns the metadata JSON directly, 202 means it's processing async and hands you a Location header to poll. The official sample polls up to 10 times, 10 seconds apart, which is a reasonable starting point for anything that isn't a batch job.
GetPdfInformation, same pattern, smaller payload
There's no official Python sample published for this endpoint yet (only a C# one, in the same repo), but it follows the identical auth and encoding pattern, just with its own field names and no documented async option:
import base64
import requests
api_key = "YOUR_API_KEY"
url = "https://api.pdf4me.com/api/v2/GetPdfInformation"
def get_pdf_information(file_path):
with open(file_path, "rb") as f:
content = base64.b64encode(f.read()).decode("utf-8")
headers = {
"Content-Type": "application/json",
"Authorization": f"Basic {api_key}",
}
payload = {
"File Name": "document.pdf",
"File Content": content,
}
response = requests.post(url, headers=headers, json=payload, timeout=30)
response.raise_for_status()
return response.json()
info = get_pdf_information("sample.pdf")
print(info)
The response here is flatter too: a single Metadata Info field rather than the structured document/file/security breakdown GetPdfMetadata returns. If your triage logic just needs author, title, and encryption status, this is the lighter call.
The async flag the docs page doesn't mention
This is the part worth flagging for anyone who read the marketing docs page and stopped there. docs.pdf4me.com's own request example for GetPdfMetadata shows a two-field payload, no async flag anywhere. But PDF4me's official sample script sends "async": true by default and handles a 202 Accepted response with polling. That behavior exists at the REST level, it's just not visible unless you go read the sample code instead of the parameter table.
Practically: for a single small file, the endpoint can return 200 with the metadata inline. For larger files, or under load, expect a 202 and a Location header to poll. Build for both from the start rather than assuming a hardcoded 200 handler covers production traffic.
That also puts n8n's GetPdfMetadata node in a different light. Its Async toggle isn't just an n8n-side convenience, it's very likely surfacing this exact REST-level async parameter. That's an inference from matching behavior, not something n8n's own docs state outright, so treat it as a reasonable working assumption rather than a confirmed 1:1 mapping.
Where this shows up outside a raw HTTP client
Power Automate is the only platform with both actions as separate, named steps, each taking the same File Name / File Content pair, mappable straight from SharePoint, OneDrive, or an email trigger. Zapier ships a GetPdfMetadata action that takes a File and File Name. n8n's GetPdfMetadata node adds the input-format choice (binary, Base64, or URL) plus the Async toggle covered above.
There's no Make module for either endpoint yet, and no dedicated Zapier or n8n page for GetPdfInformation specifically. If you're on Make, or need GetPdfInformation inside Zapier or n8n today, the REST call above is the way in.
The practical takeaway
Match the endpoint to the question. "Who made this file, and is it locked?" is GetPdfInformation. "Does this meet an archival, size, or signature standard, and how many pages is it?" is GetPdfMetadata. Run the cheaper call where you can, and build the 202/polling path for GetPdfMetadata from day one rather than retrofitting it after the first large file times out in production.
(A more editorial, less code-heavy version of this piece is also up on Medium and Hashnode.)
Learn more
Developer portal: dev.pdf4me.com
Documentation: docs.pdf4me.com
Website: pdf4me.com