Интеграция электронной подписи PandaDoc на сайт

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Интеграция электронной подписи PandaDoc на сайт
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Интеграция электронной подписи PandaDoc на сайт

PandaDoc отличается от DocuSign и SignNow тем, что это не просто сервис подписи, а полноценная платформа для работы с документами: создание из шаблонов, переменные, approval workflows, платёжные блоки внутри документа, аналитика открытий. REST API покрывает весь цикл от создания до архивирования.

Регистрация приложения и аутентификация

В PandaDoc Developer Dashboard: создать приложение → получить Client ID и Client Secret. Два режима аутентификации:

  • API Key — простой ключ в заголовке, для серверных интеграций без пользовательского контекста
  • OAuth 2.0 — для многопользовательских приложений
// Самый простой вариант для собственного сайта
$headers = [
    'Authorization' => 'API-Key ' . config('services.pandadoc.api_key'),
    'Content-Type'  => 'application/json',
];

Для OAuth — стандартный Authorization Code Flow на app.pandadoc.com/oauth2/authorize.

Создание документа из шаблона

PandaDoc поддерживает шаблоны — это удобнее, чем каждый раз загружать PDF:

class PandaDocService
{
    private string $baseUrl = 'https://api.pandadoc.com/public/v1';

    public function createFromTemplate(
        string $templateId,
        array  $recipient,
        array  $tokens
    ): array {
        $response = Http::withHeaders([
            'Authorization' => 'API-Key ' . config('services.pandadoc.api_key'),
            'Content-Type'  => 'application/json',
        ])->post("{$this->baseUrl}/documents", [
            'name'      => "Договор — {$recipient['email']}",
            'template'  => ['id' => $templateId],
            'recipients' => [
                [
                    'email'      => $recipient['email'],
                    'first_name' => $recipient['first_name'],
                    'last_name'  => $recipient['last_name'],
                    'role'       => 'client', // роль из шаблона
                ],
            ],
            'tokens' => array_map(fn($k, $v) => ['name' => $k, 'value' => $v],
                array_keys($tokens), $tokens),
            'metadata' => [
                'order_id' => $recipient['order_id'] ?? '',
            ],
        ]);

        return $response->json();
    }
}

Токены — это переменные в шаблоне вида [COMPANY_NAME], [CONTRACT_DATE]. При создании документа они подставляются автоматически.

Создание документа из загружаемого PDF

public function createFromPDF(string $pdfPath, array $recipient): array
{
    // Шаг 1: загрузить файл
    $uploadResponse = Http::withHeaders([
        'Authorization' => 'API-Key ' . config('services.pandadoc.api_key'),
    ])->attach('file', file_get_contents($pdfPath), 'contract.pdf')
      ->post("{$this->baseUrl}/documents");

    $documentId = $uploadResponse->json('id');

    // Шаг 2: ждём, пока документ обработается (обычно несколько секунд)
    $this->waitForStatus($documentId, 'document.uploaded');

    // Шаг 3: добавляем поле подписи
    Http::withHeaders([
        'Authorization' => 'API-Key ' . config('services.pandadoc.api_key'),
        'Content-Type'  => 'application/json',
    ])->patch("{$this->baseUrl}/documents/{$documentId}", [
        'recipients' => [[
            'email' => $recipient['email'],
            'role'  => 'Signer',
        ]],
        'fields' => [[
            'field_id'   => 'sig1',
            'type'       => 'signature',
            'role'       => 'Signer',
            'page'       => 0,
            'x'          => 100,
            'y'          => 600,
            'width'      => 200,
            'height'     => 50,
        ]],
    ]);

    return ['id' => $documentId];
}

private function waitForStatus(string $documentId, string $status): void
{
    $attempts = 0;
    do {
        sleep(1);
        $doc = Http::withHeaders([
            'Authorization' => 'API-Key ' . config('services.pandadoc.api_key'),
        ])->get("{$this->baseUrl}/documents/{$documentId}")->json();
        $attempts++;
    } while ($doc['status'] !== $status && $attempts < 15);
}

Отправка на подпись

public function sendDocument(string $documentId, string $message = ''): void
{
    Http::withHeaders([
        'Authorization' => 'API-Key ' . config('services.pandadoc.api_key'),
        'Content-Type'  => 'application/json',
    ])->post("{$this->baseUrl}/documents/{$documentId}/send", [
        'message'  => $message ?: 'Пожалуйста, ознакомьтесь и подпишите документ.',
        'subject'  => 'Документ для подписания',
        'silent'   => false, // true — не отправлять email, только ссылка
    ]);
}

Embedded signing через session link

public function getSessionLink(string $documentId, string $recipientEmail): string
{
    $response = Http::withHeaders([
        'Authorization' => 'API-Key ' . config('services.pandadoc.api_key'),
        'Content-Type'  => 'application/json',
    ])->post("{$this->baseUrl}/documents/{$documentId}/session", [
        'recipient' => $recipientEmail,
        'lifetime'  => 3600, // секунды
    ]);

    return $response->json('id'); // это session ID, не URL напрямую
    // URL для iframe: https://app.pandadoc.com/s/{session_id}
}

Итоговый URL для iframe: https://app.pandadoc.com/s/{session_id}. PandaDoc отправляет postMessage при завершении подписания.

Webhook

// Регистрация в настройках PandaDoc: Settings → API → Webhooks → Add endpoint

public function handlePandaDocWebhook(Request $request): Response
{
    // PandaDoc подписывает через HMAC-SHA256, ключ из настроек
    $signature = $request->header('x-pandadoc-signature');
    $body      = $request->getContent();
    $expected  = hash_hmac('sha256', $body, config('services.pandadoc.webhook_key'));

    if (!hash_equals($expected, $signature)) {
        abort(403);
    }

    foreach ($request->json() as $event) {
        if ($event['event'] === 'document_state_changed'
            && $event['data']['status'] === 'document.completed') {
            $docId = $event['data']['id'];
            DownloadPandaDocJob::dispatch($docId);
        }
    }

    return response()->noContent();
}

Обратите внимание: PandaDoc может отправить несколько событий в одном webhook-запросе — итерируем массив.

Скачивание и хранение

public function download(string $documentId, string $savePath): void
{
    $response = Http::withHeaders([
        'Authorization' => 'API-Key ' . config('services.pandadoc.api_key'),
    ])->get("{$this->baseUrl}/documents/{$documentId}/download");

    file_put_contents($savePath, $response->body());
}

Что отличает PandaDoc

Шаблоны с брендингом (логотип, цвета, стиль), pricing tables прямо в документе (клиент видит сумму и подписывает), approval workflows (документ проходит внутреннее согласование до отправки клиенту), встроенная аналитика просмотра (когда открыли, сколько времени на каждой странице). Это делает PandaDoc подходящим для коммерческих предложений и договоров с ценообразованием, а не только для типовых бланков.

Сроки

Базовая интеграция (шаблон → создание → отправка → webhook → скачивание): 2–3 рабочих дня. С embedded signing, токенами из CRM и approval workflow: 4–5 рабочих дней.