Sign a PDF with PHP
Send a document for signature from PHP with cURL or Guzzle, including the Laravel version.
Drop your document here and sign it now. PDF, Word and Excel all work: a .docx or .xlsx is laid out in your browser exactly as it was written, so there is nothing to convert first. Add a signature, a date, a company stamp or a watermark, then download it sealed. Free to start, no account, and the file is never uploaded to open it.
Create a document and get a signing link
One POST creates the document, places the fields and returns a signing URL for each signer. The key stays in the environment.
<?php
$ch = curl_init("https://api.pdfverified.com/v1/documents");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("PDFVERIFIED_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"name" => "Services agreement",
"file_url" => "https://example.com/agreement.pdf",
"signers" => [["name" => "Jane Doe", "email" => "jane@example.com", "role" => "client"]],
"webhook_url" => "https://example.com/hooks/pdfverified",
]),
CURLOPT_TIMEOUT => 30,
]);
$doc = json_decode(curl_exec($ch), true);
echo $doc["id"];What this ecosystem gets wrong first
- In Laravel, Http::withToken(config("services.pdfverified.key"))->post(...) is the same call in one line, and config() rather than env() so it survives config caching. Calling env() outside a config file is the classic bug that works locally and returns null in production.
- Set CURLOPT_TIMEOUT. Without it cURL waits indefinitely, which on a shared host means a worker held open until the process manager kills it.
- If you are on a host that disables allow_url_fopen, cURL is your only option, which is why the example uses it rather than file_get_contents.
Handling the webhook
When a signer completes, we POST the document id, the completion time, the signer record and the SHA-256 fingerprint of the sealed file to your webhook_url. Verify the signature header against the raw request body before you trust any of it, and respond 2xx quickly: do the slow work afterwards, because a webhook that takes ten seconds to answer is a webhook that gets retried.
The fingerprint in that payload is the same value the public verification page checks against, so you can store it and let anybody confirm a document you hold is the one that was signed.
What you get back
- A sealed PDF, with the signature part of the page rather than an annotation some viewers skip
- An audit certificate naming each signer, the time, the address and which checks they passed
- A SHA-256 fingerprint, and a public verification URL that needs no account to open
- Optional company stamps with serial numbers, applied in the same call
The REST API is included on the Business plan at $15 a month rather than sold as an add-on, which is the part worth comparing: several of the platforms a developer evaluates price the API separately and considerably higher.