If you're building any system that involves contracts, invoices, or compliance documents, you need a way to digitally sign PDFs programmatically. With the PDFSignify API, "sending a PDF for signature" means sending the PDF file along with your digital certificate to the API and getting back a signed PDF — all in a single HTTP request.
This guide covers the complete implementation in multiple languages, with production-ready patterns and best practices.
How PDFSignify Handles "Send for Signature"
Unlike eSignature platforms where "send for signature" means emailing a document to a human signer and waiting for them to click and sign, PDFSignify works differently. It's a certificate-based digital signing API. You provide the PDF, a .pfx/.p12 certificate, and the certificate password. The API applies a cryptographic digital signature and returns the signed PDF immediately.
- No signer email addresses or notification workflows
- No document IDs or stored files on PDFSignify's servers
- No webhooks or status polling — the response IS the signed document
- Cryptographic signature using your own digital certificate
- The signed PDF is verifiable in any PDF reader (Adobe, Foxit, etc.)
What You Need
- A PDFSignify account — sign up at pdfsignify.com to get your AccessKey and SecretKey
- A digital certificate file (.pfx or .p12) and its password
- The PDF document you want to sign
- Any HTTP client — cURL, axios, fetch, Guzzle, etc.
Authentication
Every request to PDFSignify requires two headers: AccessKey and SecretKey. There's no OAuth, no Bearer tokens, and no session management. Just include both headers on every request.
AccessKey: your_access_key_here
SecretKey: your_secret_key_hereMethod 1: cURL
The simplest way to test the API. This sends a PDF and certificate to the sign-pdf endpoint and saves the signed result.
curl -X POST https://api.pdfsignify.com/api/v1/sign-pdf \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "SecretKey: YOUR_SECRET_KEY" \
-F "[email protected]" \
-F "[email protected]" \
-F "certificatePassword=your_cert_password" \
-F "signaturePageAppearance=-1" \
-F "signatureMessage=Digitally signed" \
-F "signatureHeight=100" \
-F "signatureWidth=150" \
-F "signatureXPosition=180" \
-F "signatureYPosition=100" \
--output signed_document.pdfThe -F flags send each field as multipart form data. The --output flag saves the response body (the signed PDF) directly to a file.
Method 2: JavaScript (Node.js)
const axios = require("axios");
const FormData = require("form-data");
const fs = require("fs");
async function signPdf(pdfPath, certificatePath, certPassword) {
const formData = new FormData();
formData.append("pdf", fs.createReadStream(pdfPath), {
filename: "document.pdf",
contentType: "application/pdf",
});
formData.append("certificate", fs.createReadStream(certificatePath), {
filename: "certificate.pfx",
contentType: "application/x-pkcs12",
});
formData.append("certificatePassword", certPassword);
formData.append("signaturePageAppearance", "-1");
formData.append("signatureMessage", "Digitally signed");
formData.append("signatureHeight", "100");
formData.append("signatureWidth", "150");
formData.append("signatureXPosition", "180");
formData.append("signatureYPosition", "100");
const response = await axios.post(
"https://api.pdfsignify.com/api/v1/sign-pdf",
formData,
{
headers: {
...formData.getHeaders(),
AccessKey: "YOUR_ACCESS_KEY",
SecretKey: "YOUR_SECRET_KEY",
},
responseType: "arraybuffer",
}
);
fs.writeFileSync("signed_document.pdf", response.data);
console.log("Signed PDF saved.");
}
signPdf("document.pdf", "certificate.pfx", "cert_password");The key detail is responseType: "arraybuffer". Since PDFSignify returns raw PDF binary data, you need to tell axios not to parse the response as JSON.
Method 3: PHP
<?php
function signPdf(string $pdfPath, string $certPath, string $certPassword): string
{
$boundary = uniqid();
$delimiter = '----' . $boundary;
$fields = [
'certificatePassword' => $certPassword,
'signaturePageAppearance' => '-1',
'signatureMessage' => 'Digitally signed',
'signatureHeight' => '100',
'signatureWidth' => '150',
'signatureXPosition' => '180',
'signatureYPosition' => '100',
];
$body = '';
foreach ($fields as $name => $value) {
$body .= "--{$delimiter}\r\n";
$body .= "Content-Disposition: form-data; name=\"{$name}\"\r\n\r\n";
$body .= "{$value}\r\n";
}
$body .= "--{$delimiter}\r\n";
$body .= "Content-Disposition: form-data; name=\"pdf\"; filename=\"document.pdf\"\r\n";
$body .= "Content-Type: application/pdf\r\n\r\n";
$body .= file_get_contents($pdfPath) . "\r\n";
$body .= "--{$delimiter}\r\n";
$body .= "Content-Disposition: form-data; name=\"certificate\"; filename=\"cert.pfx\"\r\n";
$body .= "Content-Type: application/x-pkcs12\r\n\r\n";
$body .= file_get_contents($certPath) . "\r\n";
$body .= "--{$delimiter}--\r\n";
$ch = curl_init('https://api.pdfsignify.com/api/v1/sign-pdf');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: multipart/form-data; boundary=' . $delimiter,
'AccessKey: YOUR_ACCESS_KEY',
'SecretKey: YOUR_SECRET_KEY',
],
CURLOPT_POSTFIELDS => $body,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new RuntimeException('Signing failed: ' . $response);
}
return $response;
}
$signedPdf = signPdf('document.pdf', 'certificate.pfx', 'cert_password');
file_put_contents('signed_document.pdf', $signedPdf);Method 4: PHP with Laravel Http Facade
If you're using Laravel, the Http facade provides a cleaner interface for the same operation.
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([
'AccessKey' => config('services.pdfsignify.access_key'),
'SecretKey' => config('services.pdfsignify.secret_key'),
])
->attach('pdf', fopen('document.pdf', 'r'), 'document.pdf')
->attach('certificate', fopen('certificate.pfx', 'r'), 'certificate.pfx')
->post('https://api.pdfsignify.com/api/v1/sign-pdf', [
'certificatePassword' => config('services.pdfsignify.certificate_password'),
'signaturePageAppearance' => -1,
'signatureMessage' => 'Digitally signed',
'signatureHeight' => 100,
'signatureWidth' => 150,
'signatureXPosition' => 180,
'signatureYPosition' => 100,
]);
file_put_contents('signed_document.pdf', $response->body());Customizing the Signature Appearance
PDFSignify gives you control over how the signature looks and where it appears on the PDF.
- signaturePageAppearance: Which page to place the visible signature. Use -1 for all pages.
- signatureMessage: The text displayed in the signature block (e.g., "Signed by Acme Corp").
- signatureDateLabel and signatureDateFormat: Customize the date display in the signature.
- signatureHeight and signatureWidth: Control the size of the signature block in points.
- signatureXPosition and signatureYPosition: Position the signature on the page.
- signatureBackgroundImage: Upload an image (e.g., handwritten signature scan) to display behind the signature text.
- timezone: Set the timezone for the signature timestamp.
Setting PDF Metadata
PDFSignify also offers a separate endpoint for setting PDF metadata without signing. This is useful for document management and compliance workflows.
curl -X POST https://api.pdfsignify.com/api/v1/set-pdf-metadata \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "SecretKey: YOUR_SECRET_KEY" \
-F "[email protected]" \
-F "pdfMetadataAuthor=Acme Corp" \
-F "pdfMetadataTitle=Service Agreement" \
-F "pdfMetadataKeywords=contract, agreement, 2026" \
--output document_with_metadata.pdfValidating Your Certificate Before Signing
If you want to verify that a certificate and password combination is valid before attempting to sign a document, use the check-certificate-password endpoint.
const formData = new FormData();
formData.append("certificate", fs.createReadStream("certificate.pfx"), {
filename: "certificate.pfx",
contentType: "application/x-pkcs12",
});
formData.append("certificatePassword", "cert_password");
const response = await axios.post(
"https://api.pdfsignify.com/api/v1/check-certificate-password",
formData,
{
headers: {
...formData.getHeaders(),
AccessKey: "YOUR_ACCESS_KEY",
SecretKey: "YOUR_SECRET_KEY",
},
}
);
console.log(response.data); // { success: true }Real Use Cases
- Automated invoice signing: Sign every invoice PDF before sending it to clients
- Contract certification: Apply your company's digital certificate to finalized contracts
- Compliance workflows: Certify documents before archiving for regulatory requirements
- Document management systems: Sign on upload or sign on approval
- CI/CD pipelines: Automatically sign release documents or audit reports
Error Handling Best Practices
- Always check the HTTP status code — a 200 means success, anything else means the signing failed
- Validate the certificate password before attempting to sign (use the check-certificate-password endpoint)
- Set reasonable timeouts for large PDFs — signing a 50MB file takes longer than a 1-page document
- Log failed signing attempts with the error response body for debugging
- Implement retry logic for transient network failures
Production Architecture Tips
- Store certificates in secure storage (e.g., environment secrets, vault) — never in your codebase
- Keep AccessKey and SecretKey in environment variables
- Clean up temporary PDF files after signing
- If signing large batches, use a job queue to avoid blocking your main application
- Store signed PDFs in durable storage (S3, GCS, Azure Blob) with proper access controls
PDFSignify vs. Traditional eSignature APIs
Traditional eSignature APIs (DocuSign, HelloSign, PandaDoc) are workflow platforms: upload a document, define signers, send email notifications, wait for humans to sign, receive webhooks. They're designed for human-in-the-loop signing ceremonies.
PDFSignify is a signing utility: send a file and certificate, get a signed file back. It's designed for automated, certificate-based digital signing. If your use case is "apply a cryptographic signature to this PDF", PDFSignify is simpler, faster, and more predictable. If your use case is "send a contract to John and wait for him to sign it", you need an eSignature workflow platform.
Summary
Sending a PDF for digital signature with PDFSignify takes a single API call. You post the PDF, certificate, and password as multipart form data, and you receive the signed PDF back in the response body. No document IDs, no webhooks, no polling — just a clean, synchronous operation that fits into any tech stack.
The fastest way to sign a PDF is an API that returns the signed file in the same request. That's PDFSignify.