PHP client
signsealer/sdk for PHP 8.1 and later. Only PHP's own
curl and json: no Guzzle, nothing to pin.
composer require signsealer/sdk
On its way to Packagist. The client is written and tested against this API; until its first release is published, the line above does not find it. Ask us and we will send the package. For a WordPress site, the WordPress plugin needs no code at all.
The same three promises as the Node client: one
idempotency key through every retry of a write, a Retry-After honoured,
and the API's own sentence, code, hint and request id on every error.
Send a document
use SignSealer\SignSealer;
use SignSealer\SignSealerError;
$signsealer = new SignSealer(getenv('SIGNSEALER_KEY'));
$doc = $signsealer->prepareDocument([
'template_code' => 'rental-agreement',
'values' => ['guest_name' => 'Dana Reyes', 'trip_date' => '2026-11-14'],
'external_ref' => 'booking-1042',
]);
$sent = $signsealer->send($doc['document_id'], [['full_name' => 'Dana Reyes', 'email' => 'dana@example.com']]);
echo $sent['links'][0]['url'];
Every method
| Method | Calls |
|---|---|
| account() · branding() | GET /v1/account · /v1/branding |
| templates($code = null) · template($id) | GET /v1/templates · /v1/templates/:id |
| documents($filter) · document($id) · documentSigners($id) | GET /v1/documents · /:id · /:id/signers |
| prepareDocument($document, $idempotencyKey = null) | POST /v1/documents |
| documentFromPdf($title, $pdfBytes, $fields = null, $textTags = false) | POST / |
| send($documentId, $signers) · remind($documentId, $signerId) · embedLink($documentId, $signerId) · void($documentId, $reason) | POST / |
| certificate($id) · pdf($id) · bundle($id) | GET /bytes |
| standing($template, $email = null, $phone = null) | GET /v1/standing |
| workflows() · startWorkflow($workflowId, $participant) | GET /v1/workflows · POST / |
| webhooks() · addWebhook($url, $events = null) · ensureWebhook($url, $events = null) · removeWebhook($id, $reason) | /v1/webhooks |
Each answers with the API's JSON as an array, exactly as the API reference describes it.
Errors
try {
$signsealer->prepareDocument(['template_code' => 'rental-agreement', 'values' => []]);
} catch (SignSealerError $e) {
echo $e->status, ' ', $e->errorCode, ' ', $e->getMessage(); // 422 invalid no value for guest_name
echo $e->hint, ' ', $e->requestId; // what to do, and the id to quote
}
Verifying a webhook
use SignSealer\Webhook;
$check = Webhook::verify(
getenv('SIGNSEALER_WEBHOOK_SECRET'),
file_get_contents('php://input'), // the raw body
$_SERVER['HTTP_SIGNSEALER_SIGNATURE'] ?? null,
$_SERVER['HTTP_SIGNSEALER_TIMESTAMP'] ?? null,
);
if (!$check['ok']) { http_response_code(400); exit($check['reason']); }
Ready to build? An API key takes a minute in the portal, and the free plan covers the first 10 agreements a month.
Get an API key