This article is a collection of working PHP code examples for the PDFSignify API. Every example uses cURL and can be dropped into any PHP project. No frameworks required, no external dependencies beyond PHP's built-in cURL extension.
Before You Start
You need three things to use these examples:
- A PDFSignify account — sign up at pdfsignify.com to get your AccessKey and SecretKey
- A .pfx or .p12 digital certificate file with its password
- PHP 7.4 or later with the cURL extension enabled
The API authenticates with two custom headers on every request: AccessKey and SecretKey. There are no tokens to refresh and no OAuth to configure.
Example 1: Sign a PDF (Minimal)
The simplest possible signing request. Send the PDF, the certificate, and the password. Get the signed PDF back.
<?php
$ch = curl_init('https://api.pdfsignify.com/api/v1/sign-pdf');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'AccessKey: YOUR_ACCESS_KEY',
'SecretKey: YOUR_SECRET_KEY',
],
CURLOPT_POSTFIELDS => [
'certificate' => new CURLFile('certificate.pfx', 'application/x-pkcs12'),
'certificatePassword' => 'your_certificate_password',
'pdf' => new CURLFile('document.pdf', 'application/pdf'),
],
]);
$response = curl_exec($ch);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
if (strpos($contentType, 'application/pdf') !== false) {
file_put_contents('signed.pdf', $response);
echo 'Done. Signed PDF saved.';
} else {
echo 'Error: ' . $response;
}Example 2: Sign with Custom Signature Appearance
Add a logo, position the signature on the page, and customize the message text. This example builds the multipart body manually for full control:
<?php
$cert = file_get_contents('certificate.pfx');
$pdf = file_get_contents('document.pdf');
$logo = file_get_contents('logo.png');
$boundary = uniqid();
$delimiter = '--------------------' . $boundary;
$parts = [];
$parts[] = '--' . $delimiter;
$parts[] = 'Content-Disposition: form-data; name="certificate"; filename="certificate.pfx"';
$parts[] = 'Content-Type: application/x-pkcs12';
$parts[] = '';
$parts[] = $cert;
$parts[] = '--' . $delimiter;
$parts[] = 'Content-Disposition: form-data; name="certificatePassword"';
$parts[] = '';
$parts[] = 'your_certificate_password';
$parts[] = '--' . $delimiter;
$parts[] = 'Content-Disposition: form-data; name="pdf"; filename="document.pdf"';
$parts[] = 'Content-Type: application/pdf';
$parts[] = '';
$parts[] = $pdf;
$parts[] = '--' . $delimiter;
$parts[] = 'Content-Disposition: form-data; name="signatureBackgroundImage"; filename="logo.png"';
$parts[] = 'Content-Type: image/png';
$parts[] = '';
$parts[] = $logo;
$textFields = [
'signaturePageAppearance' => '-1',
'timezone' => 'America/New_York',
'signatureMessage' => 'Signed by Acme Inc.',
'signatureDateFormat' => 'Y-m-d H:i:s',
'signatureHeight' => '80',
'signatureWidth' => '200',
'signatureYPosition' => '50',
'signatureXPosition' => '350',
];
foreach ($textFields as $name => $value) {
$parts[] = '--' . $delimiter;
$parts[] = 'Content-Disposition: form-data; name="' . $name . '"';
$parts[] = '';
$parts[] = $value;
}
$parts[] = '--' . $delimiter . '--';
$parts[] = '';
$body = implode("\r\n", $parts);
$ch = curl_init('https://api.pdfsignify.com/api/v1/sign-pdf');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: multipart/form-data; boundary=' . $delimiter,
'AccessKey: YOUR_ACCESS_KEY',
'SecretKey: YOUR_SECRET_KEY',
]);
$response = curl_exec($ch);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
if (strpos($contentType, 'application/pdf') !== false) {
file_put_contents('signed_with_logo.pdf', $response);
echo 'Signed PDF with custom appearance saved.';
} else {
echo 'Error: ' . $response;
}Example 3: Validate a Certificate Before Signing
Use this to verify that a certificate and password combination is correct before attempting to sign. Useful when users upload their own certificates:
<?php
$ch = curl_init('https://api.pdfsignify.com/api/v1/check-certificate-password');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'AccessKey: YOUR_ACCESS_KEY',
'SecretKey: YOUR_SECRET_KEY',
],
CURLOPT_POSTFIELDS => [
'certificate' => new CURLFile('certificate.pfx', 'application/x-pkcs12'),
'certificatePassword' => 'test_password',
],
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
echo $result['success'] ? 'Valid certificate.' : 'Invalid certificate or password.';Example 4: Set PDF Metadata
Update the author, title, keywords, and other metadata fields of a PDF without signing it:
<?php
$ch = curl_init('https://api.pdfsignify.com/api/v1/set-pdf-metadata');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'AccessKey: YOUR_ACCESS_KEY',
'SecretKey: YOUR_SECRET_KEY',
],
CURLOPT_POSTFIELDS => [
'pdf' => new CURLFile('report.pdf', 'application/pdf'),
'pdfMetadataAuthor' => 'Finance Team',
'pdfMetadataTitle' => 'Annual Report 2026',
'pdfMetadataSubject' => 'Financial Summary',
'pdfMetadataKeywords' => 'annual,report,finance,2026',
'pdfMetadataCreator' => 'Internal Tools',
'pdfMetadataProducer' => 'PDFSignify',
],
]);
$response = curl_exec($ch);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
if (strpos($contentType, 'application/pdf') !== false) {
file_put_contents('report_with_metadata.pdf', $response);
echo 'Metadata updated.';
} else {
echo 'Error: ' . $response;
}Example 5: Sign and Stream to Browser
Instead of saving the signed PDF to disk, you can serve it directly as a download. This works well for web application endpoints:
<?php
$ch = curl_init('https://api.pdfsignify.com/api/v1/sign-pdf');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'AccessKey: YOUR_ACCESS_KEY',
'SecretKey: YOUR_SECRET_KEY',
],
CURLOPT_POSTFIELDS => [
'certificate' => new CURLFile('certificate.pfx', 'application/x-pkcs12'),
'certificatePassword' => 'your_certificate_password',
'pdf' => new CURLFile('invoice.pdf', 'application/pdf'),
],
]);
$response = curl_exec($ch);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200 && strpos($contentType, 'application/pdf') !== false) {
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="signed_invoice.pdf"');
header('Content-Length: ' . strlen($response));
echo $response;
exit;
}
http_response_code(500);
header('Content-Type: application/json');
echo json_encode(['error' => 'Signing failed', 'details' => $response]);Example 6: Helper Function for Reuse
If you are signing PDFs in multiple places in your application, extract the logic into a reusable function:
<?php
function signPdf(
string $pdfPath,
string $certPath,
string $certPassword,
string $accessKey,
string $secretKey
): string|false {
$ch = curl_init('https://api.pdfsignify.com/api/v1/sign-pdf');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'AccessKey: ' . $accessKey,
'SecretKey: ' . $secretKey,
],
CURLOPT_POSTFIELDS => [
'certificate' => new CURLFile($certPath, 'application/x-pkcs12'),
'certificatePassword' => $certPassword,
'pdf' => new CURLFile($pdfPath, 'application/pdf'),
],
]);
$response = curl_exec($ch);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
if (strpos($contentType, 'application/pdf') !== false) {
return $response;
}
return false;
}
// Usage:
$signed = signPdf(
'contract.pdf',
'certificate.pfx',
'password123',
getenv('PDFSIGNIFY_ACCESS_KEY'),
getenv('PDFSIGNIFY_SECRET_KEY')
);
if ($signed !== false) {
file_put_contents('signed_contract.pdf', $signed);
}Tips for Production Use
- Store AccessKey and SecretKey in environment variables — never hardcode them in source files
- The sign-pdf and set-pdf-metadata endpoints return binary PDF data, not JSON — always check Content-Type before parsing
- Only check-certificate-password returns JSON
- Use curl_getinfo($ch, CURLINFO_HTTP_CODE) to detect server errors (4xx/5xx)
- Set CURLOPT_TIMEOUT to a reasonable value for large PDFs to avoid hanging requests
- Log errors with context but never log the SecretKey
Every example on this page uses only PHP and cURL. No Composer packages, no frameworks, no external dependencies.