В документации Adobe сочетается большой объем информации и плохая организация этой информации. Поэтому когда перед мной стала задача отправлять документы через Adobe Sign Api, я потратил несколько дней чтобы понять как всё это работает. 

И вот моё решение перед вами. Надеюсь, оно сэкономит время и нервы тех кому только предстоит разобраться в этом. 

Порядок действий:

  1. Создаем статичный ключ для работы с API - Access token

  2. Получаем домены для работы с API - Base uris

  3. Загружаем документ

  4. Отправляем документ на подпись

  5. Проверяем статус подписи

  6. Сохраняем подписанный файл

Создаем статичный ключ для работы с API - Access token

Заходим в свой аккаунт на сайте Adobe Sign API: https://secure.echosign.com/public/login. Переходим на страницу Account. Выбираем Personal Preferences и Access Tokens.

Нажимаем на плюсик справа, вводим название, выбираем доступы и сохраняем.

Какие доступы нам нужны?

На этот вопрос у меня ответа нет, поэтому я выбрал все доступы, чтобы наверняка заработало. Да, это не безопасно, но зато так точно будет работать. Мне было важно, чтобы оно заработало.

После сохранения, кликаем на наш токен и нажимаем сверху “Integration Key”, чтобы получить наш токен.

Далее в перменной $accessToken будет именно этот токен.

Получаем домены для работы с API - Base uris

<?php
// Access token, полученный выше
$accessToken = '';

// Laravel фасад:
// GET запрос
// Доп. заголовок: Bearer $accessToken
// URL: https://api.adobesign.com/api/rest/v6/baseUris
$response = Http::withToken($accessToken)
  ->get('https://api.adobesign.com/api/rest/v6/baseUris');

// В ответе JSON с полем apiAccessPoint 
$apiAccessPoint = $response->json('apiAccessPoint');

В $apiAccessPoint домен для API запросов.

Загружаем документ

<?php
// Access token, полученный выше
$accessToken = '';

// Домен для API запросов, полученный выше
$apiAccessPoint = '';

// Путь к pdf шаблону
$template = file_get_contents($pathToTemplate);

// Laravel фасад:
// POST multipart/form-data запрос
// Доп. заголовок: Bearer $accessToken
// URL: $apiAccessPoint.'/api/rest/v6/transientDocuments'
// В теле указываем название файла, mime тип и содержимое файла
$response = Http
   ::withToken($accessToken)
   ->baseUrl($apiAccessPoint)
   ->asMultipart()
   ->post('/api/rest/v6/transientDocuments', [
       'File-Name' => 'document.pdf',
       'Mime-Type' => 'application/pdf',
       'File'      => $template
   ]);

// В ответе JSON с полем transientDocumentId, что является ID загруженного дока
$transientDocumentID = $response->json('transientDocumentId');
if ( ! $transientDocumentID) {
   // Если не пришел ID документа, то обрабатываем ошибку
}

В переменной $transientDocumentID будет ID загруженного документа.

Отправляем документ на подпись

Далее мне надо было понять как отправить документ на подпись.

Сначала я пытался добавить в документ виджеты. Виджет - это поле ввода в которое пользователь может внести свои данные, включая подпись. Но виджетам необходимо указывать координаты, которые непонятно как связаны с реальным документом. 

Поэтому после нескольких часов поиска в интернете, я нашел руководство по тегам, которые можно добавить в шаблон, чтобы поля появились сами собой. 

Например, чтобы появилось поле подписи, нужно ввести тег {{ es:signer:signature }}

В документе это может выглядеть так:

Документ #1234

Исполнитель: Дмитрий Дмитриевич {{es:signer:signature }}

Далее необходимо сформировать тело запроса. Оно содержит некоторое количество полей:

<?php
// Функция для формирования тела запроса. Используется ниже
function getBodyForSignDocument($documentID, $email): array
{
   return [
       // ID документа, полученный выше
       "fileInfos"           => [
           [
               "transientDocumentId" => $documentID
           ]
       ],
       // Название документа, которое увидит клиент
       "name"                => "Series Document",
       "participantSetsInfo" => [
           [
               "order"       => 1,
               "role"        => "SIGNER",
               "memberInfos" => [
                   [
                       // Почта клиента
                       "email" => $email,
                       "id"    => 1
                   ]
               ]
           ]
       ],
       "signatureType"       => "ESIGN",
       "state"               => "IN_PROCESS"
   ];
}

Теперь необходимо выполнить запрос на отправку файла на подпись:

<?php
// Access token, полученный выше
$accessToken = '';

// Домен для API запросов, полученный выше
$apiAccessPoint = '';

// Тело запроса, функция которого писана выше
$bodyForSignDocument = getBodyForSignDocument($transientDocumentID, $email);


// Laravel фасад:
// POST application/json запрос
// Доп. заголовок: Bearer $accessToken
// URL: $apiAccessPoint.'/api/rest/v6/agreements'
// Тело запроса описано выше
$response = Http::withToken(self::API_TOKEN)
                ->baseUrl($apiAccessPoint)
                ->asJson()
                ->post(
                    '/api/rest/v6/agreements',
                    $bodyForSignDocument
                );

// В ответе JSON с ID загруженного документа. Он понадобится ниже
$documentID = $response->json('id');
if ($response->status() != '201' || ! $documentID) {
   // Если ID не пришел или документ не был первично обработан Adobe, обрабатываем ошибку
}

В переменной $documentID содержится ID документа, который был отправлен на подпись.

Проверяем статус подписи

<?php
// Access token, полученный выше
$accessToken = '';

// Домен для API запросов, полученный выше
$apiAccessPoint = '';

// ID документа, полученный выше
$documentID

// Laravel фасад:
// GET запрос
// Доп. заголовок: Bearer $accessToken
// URL: $apiAccessPoint.'/api/rest/v6/agreements/'.$documentID
$response = Http::withToken(self::API_TOKEN)
               ->baseUrl($apiAccessPoint)
               ->get('/api/rest/v6/agreements/' . $documentID);

// В ответе JSON с полем status
$status = $response->json('status');
if ($status !== 'SIGNED') {
   // Если статус не SIGNED, то ждем пока подпишут
}

Сохраняем подписанный файл

<?php
// Access token, полученный выше
$accessToken = '';

// Домен для API запросов, полученный выше
$apiAccessPoint = '';

// ID документа, полученный выше
$documentID

// Полный путь до файла  
$fileURLPath = $apiAccessPoint . 'api/rest/v6/agreements/' . $documentID . '/combinedDocument';

// Laravel фасад:
// GET запрос
// Доп. заголовок: Bearer $accessToken
// URL: $apiAccessPoint.$fileURLPath
$fileContent = Http::withToken(self::API_TOKEN)
                  ->baseUrl($apiAccessPoint)
                  ->get($fileURLPath);

// В теле ответа будет подписанный PDF файл, если раннее в статусе было SIGNED 
$fileContent = $fileContent->body();

Источники. Примечания

Источники

Касательно авторизации

Изначально Adobe просит использовать авторизацию через кнопку "Войти через Adobe". Но такой способ мне не подходил, ибо система должна функционировать автономно без вмешательства пользователей. Авторизация - тоже вмешательство.

Именно поэтому была найдена альтернатива в виде статичного токена - access token.

Касательно параметров в POST методе /api/rest/v6/agreements

Советую ознакомиться с описанием запросов к API 6й версии для понимание что можно добавить и изменить.

Например, можно не отправлять сразу документ, а подготовить его, добавив те виджеты. И только потом отправлять. Либо же, можно добавить какие-то данные в документ через автозамену тегов в формат {{var.name}}

Прошлая статья на тему Adobe

"Генерация файлов с Adobe" - в статье описаны методы формирования файлов из doсx шаблонов.

Комментарии (0)