Integração com Assinatura embutida
Introdução
A integração com Assinatura embutida permite assinar/aprovar documentos submetidos no Signer dentro de qualquer aplicação por meio do componente LacunaSignerWidget.
O Signer deve ser configurado com uma licença do Web PKI que tenha o domínio no qual o componente será carregado.
Instalação
Primeiro, inclua na sua página o arquivo lacuna-signer-widget.js mais recente:
<script type="text/javascript" src="https://cdn.lacunasoftware.com/libs/signer/lacuna-signer-widget-0.8.0.min.js"
integrity="sha256-kS96fv3kyz1iJOP3crrI/2dvBzAgEHu4dZF9ecS/f0I="
crossorigin="anonymous"></script>
Em seguida, instancie a classe LacunaSignerWidget:
var widget = new LacunaSignerWidget();
Chame então o método on() passando o tipo de evento que quer escutar e uma função de callback que será chamada quando o usuário assinar/aprovar o documento:
//assinatura
widget.on(widget.events.documentSigned, function (e) {
// ...
//alert('Documento ' + e.id + ' assinado');
});
//aprovação
widget.on(widget.events.documentApproved, function (e) {
// ...
//alert('Documento ' + e.id + ' aprovado');
});
Se preferir use o método listen() para escutar todos eventos com apenas um callback:
widget.listen(function (e) {
if (e.type === widget.events.documentSigned) {
// ...
//alert('Documento ' + e.id + ' assinado');
} else if (e.type === widget.events.documentApproved) {
// ...
//alert('Documento ' + e.id + ' aprovado');
}
});
Sempre verifique no backend se o documento foi de fato concluído, dado que os callbacks podem ser acionados por outros arquivos javascript.
Por fim, carregue o iFrame utilizando o método render(), que recebe duas entradas obrigatórias:
embedUrl: a URL para ação que deseja ser realizada. Corresponde ao parâmetro embedUrl retornado pela API Action URLelementId: id do elemento no qual será exibido o componente de assinatura.
E duas entradas opcionais:
page: numero da página na qual o documento será aberto em sua inicialização (para abrir a última página de qualquer documento, não importando o tamanho dele, atribui-se o número'-1').scale: a porcentagem que definirá em qual escala o documento será aberto. Pode ser definido através de um simples string'100'ou através dowidget.scaleOptions.S100
widget.render(embedUrl, 'embed-container', page, scale);
Caso prefira, pode ser fornecido o elemento DOM diretamente:
widget.renderElement(embedUrl, document.getElementById('embed-container'), page, scale);
Exemplo online
Para experimentar, abra Assinatura embutida no site de demonstração, que embute a página de assinatura do Dropsigner com este widget. A versão em Markdown lista todas as chamadas que ele faz.
A página abaixo é o lado do navegador de uma assinatura embutida. O botão pede uma URL de embed ao seu próprio backend, e o seu backend, que mantém a chave de API longe do navegador:
- Envia o PDF (
POST /api/uploads) e cria o documento com o signatário como participante e comdisablePendingActionNotifications: true, para que ninguém receba e-mail (POST /api/documents). - Pede a URL de ação desse participante (
POST /api/documents/{id}/action-url) e devolve oembedUrldela.
Veja Assinatura na sua própria aplicação para as duas chamadas.
O script chama o backend com o $.post do jQuery, então carregue o jQuery na página ou use fetch no lugar.
Na rota POST /api/documents/{id}/action-url, o {id} é o ID do documento, e não o ID da ação do participante (flowActionId). Com o ID da ação na rota, a API responde com o erro DocumentNotFound. Envie o flowActionId no corpo da requisição, e só quando o participante tem mais de uma ação pendente no documento. Os IDs das ações ficam em flowActions[].id, na resposta de GET /api/documents/{id}.
<script src="https://cdn.lacunasoftware.com/libs/signer/lacuna-signer-widget-0.8.0.min.js"></script>
<div style="text-align: center;">
<h1>
Signer embedded signature
</h1>
<button type="button" onclick="startSignature(this)">
Start Signature for Alan Turing (560.723.861-05)
</button>
</div>
<div id="embed-container" class="frame-container">
</div>
.frame-container {
position: relative;
width: 100%;
height: 0;
padding-bottom: 56.25%;
}
.frame-responsive {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
border: none;
}
function sign(embedUrl) {
var widget = new LacunaSignerWidget();
widget.on(widget.events.documentSigned, function (e) {
// ...
alert('Document ' + e.id + ' signed');
});
widget.render(embedUrl, 'embed-container');
}
// Substitua pela sua própria chamada: o seu backend cria o documento e devolve a URL de embed
function startSignature(elem) {
elem.innerHTML = 'Loading ...';
$.post("/seu-backend/assinatura-embutida", {}).
done(function (data) {
if (data) {
sign(data);
elem.style.visibility = "hidden";
} else {
elem.innerHTML = 'Error';
}
}).fail(function () {
elem.innerHTML = 'Error';
});
}
Assine com o certificado de teste da Lacuna de Alan Turing (CPF 560.723.861-05), da página Certificados de teste, numa instância que confie na ICP de testes da Lacuna. Se o Web PKI não estiver instalado, o widget leva o usuário à página de instalação, que o traz de volta à sua aplicação no fim.
Exemplo online de assinatura em nuvem
Para este exemplo é utilizado o certificado de teste do BirdID (CPF 026.102.470-10, veja abaixo as instruções para pareamento).
A página é a mesma do exemplo online, com outro título e outro botão; o backend cria o documento para o usuário de teste do BirdID, que assina com um certificado em nuvem.
<script src="https://cdn.lacunasoftware.com/libs/signer/lacuna-signer-widget-0.8.0.min.js"></script>
<div style="text-align: center;">
<h1>
Signer embedded Cloud signature
</h1>
<button type="button" onclick="startSignature(this)">
Start Signature for Usuario Teste BIRDID (026.102.470-10)
</button>
</div>
<div id="embed-container" class="frame-container">
</div>
function sign(embedUrl) {
var widget = new LacunaSignerWidget();
widget.on(widget.events.documentSigned, function (e) {
// ...
alert('Document ' + e.id + ' signed');
});
widget.render(embedUrl, 'embed-container');
}
// O seu backend cria o documento para o usuário de teste do BirdID e devolve a URL de embed
function startSignature(elem) {
elem.innerHTML = 'Loading ...';
$.post("/seu-backend/assinatura-embutida?nuvem=true", {}).
done(function (data) {
if (data) {
sign(data);
elem.style.visibility = "hidden";
} else {
elem.innerHTML = 'Error';
}
}).fail(function () {
elem.innerHTML = 'Error';
});
}
Para assinar como o usuário de teste do ambiente de homologação do BirdID, leia o QR code abaixo no aplicativo BirdID:
Configurações adicionais
Na instanciação da classe LacunaSignerWidget você pode passar um objeto com uma ou mais das configurações listadas abaixo:
| Atributo | Tipo | Descrição |
|---|---|---|
enableNotifications | boolean | Notificações não são enviadas após a conclusão da assinatura/aprovação embutida. Defina como true para enviá-las. Pode ser definido após a instanciação com método setEnableNotifications. |
disableDocumentPreview | boolean | Se true, esconde a pré-visualização do documento. Nesse caso, será exibido apenas o botão de assinatura e dados do assinante/aprovador. Pode ser definido após a instanciação com método setDisableDocumentPreview. |
enableRefusal | boolean | Se true, exibirá a opção para recusar uma assinatura. Pode ser definido após a instanciação com método setEnableRefusal. |
culture | string | Define o idioma utilizado, as opções disponíveis são "pt"(português), "en"(inglês) e "es"(espanhol) |
theme | string | Define o tema do widget, use o código de 3 caracteres de cada tema (ex: amazon-cornell-red: "acr"), os temas disponíveis estão na página de temas |
Exemplo:
var widget = new LacunaSignerWidget({ disableDocumentPreview: true });
var widget = new LacunaSignerWidget();
widget.setDisableDocumentPreview(true);
Exemplo online de assinatura sem pré-visualização
A mesma página do exemplo online, com disableDocumentPreview: true e o widget num contêiner de no máximo 600 pixels
de largura.
<script src="https://cdn.lacunasoftware.com/libs/signer/lacuna-signer-widget-0.8.0.min.js"></script>
<div style="text-align: center;">
<h1>
Signer embedded signature without Preview
</h1>
<button type="button" onclick="startSignature(this)">
Start Signature for Alan Turing (560.723.861-05)
</button>
</div>
<div class="container">
<div id="embed-container" class="frame-container">
</div>
</div>
.container {
max-width: 600px;
height: 100%;
margin-left: auto;
margin-right: auto;
}
function sign(embedUrl) {
var widget = new LacunaSignerWidget({ disableDocumentPreview: true });
widget.on(widget.events.documentSigned, function (e) {
// ...
alert('Document ' + e.id + ' signed');
});
widget.render(embedUrl, 'embed-container');
}
// Substitua pela sua própria chamada: o seu backend cria o documento e devolve a URL de embed
function startSignature(elem) {
elem.innerHTML = 'Loading ...';
$.post("/seu-backend/assinatura-embutida", {}).
done(function (data) {
if (data) {
sign(data);
elem.style.visibility = "hidden";
} else {
elem.innerHTML = 'Error';
}
}).fail(function () {
elem.innerHTML = 'Error';
});
}
Exemplo para dispositivos móveis
Também é possível utilizar o exemplo de assinaturas embutidas em dispositivos móveis, um app de exemplo está disponível em nosso repositório do GitHub. O exemplo contém uma página da web contendo o widget em JavaScript rodando em seu dispositivo. A aplicação foi desenvolvida com Flutter.
A imagem abaixo mostra o processo de assinatura sem preview de documento dentro do aplicativo:

Posicionamento de marcas de assinatura
À partir da versão 1.70.0 do Signer e 0.7.0 do Widget, é possível embutir a tela de posicionamento de marcas de assinatura em outras aplicações tal como já era feito para a tela de assinatura. Uma vez posicionadas, é possível obter os dados de posicionamento correspondente tanto pela biblioteca quando pela API do Signer para que sejam criados um ou mais documentos com as posições selecionadas.
O primeiro passo é criar uma sessão de posicionamento utilizando a API de criação de sessão. Existem duas variações dessa API:
-
API de criação de sessão básica: permite criar a sessão de posicionamento fornecendo apenas os dados necessários para criação da sessão de posicionamento. Dados pessoais de signatários como e-mail e CPF, por exemplo, são opcionais. Use esta API, caso, após obter o resultado da sessão, você ainda pretenda atualizar os dados da requisição de criação de documentos que será enviada posteriormente ao Signer.
-
API de criação de sessão com requisição de criação de documento: permite criar a sessão de posicionamento fornecendo o mesmo request que é utilizado para criar documentos. Use esta API, caso prefira encaminhar o resultado da sessão diretamente para a API de criação de documentos sem fazer nenhuma alteração adicional.
O resultado de ambas APIs será o retorno de um ID de sessão e uma URL para embutir a tela de posicionamento:
{
//ID da sessão
"id": "4cdcfa93-8f38-46f9-8634-246d5589fe5f",
//URL para usar com o Widget
"embedUrl": "https://www.dropsigner.com/position-marks/4cdcfa93-8f38-46f9-8634-246d5589fe5f?v=1"
}
Uma vez obtida a URL de sessão, basta inicializar o Widget assim como é feito para a funcionalidade de assinatura:
var widget = new LacunaSignerWidget();
Chame o método on() passando o evento de posicionamento de marcas e uma função de callback que será chamada quando o usuário concluir o posicionamento:
//assinatura
widget.on(widget.events.marksPositioned, function (e) {
// O atributo data conterá a requisição preenchida com as posições das marcas
//console.log(e.data);
//alert('Marcas posicionadas');
});
Por fim, carregue o iFrame utilizando o método render():
widget.render(embedUrl, 'embed-container');
Uma vez concluída a sessão de posicionamento, cada entrada do atributo flowActions da requisição fornecida na criação da sessão será atualizada com as posições selecionadas na
tela de posicionamento (mais especificamente, será preenchido o atributo prePositionedMarks).
Essa requisição atualizada pode ser obtida pelo atributo data do evento de posicionamento ou pelo atributo de mesmo nome da
API de obtenção de dados da sessão.
A sessão de posicionamento tem duração de 1 hora após sua criação. Após esse período, não será possível obter nem atualizar os dados da sessão.