Інтеграція електронного підпису SignNow на сайт
SignNow — конкурент DocuSign від airSlate, орієнтований на SMB та API-інтеграції. Відрізняється простішим ціноутворенням та REST API без обов'язкового SDK — всі операції через стандартні HTTP-запити. Документація: docs.signnow.com.
Аутентифікація
SignNow використовує OAuth 2.0 з client_credentials для серверних інтеграцій:
class SignNowAuthService
{
private string $baseUrl = 'https://api.signnow.com';
public function getToken(): string
{
$response = Http::withBasicAuth(
config('services.signnow.client_id'),
config('services.signnow.client_secret')
)->asForm()->post("{$this->baseUrl}/oauth2/token", [
'grant_type' => 'client_credentials',
'scope' => '*',
]);
$token = $response->json('access_token');
// Кешируємо — токен живе годину
Cache::put('signnow_token', $token, now()->addMinutes(55));
return $token;
}
public function token(): string
{
return Cache::get('signnow_token') ?? $this->getToken();
}
}
Для флоу з підписом конкретного користувача (user-level operations) потрібен Password Grant з логіном/паролем користувача SignNow. Для більшості API-інтеграцій достатньо client_credentials.
Завантаження документа та простановка полів
class SignNowDocumentService
{
public function __construct(private SignNowAuthService $auth)
{}
public function uploadDocument(string $pdfPath, string $fileName): string
{
$response = Http::withToken($this->auth->token())
->attach('file', file_get_contents($pdfPath), $fileName)
->post('https://api.signnow.com/document');
return $response->json('id'); // document ID
}
public function addSignatureFields(string $documentId, array $signers): void
{
$fields = [];
$roleIndex = 0;
foreach ($signers as $signer) {
$fields[] = [
'type' => 'signature',
'role' => $signer['role'] ?? "Signer {$roleIndex}",
'role_id' => (string)$roleIndex,
'required' => true,
'height' => 40,
'width' => 200,
'x' => 100,
'y' => 600,
'page_number' => 0,
];
$roleIndex++;
}
Http::withToken($this->auth->token())
->put("https://api.signnow.com/document/{$documentId}", [
'fields' => $fields,
]);
}
}
SignNow підтримує smart fields через anchor-теги в PDF: якщо у документі є текст [[sig|req|signer1]], SignNow автоматично ставить поле підпису. Це зручніше, ніж фіксовані координати.
Створення invite для підписантів
public function sendInvite(string $documentId, array $signers): string
{
$recipients = [];
foreach ($signers as $index => $signer) {
$recipients[] = [
'email' => $signer['email'],
'role' => $signer['role'] ?? "Signer {$index}",
'role_id' => (string)$index,
'order' => $index + 1,
'reminder' => [
'remind_before' => 0,
'remind_after' => 3, // напомнить через 3 дня
'remind_repeat' => 2, // повторювати кожні 2 дні
],
'expiration_days' => 30,
'subject' => 'Будь ласка, підпишіть документ',
'message' => "Привіт, {$signer['name']}! Прошу вас підписати прикріплений документ.",
];
}
$response = Http::withToken($this->auth->token())
->post("https://api.signnow.com/document/{$documentId}/invite", [
'to' => $recipients,
'from' => config('services.signnow.sender_email'),
]);
return $response->json('status'); // 'success'
}
Embedded signing
Для підпису без переходу на SignNow — отримання посилання для вставки в iframe або редиректа:
public function getSigningLink(string $documentId, string $email): string
{
$response = Http::withToken($this->auth->token())
->post("https://api.signnow.com/link", [
'document_id' => $documentId,
]);
// link дійсний один раз і обмежений час
return $response->json('url');
}
Embedded signing працює через <iframe src="..."> або window.open. Після підписання SignNow викликає postMessage або редирект на вказаний URL.
Webhook: події документа
// Реєстрація webhook
Http::withToken($this->auth->token())
->post('https://api.signnow.com/api/v2/events', [
'event' => 'document.complete',
'entity_id' => $documentId,
'action' => 'callback',
'callback_url' => route('webhooks.signnow'),
]);
// Обробник
public function handleSignNowWebhook(Request $request): Response
{
$data = $request->json()->all();
if (($data['event'] ?? '') === 'document.complete') {
$documentId = $data['meta']['document_id'];
DownloadSignedDocumentJob::dispatch($documentId);
}
return response()->noContent();
}
Скачування підписаного документа
public function downloadSigned(string $documentId): string
{
$response = Http::withToken($this->auth->token())
->get("https://api.signnow.com/document/{$documentId}/download", [
'type' => 'collapsed', // єдиний PDF з усіма підписами
]);
$path = storage_path("app/contracts/signed_{$documentId}.pdf");
file_put_contents($path, $response->body());
return $path;
}
Відмінності від DocuSign
SignNow працює через чистий REST без обов'язкового SDK, що спрощує інтеграцію на будь-якій мові. Немає вбудованого фіскального сховища документів — якщо потрібно зберігати підписані договори з аудит-треком, це організовується на боці додатка. Функціональність embedded signing менш гнучка за кастомізацією UI. При цьому API більш прямолінійний і добре задокументований.
Терміни
OAuth, завантаження документа, відправка invite, webhook та скачування підписаного файлу: 2–3 робочих дні. З embedded signing та повним UX-флоу всередині сайту: 3–4 робочих дні.







